mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
Fix FunC UB (#656)
* Fix UB in func * Improve optimizing int consts and unused variables in FunC * Bump funC version to 0.4.3 * Fix analyzing repeat loop --------- Co-authored-by: SpyCheese <mikle98@yandex.ru>
This commit is contained in:
parent
f51eb2d747
commit
8eb167b76a
8 changed files with 31 additions and 8 deletions
|
@ -179,7 +179,7 @@ void VarDescr::set_const_nan() {
|
|||
|
||||
void VarDescr::operator|=(const VarDescr& y) {
|
||||
val &= y.val;
|
||||
if (is_int_const() && cmp(int_const, y.int_const) != 0) {
|
||||
if (is_int_const() && y.is_int_const() && cmp(int_const, y.int_const) != 0) {
|
||||
val &= ~_Const;
|
||||
}
|
||||
if (!(val & _Const)) {
|
||||
|
|
|
@ -388,7 +388,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
|
|||
for (; l_it < left.cend(); ++l_it, ++r_it) {
|
||||
if (std::find(l_it + 1, left.cend(), *l_it) == left.cend()) {
|
||||
auto p = next_var_info[*l_it];
|
||||
new_var_info.add_var(*r_it, !p || p->is_unused());
|
||||
new_var_info.add_var(*r_it, edit && (!p || p->is_unused()));
|
||||
new_left.push_back(*l_it);
|
||||
new_right.push_back(*r_it);
|
||||
}
|
||||
|
@ -500,7 +500,12 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
|
|||
}
|
||||
changes = (new_var_info.size() == n);
|
||||
} while (changes <= edit);
|
||||
assert(left.size() == 1);
|
||||
bool last = new_var_info.count_used(left) == 0;
|
||||
new_var_info += left;
|
||||
if (last) {
|
||||
new_var_info[left[0]]->flags |= VarDescr::_Last;
|
||||
}
|
||||
return set_var_info(std::move(new_var_info));
|
||||
}
|
||||
case _Again: {
|
||||
|
|
|
@ -29,8 +29,12 @@ using namespace std::literals::string_literals;
|
|||
|
||||
int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt;
|
||||
std::vector<SymDef*> glob_func, glob_vars;
|
||||
std::set<std::string> prohibited_var_names;
|
||||
|
||||
SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) {
|
||||
if (name.back() == '_') {
|
||||
prohibited_var_names.insert(name);
|
||||
}
|
||||
sym_idx_t name_idx = sym::symbols.lookup(name, 1);
|
||||
if (sym::symbols.is_keyword(name_idx)) {
|
||||
std::cerr << "fatal: global function `" << name << "` already defined as a keyword" << std::endl;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#pragma once
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <algorithm>
|
||||
|
@ -40,7 +41,7 @@ extern std::string generated_from;
|
|||
|
||||
constexpr int optimize_depth = 20;
|
||||
|
||||
const std::string func_version{"0.4.2"};
|
||||
const std::string func_version{"0.4.3"};
|
||||
|
||||
enum Keyword {
|
||||
_Eof = -1,
|
||||
|
@ -839,6 +840,7 @@ struct SymValConst : sym::SymValBase {
|
|||
|
||||
extern int glob_func_cnt, undef_func_cnt, glob_var_cnt;
|
||||
extern std::vector<SymDef*> glob_func, glob_vars;
|
||||
extern std::set<std::string> prohibited_var_names;
|
||||
|
||||
/*
|
||||
*
|
||||
|
|
|
@ -205,6 +205,10 @@ int Expr::predefine_vars() {
|
|||
case _Var:
|
||||
if (!sym) {
|
||||
assert(val < 0 && here.defined());
|
||||
if (prohibited_var_names.count(sym::symbols.get_name(~val))) {
|
||||
throw src::ParseError{
|
||||
here, PSTRING() << "symbol `" << sym::symbols.get_name(~val) << "` cannot be redefined as a variable"};
|
||||
}
|
||||
sym = sym::define_symbol(~val, false, here);
|
||||
// std::cerr << "predefining variable " << sym::symbols.get_name(~val) << std::endl;
|
||||
if (!sym) {
|
||||
|
|
|
@ -172,6 +172,10 @@ FormalArg parse_formal_arg(Lexer& lex, int fa_idx) {
|
|||
lex.expect(_Ident, "formal parameter name");
|
||||
}
|
||||
loc = lex.cur().loc;
|
||||
if (prohibited_var_names.count(sym::symbols.get_name(lex.cur().val))) {
|
||||
throw src::ParseError{
|
||||
loc, PSTRING() << "symbol `" << sym::symbols.get_name(lex.cur().val) << "` cannot be redefined as a variable"};
|
||||
}
|
||||
SymDef* new_sym_def = sym::define_symbol(lex.cur().val, true, loc);
|
||||
if (!new_sym_def) {
|
||||
lex.cur().error_at("cannot define symbol `", "`");
|
||||
|
@ -397,7 +401,7 @@ bool check_global_func(const Lexem& cur, sym_idx_t func_name = 0) {
|
|||
def = sym::define_global_symbol(func_name, 0, cur.loc);
|
||||
assert(def && "cannot define global function");
|
||||
++undef_func_cnt;
|
||||
make_new_glob_func(def, TypeExpr::new_hole()); // was: ... ::new_func()
|
||||
make_new_glob_func(def, TypeExpr::new_func()); // was: ... ::new_func()
|
||||
return true;
|
||||
}
|
||||
SymVal* val = dynamic_cast<SymVal*>(def->value);
|
||||
|
@ -1369,6 +1373,10 @@ std::vector<TypeExpr*> parse_type_var_list(Lexer& lex) {
|
|||
throw src::ParseError{lex.cur().loc, "free type identifier expected"};
|
||||
}
|
||||
auto loc = lex.cur().loc;
|
||||
if (prohibited_var_names.count(sym::symbols.get_name(lex.cur().val))) {
|
||||
throw src::ParseError{loc, PSTRING() << "symbol `" << sym::symbols.get_name(lex.cur().val)
|
||||
<< "` cannot be redefined as a variable"};
|
||||
}
|
||||
SymDef* new_sym_def = sym::define_symbol(lex.cur().val, true, loc);
|
||||
if (!new_sym_def || new_sym_def->value) {
|
||||
lex.cur().error_at("redefined type variable `", "`");
|
||||
|
|
|
@ -32,8 +32,8 @@ int scope_level;
|
|||
|
||||
SymTable<100003> symbols;
|
||||
|
||||
SymDef* sym_def[symbols.hprime];
|
||||
SymDef* global_sym_def[symbols.hprime];
|
||||
SymDef* sym_def[symbols.hprime + 1];
|
||||
SymDef* global_sym_def[symbols.hprime + 1];
|
||||
std::vector<std::pair<int, SymDef>> symbol_stack;
|
||||
std::vector<src::SrcLocation> scope_opened_at;
|
||||
|
||||
|
|
|
@ -161,8 +161,8 @@ struct SymDef {
|
|||
}
|
||||
};
|
||||
|
||||
extern SymDef* sym_def[symbols.hprime];
|
||||
extern SymDef* global_sym_def[symbols.hprime];
|
||||
extern SymDef* sym_def[symbols.hprime + 1];
|
||||
extern SymDef* global_sym_def[symbols.hprime + 1];
|
||||
extern std::vector<std::pair<int, SymDef>> symbol_stack;
|
||||
extern std::vector<src::SrcLocation> scope_opened_at;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue