1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-13 03:32:22 +00:00

Add complex assigns to FunC and fix UB (#574)

* Fixed complex funC setglob cases

* Forbid modifying local variables after using them in the same tensor

* Fix analyzing "while" in func

* Update funC version (#9)

* Update stress tester

* Fix using variable after move

Co-authored-by: krigga <krigga7@gmail.com>
Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
EmelyanenkoK 2022-12-29 18:06:13 +03:00 committed by GitHub
parent 7347ec0b3b
commit a1d8a5e4f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 19 deletions

View file

@ -810,6 +810,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
break; break;
} }
case _While: { case _While: {
auto values0 = values;
values = block0->fwd_analyze(values); values = block0->fwd_analyze(values);
if (values[left[0]] && values[left[0]]->always_false()) { if (values[left[0]] && values[left[0]]->always_false()) {
// block1 never executed // block1 never executed
@ -817,7 +818,7 @@ VarDescrList Op::fwd_analyze(VarDescrList values) {
break; break;
} }
while (true) { while (true) {
VarDescrList next_values = values | block0->fwd_analyze(block1->fwd_analyze(values)); VarDescrList next_values = values | block0->fwd_analyze(values0 | block1->fwd_analyze(values));
if (same_values(next_values, values)) { if (same_values(next_values, values)) {
break; break;
} }

View file

@ -137,13 +137,20 @@ class CodeRepeat(Code):
self.c.write(f, indent + 1) self.c.write(f, indent + 1)
print(" " * (indent + 1) + "%s += 1;" % var, file=f) print(" " * (indent + 1) + "%s += 1;" % var, file=f)
print(" " * indent + "}", file=f) print(" " * indent + "}", file=f)
else: elif self.loop_type == 2:
var = gen_var_name() var = gen_var_name()
print(" " * indent + "int %s = 0;" % var, file=f) print(" " * indent + "int %s = 0;" % var, file=f)
print(" " * indent + "do {", file=f) print(" " * indent + "do {", file=f)
self.c.write(f, indent + 1) self.c.write(f, indent + 1)
print(" " * (indent + 1) + "%s += 1;" % var, file=f) print(" " * (indent + 1) + "%s += 1;" % var, file=f)
print(" " * indent + "} until (%s >= %d);" % (var, self.n), file=f) print(" " * indent + "} until (%s >= %d);" % (var, self.n), file=f)
else:
var = gen_var_name()
print(" " * indent + "int %s = %d;" % (var, self.n - 1), file=f)
print(" " * indent + "while (%s >= 0) {" % var, file=f)
self.c.write(f, indent + 1)
print(" " * (indent + 1) + "%s -= 1;" % var, file=f)
print(" " * indent + "}", file=f)
class CodeThrow(Code): class CodeThrow(Code):
def __init__(self): def __init__(self):
@ -199,7 +206,7 @@ def gen_code(xl, xr, with_return, loop_depth=0, try_catch_depth=0, can_throw=Fal
for _ in range(random.randint(0, 2)): for _ in range(random.randint(0, 2)):
if random.randint(0, 3) == 0 and loop_depth < 3: if random.randint(0, 3) == 0 and loop_depth < 3:
c = gen_code(xl, xr, False, loop_depth + 1, try_catch_depth, can_throw) c = gen_code(xl, xr, False, loop_depth + 1, try_catch_depth, can_throw)
code.append(CodeRepeat(random.randint(0, 3), c, random.randint(0, 2))) code.append(CodeRepeat(random.randint(0, 3), c, random.randint(0, 3)))
elif xr - xl > 1: elif xr - xl > 1:
xmid = random.randrange(xl + 1, xr) xmid = random.randrange(xl + 1, xr)
ret = random.choice((0, 0, 0, 0, 0, 1, 2)) ret = random.choice((0, 0, 0, 0, 0, 1, 2))

View file

@ -39,7 +39,7 @@ extern std::string generated_from;
constexpr int optimize_depth = 20; constexpr int optimize_depth = 20;
const std::string func_version{"0.3.0"}; const std::string func_version{"0.4.0"};
enum Keyword { enum Keyword {
_Eof = -1, _Eof = -1,
@ -306,10 +306,16 @@ struct TmpVar {
sym_idx_t name; sym_idx_t name;
int coord; int coord;
std::unique_ptr<SrcLocation> where; std::unique_ptr<SrcLocation> where;
size_t modify_forbidden = 0;
TmpVar(var_idx_t _idx, int _cls, TypeExpr* _type = 0, SymDef* sym = 0, const SrcLocation* loc = 0); TmpVar(var_idx_t _idx, int _cls, TypeExpr* _type = 0, SymDef* sym = 0, const SrcLocation* loc = 0);
void show(std::ostream& os, int omit_idx = 0) const; void show(std::ostream& os, int omit_idx = 0) const;
void dump(std::ostream& os) const; void dump(std::ostream& os) const;
void set_location(const SrcLocation& loc); void set_location(const SrcLocation& loc);
std::string to_string() const {
std::ostringstream s;
show(s, 2);
return s.str();
}
}; };
struct VarDescr { struct VarDescr {
@ -722,6 +728,22 @@ struct CodeBlob {
void mark_noreturn(); void mark_noreturn();
void generate_code(AsmOpList& out_list, int mode = 0); void generate_code(AsmOpList& out_list, int mode = 0);
void generate_code(std::ostream& os, int mode = 0, int indent = 0); void generate_code(std::ostream& os, int mode = 0, int indent = 0);
void mark_modify_forbidden(var_idx_t idx) {
++vars.at(idx).modify_forbidden;
}
void unmark_modify_forbidden(var_idx_t idx) {
assert(vars.at(idx).modify_forbidden > 0);
--vars.at(idx).modify_forbidden;
}
void check_modify_forbidden(var_idx_t idx, const SrcLocation& here) const {
if (vars.at(idx).modify_forbidden) {
throw src::ParseError{here, PSTRING() << "Modifying local variable " << vars[idx].to_string()
<< " after using it in the same expression"};
}
}
}; };
/* /*
@ -925,7 +947,7 @@ struct Expr {
} }
int define_new_vars(CodeBlob& code); int define_new_vars(CodeBlob& code);
int predefine_vars(); int predefine_vars();
std::vector<var_idx_t> pre_compile(CodeBlob& code, bool lval = false) const; std::vector<var_idx_t> pre_compile(CodeBlob& code, std::vector<std::pair<SymDef*, var_idx_t>>* lval_globs = nullptr) const;
static std::vector<var_idx_t> pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here); static std::vector<var_idx_t> pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here);
var_idx_t new_tmp(CodeBlob& code) const; var_idx_t new_tmp(CodeBlob& code) const;
std::vector<var_idx_t> new_tmp_vect(CodeBlob& code) const { std::vector<var_idx_t> new_tmp_vect(CodeBlob& code) const {

View file

@ -221,6 +221,13 @@ var_idx_t Expr::new_tmp(CodeBlob& code) const {
return code.create_tmp_var(e_type, &here); return code.create_tmp_var(e_type, &here);
} }
void add_set_globs(CodeBlob& code, std::vector<std::pair<SymDef*, var_idx_t>>& globs, const SrcLocation& here) {
for (const auto& p : globs) {
auto& op = code.emplace_back(here, Op::_SetGlob, std::vector<var_idx_t>{}, std::vector<var_idx_t>{ p.second }, p.first);
op.flags |= Op::_Impure;
}
}
std::vector<var_idx_t> Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here) { std::vector<var_idx_t> Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rhs, const SrcLocation& here) {
while (lhs->is_type_apply()) { while (lhs->is_type_apply()) {
lhs = lhs->args.at(0); lhs = lhs->args.at(0);
@ -245,19 +252,18 @@ std::vector<var_idx_t> Expr::pre_compile_let(CodeBlob& code, Expr* lhs, Expr* rh
return tmp; return tmp;
} }
auto right = rhs->pre_compile(code); auto right = rhs->pre_compile(code);
if (lhs->cls == Expr::_GlobVar) { std::vector<std::pair<SymDef*, var_idx_t>> globs;
assert(lhs->sym); auto left = lhs->pre_compile(code, &globs);
auto& op = code.emplace_back(here, Op::_SetGlob, std::vector<var_idx_t>{}, right, lhs->sym); for (var_idx_t v : left) {
op.flags |= Op::_Impure; code.check_modify_forbidden(v, here);
} else {
auto left = lhs->pre_compile(code, true);
code.emplace_back(here, Op::_Let, std::move(left), right);
} }
code.emplace_back(here, Op::_Let, std::move(left), right);
add_set_globs(code, globs, here);
return right; return right;
} }
std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const { std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, std::vector<std::pair<SymDef*, var_idx_t>>* lval_globs) const {
if (lval && !(cls == _Tensor || cls == _Var || cls == _Hole || cls == _TypeApply)) { if (lval_globs && !(cls == _Tensor || cls == _Var || cls == _Hole || cls == _TypeApply || cls == _GlobVar)) {
std::cerr << "lvalue expression constructor is " << cls << std::endl; std::cerr << "lvalue expression constructor is " << cls << std::endl;
throw src::Fatal{"cannot compile lvalue expression with unknown constructor"}; throw src::Fatal{"cannot compile lvalue expression with unknown constructor"};
} }
@ -265,9 +271,15 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
case _Tensor: { case _Tensor: {
std::vector<var_idx_t> res; std::vector<var_idx_t> res;
for (const auto& x : args) { for (const auto& x : args) {
auto add = x->pre_compile(code, lval); auto add = x->pre_compile(code, lval_globs);
for (var_idx_t v : add) {
code.mark_modify_forbidden(v);
}
res.insert(res.end(), add.cbegin(), add.cend()); res.insert(res.end(), add.cbegin(), add.cend());
} }
for (var_idx_t v : res) {
code.unmark_modify_forbidden(v);
}
return res; return res;
} }
case _Apply: { case _Apply: {
@ -279,6 +291,9 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
std::vector<std::vector<var_idx_t>> add_list(args.size()); std::vector<std::vector<var_idx_t>> add_list(args.size());
for (int i : func->arg_order) { for (int i : func->arg_order) {
add_list[i] = args[i]->pre_compile(code); add_list[i] = args[i]->pre_compile(code);
for (var_idx_t v : add_list[i]) {
code.mark_modify_forbidden(v);
}
} }
for (const auto& add : add_list) { for (const auto& add : add_list) {
res.insert(res.end(), add.cbegin(), add.cend()); res.insert(res.end(), add.cbegin(), add.cend());
@ -286,9 +301,15 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
} else { } else {
for (const auto& x : args) { for (const auto& x : args) {
auto add = x->pre_compile(code); auto add = x->pre_compile(code);
for (var_idx_t v : add) {
code.mark_modify_forbidden(v);
}
res.insert(res.end(), add.cbegin(), add.cend()); res.insert(res.end(), add.cbegin(), add.cend());
} }
} }
for (var_idx_t v : res) {
code.unmark_modify_forbidden(v);
}
auto rvect = new_tmp_vect(code); auto rvect = new_tmp_vect(code);
auto& op = code.emplace_back(here, Op::_Call, rvect, std::move(res), sym); auto& op = code.emplace_back(here, Op::_Call, rvect, std::move(res), sym);
if (flags & _IsImpure) { if (flags & _IsImpure) {
@ -297,7 +318,7 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
return rvect; return rvect;
} }
case _TypeApply: case _TypeApply:
return args[0]->pre_compile(code, lval); return args[0]->pre_compile(code, lval_globs);
case _Var: case _Var:
case _Hole: case _Hole:
return {val}; return {val};
@ -329,8 +350,13 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
case _Glob: case _Glob:
case _GlobVar: { case _GlobVar: {
auto rvect = new_tmp_vect(code); auto rvect = new_tmp_vect(code);
code.emplace_back(here, Op::_GlobVar, rvect, std::vector<var_idx_t>{}, sym); if (lval_globs) {
return rvect; lval_globs->push_back({ sym, rvect[0] });
return rvect;
} else {
code.emplace_back(here, Op::_GlobVar, rvect, std::vector<var_idx_t>{}, sym);
return rvect;
}
} }
case _Letop: { case _Letop: {
return pre_compile_let(code, args.at(0), args.at(1), here); return pre_compile_let(code, args.at(0), args.at(1), here);
@ -338,9 +364,17 @@ std::vector<var_idx_t> Expr::pre_compile(CodeBlob& code, bool lval) const {
case _LetFirst: { case _LetFirst: {
auto rvect = new_tmp_vect(code); auto rvect = new_tmp_vect(code);
auto right = args[1]->pre_compile(code); auto right = args[1]->pre_compile(code);
auto left = args[0]->pre_compile(code, true); std::vector<std::pair<SymDef*, var_idx_t>> local_globs;
if (!lval_globs) {
lval_globs = &local_globs;
}
auto left = args[0]->pre_compile(code, lval_globs);
left.push_back(rvect[0]); left.push_back(rvect[0]);
for (var_idx_t v : left) {
code.check_modify_forbidden(v, here);
}
code.emplace_back(here, Op::_Let, std::move(left), std::move(right)); code.emplace_back(here, Op::_Let, std::move(left), std::move(right));
add_set_globs(code, local_globs, here);
return rvect; return rvect;
} }
case _MkTuple: { case _MkTuple: {