mirror of
https://github.com/ton-blockchain/ton
synced 2025-03-09 15:40:10 +00:00
[FunC] Forbid impure operations inside pure functions
In stdlib, all existing pure functions are asm-implemented. But since we introduced a `pure` keyword applicable to user-defined functions, we need to check that they won't have any side effects (exceptions, globals modification, etc.)
This commit is contained in:
parent
85c60d1263
commit
ef5719d7e6
9 changed files with 181 additions and 51 deletions
18
crypto/func/auto-tests/tests/invalid-pure-1.fc
Normal file
18
crypto/func/auto-tests/tests/invalid-pure-1.fc
Normal file
|
@ -0,0 +1,18 @@
|
|||
int f_impure();
|
||||
|
||||
int f_pure() pure {
|
||||
return f_impure();
|
||||
}
|
||||
|
||||
int main() {
|
||||
return f_pure();
|
||||
}
|
||||
|
||||
{-
|
||||
@compilation_should_fail
|
||||
@stderr
|
||||
"""
|
||||
An impure operation in a pure function
|
||||
return f_impure();
|
||||
"""
|
||||
-}
|
25
crypto/func/auto-tests/tests/invalid-pure-2.fc
Normal file
25
crypto/func/auto-tests/tests/invalid-pure-2.fc
Normal file
|
@ -0,0 +1,25 @@
|
|||
builder begin_cell() pure asm "NEWC";
|
||||
|
||||
global int g;
|
||||
|
||||
(builder) f_pure() pure {
|
||||
var g; // strange, but this doesn't make a variable local, it still refers to a global one
|
||||
builder b = begin_cell();
|
||||
g = g + 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
int main() {
|
||||
g = 0;
|
||||
f_pure();
|
||||
return g;
|
||||
}
|
||||
|
||||
{-
|
||||
@compilation_should_fail
|
||||
@stderr
|
||||
"""
|
||||
An impure operation in a pure function
|
||||
g = g + 1;
|
||||
"""
|
||||
-}
|
23
crypto/func/auto-tests/tests/invalid-pure-3.fc
Normal file
23
crypto/func/auto-tests/tests/invalid-pure-3.fc
Normal file
|
@ -0,0 +1,23 @@
|
|||
(int, int, int, int) compute_data_size?(cell c, int max_cells) pure asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
|
||||
builder begin_cell() pure asm "NEWC";
|
||||
cell end_cell(builder b) pure asm "ENDC";
|
||||
|
||||
(int, int) validate_input(cell input) pure {
|
||||
var (x, y, z, correct) = compute_data_size?(input, 10);
|
||||
throw_unless(102, correct);
|
||||
}
|
||||
|
||||
int main() pure {
|
||||
cell c = begin_cell().end_cell();
|
||||
validate_input(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
{-
|
||||
@compilation_should_fail
|
||||
@stderr
|
||||
"""
|
||||
An impure operation in a pure function
|
||||
throw_unless
|
||||
"""
|
||||
-}
|
47
crypto/func/auto-tests/tests/pure-functions.fc
Normal file
47
crypto/func/auto-tests/tests/pure-functions.fc
Normal file
|
@ -0,0 +1,47 @@
|
|||
cell get_data() pure asm "c4 PUSH";
|
||||
slice begin_parse(cell c) pure asm "CTOS";
|
||||
builder begin_cell() pure asm "NEWC";
|
||||
cell end_cell(builder b) pure asm "ENDC";
|
||||
() set_data(cell c) asm "c4 POP";
|
||||
|
||||
int f_pure2() pure;
|
||||
|
||||
int f_pure1() pure {
|
||||
return f_pure2();
|
||||
}
|
||||
|
||||
int f_pure2() pure {
|
||||
return 2;
|
||||
}
|
||||
|
||||
(int, int) get_contract_data() pure {
|
||||
cell c = get_data();
|
||||
slice cs = c.begin_parse();
|
||||
cs~load_bits(32);
|
||||
int value = cs~load_uint(16);
|
||||
return (1, value);
|
||||
}
|
||||
|
||||
() save_contract_data(int value) {
|
||||
builder b = begin_cell().store_int(1, 32).store_uint(value, 16);
|
||||
set_data(b.end_cell());
|
||||
}
|
||||
|
||||
int test1() pure method_id(101) {
|
||||
return f_pure1();
|
||||
}
|
||||
|
||||
int test2(int value) method_id(102) {
|
||||
save_contract_data(value);
|
||||
(_, var restored) = get_contract_data();
|
||||
return restored;
|
||||
}
|
||||
|
||||
() main() { return (); }
|
||||
|
||||
{-
|
||||
|
||||
TESTCASE | 101 | | 2
|
||||
TESTCASE | 102 | 44 | 44
|
||||
|
||||
-}
|
Loading…
Add table
Add a link
Reference in a new issue