1
0
Fork 0
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:
EmelyanenkoK 2023-04-03 10:13:39 +03:00 committed by GitHub
parent f51eb2d747
commit 8eb167b76a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 31 additions and 8 deletions

View file

@ -179,7 +179,7 @@ void VarDescr::set_const_nan() {
void VarDescr::operator|=(const VarDescr& y) { void VarDescr::operator|=(const VarDescr& y) {
val &= y.val; 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; val &= ~_Const;
} }
if (!(val & _Const)) { if (!(val & _Const)) {

View file

@ -388,7 +388,7 @@ bool Op::compute_used_vars(const CodeBlob& code, bool edit) {
for (; l_it < left.cend(); ++l_it, ++r_it) { for (; l_it < left.cend(); ++l_it, ++r_it) {
if (std::find(l_it + 1, left.cend(), *l_it) == left.cend()) { if (std::find(l_it + 1, left.cend(), *l_it) == left.cend()) {
auto p = next_var_info[*l_it]; 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_left.push_back(*l_it);
new_right.push_back(*r_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); changes = (new_var_info.size() == n);
} while (changes <= edit); } while (changes <= edit);
assert(left.size() == 1);
bool last = new_var_info.count_used(left) == 0;
new_var_info += left; new_var_info += left;
if (last) {
new_var_info[left[0]]->flags |= VarDescr::_Last;
}
return set_var_info(std::move(new_var_info)); return set_var_info(std::move(new_var_info));
} }
case _Again: { case _Again: {

View file

@ -29,8 +29,12 @@ using namespace std::literals::string_literals;
int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt; int glob_func_cnt, undef_func_cnt, glob_var_cnt, const_cnt;
std::vector<SymDef*> glob_func, glob_vars; std::vector<SymDef*> glob_func, glob_vars;
std::set<std::string> prohibited_var_names;
SymDef* predefine_builtin_func(std::string name, TypeExpr* func_type) { 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); sym_idx_t name_idx = sym::symbols.lookup(name, 1);
if (sym::symbols.is_keyword(name_idx)) { if (sym::symbols.is_keyword(name_idx)) {
std::cerr << "fatal: global function `" << name << "` already defined as a keyword" << std::endl; std::cerr << "fatal: global function `" << name << "` already defined as a keyword" << std::endl;

View file

@ -19,6 +19,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <string> #include <string>
#include <set>
#include <stack> #include <stack>
#include <utility> #include <utility>
#include <algorithm> #include <algorithm>
@ -40,7 +41,7 @@ extern std::string generated_from;
constexpr int optimize_depth = 20; constexpr int optimize_depth = 20;
const std::string func_version{"0.4.2"}; const std::string func_version{"0.4.3"};
enum Keyword { enum Keyword {
_Eof = -1, _Eof = -1,
@ -839,6 +840,7 @@ struct SymValConst : sym::SymValBase {
extern int glob_func_cnt, undef_func_cnt, glob_var_cnt; extern int glob_func_cnt, undef_func_cnt, glob_var_cnt;
extern std::vector<SymDef*> glob_func, glob_vars; extern std::vector<SymDef*> glob_func, glob_vars;
extern std::set<std::string> prohibited_var_names;
/* /*
* *

View file

@ -205,6 +205,10 @@ int Expr::predefine_vars() {
case _Var: case _Var:
if (!sym) { if (!sym) {
assert(val < 0 && here.defined()); 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); sym = sym::define_symbol(~val, false, here);
// std::cerr << "predefining variable " << sym::symbols.get_name(~val) << std::endl; // std::cerr << "predefining variable " << sym::symbols.get_name(~val) << std::endl;
if (!sym) { if (!sym) {

View file

@ -172,6 +172,10 @@ FormalArg parse_formal_arg(Lexer& lex, int fa_idx) {
lex.expect(_Ident, "formal parameter name"); lex.expect(_Ident, "formal parameter name");
} }
loc = lex.cur().loc; 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); SymDef* new_sym_def = sym::define_symbol(lex.cur().val, true, loc);
if (!new_sym_def) { if (!new_sym_def) {
lex.cur().error_at("cannot define symbol `", "`"); 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); def = sym::define_global_symbol(func_name, 0, cur.loc);
assert(def && "cannot define global function"); assert(def && "cannot define global function");
++undef_func_cnt; ++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; return true;
} }
SymVal* val = dynamic_cast<SymVal*>(def->value); 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"}; throw src::ParseError{lex.cur().loc, "free type identifier expected"};
} }
auto loc = lex.cur().loc; 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); SymDef* new_sym_def = sym::define_symbol(lex.cur().val, true, loc);
if (!new_sym_def || new_sym_def->value) { if (!new_sym_def || new_sym_def->value) {
lex.cur().error_at("redefined type variable `", "`"); lex.cur().error_at("redefined type variable `", "`");

View file

@ -32,8 +32,8 @@ int scope_level;
SymTable<100003> symbols; SymTable<100003> symbols;
SymDef* sym_def[symbols.hprime]; SymDef* sym_def[symbols.hprime + 1];
SymDef* global_sym_def[symbols.hprime]; SymDef* global_sym_def[symbols.hprime + 1];
std::vector<std::pair<int, SymDef>> symbol_stack; std::vector<std::pair<int, SymDef>> symbol_stack;
std::vector<src::SrcLocation> scope_opened_at; std::vector<src::SrcLocation> scope_opened_at;

View file

@ -161,8 +161,8 @@ struct SymDef {
} }
}; };
extern SymDef* sym_def[symbols.hprime]; extern SymDef* sym_def[symbols.hprime + 1];
extern SymDef* global_sym_def[symbols.hprime]; extern SymDef* global_sym_def[symbols.hprime + 1];
extern std::vector<std::pair<int, SymDef>> symbol_stack; extern std::vector<std::pair<int, SymDef>> symbol_stack;
extern std::vector<src::SrcLocation> scope_opened_at; extern std::vector<src::SrcLocation> scope_opened_at;