Skip to content

Commit 6e9ce41

Browse files
committed
[Tolk] Fix overflow detection on constant storeUint
1 parent 36fe5fd commit 6e9ce41

File tree

3 files changed

+89
-5
lines changed

3 files changed

+89
-5
lines changed

tolk-tester/tests/cells-slices.tolk

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ fun endCell(b: builder): cell
1616
fun beginParse(c: cell): slice
1717
asm "CTOS";
1818

19+
@noinline
20+
fun triggerOverflowIntConst() {
21+
return beginCell().storeInt(10, 4)
22+
}
23+
24+
@noinline
25+
fun triggerOverflowUintConst() {
26+
return beginCell().storeUint(123, 6)
27+
}
28+
1929
@method_id(101)
2030
fun test1(): [int,int,int,int,int] {
2131
var b: builder = beginCell().storeUint(1, 32);
@@ -435,6 +445,30 @@ fun test34(p: int, n: int) {
435445
return b;
436446
}
437447

448+
@method_id(135)
449+
fun test35(overflowMode: int) {
450+
try {
451+
val b: builder = match (overflowMode) {
452+
1 => triggerOverflowIntConst(),
453+
2 => triggerOverflowUintConst(),
454+
3 => beginCell().storeUint(10, -4),
455+
4 => beginCell().storeInt(100, 1),
456+
5 => beginCell().storeInt(1, 0),
457+
6 => beginCell().storeInt(115792089237316195423570985008687907853269984665640564039457584007913129639935, 256),
458+
7 => beginCell().storeInt(15, 4),
459+
8 => beginCell().storeUint(1<<170, 169),
460+
else => beginCell(),
461+
};
462+
return b.endCell().beginParse().loadUint(1) * 1000
463+
}
464+
catch (ex) { return ex }
465+
}
466+
467+
@method_id(136)
468+
fun test36() {
469+
return beginCell().storeInt(0, 0)
470+
}
471+
438472
fun main(): int {
439473
return 0;
440474
}
@@ -469,6 +503,15 @@ fun main(): int {
469503
@testcase | 132 | 0 | BC{00080000000a}
470504
@testcase | 133 | 0 | BC{00020a}
471505
@testcase | 134 | 0 8 | BC{00020a}
506+
@testcase | 135 | 1 | 5
507+
@testcase | 135 | 2 | 5
508+
@testcase | 135 | 3 | 5
509+
@testcase | 135 | 4 | 5
510+
@testcase | 135 | 5 | 5
511+
@testcase | 135 | 6 | 5
512+
@testcase | 135 | 7 | 5
513+
@testcase | 135 | 8 | 5
514+
@testcase | 136 | | BC{0000}
472515

473516
We test that consequtive storeInt/storeUint with constants are joined into a single number
474517

@@ -630,4 +673,32 @@ We test that consequtive storeInt/storeUint with constants are joined into a sin
630673
}>
631674
"""
632675

676+
@fif_codegen
677+
"""
678+
triggerOverflowIntConst() PROC:<{
679+
10 PUSHINT
680+
NEWC
681+
4 STI
682+
}>
683+
"""
684+
685+
@fif_codegen
686+
"""
687+
triggerOverflowUintConst() PROC:<{
688+
123 PUSHINT
689+
NEWC
690+
6 STU
691+
}>
692+
"""
693+
694+
@fif_codegen
695+
"""
696+
test36() PROC:<{
697+
0 PUSHINT
698+
NEWC
699+
OVER
700+
STIX
701+
}>
702+
"""
703+
633704
*/

tolk-tester/tests/pack-unpack-1.tolk

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ struct Point {
77
y: int32;
88
}
99

10+
struct TwoU {
11+
a: uint8
12+
b: uint8
13+
}
14+
1015
@method_id(101)
1116
fun test1(value: int) {
1217
var t: JustInt32 = { value };
@@ -84,6 +89,15 @@ fun test7(s: slice) {
8489
return (6, s.remainingBitsCount());
8590
}
8691

92+
@method_id(108)
93+
fun test8(): cell | int {
94+
try {
95+
return TwoU{a:1<<10, b:0}.toCell()
96+
} catch (ex) {
97+
return ex
98+
}
99+
}
100+
87101
fun main(c: cell) {
88102
c as Cell<Point>;
89103
(c as Cell<Point>) as cell;
@@ -103,6 +117,7 @@ fun main(c: cell) {
103117
@testcase | 107 | x{09332} | 4 12
104118
@testcase | 107 | x{2} | 5 1
105119
@testcase | 107 | x{0234} | 6 16
120+
@testcase | 108 | | 5 1
106121

107122
@fif_codegen
108123
"""

tolk/builtins.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,12 +1093,10 @@ static AsmOp compile_store_int(std::vector<VarDescr>& res, std::vector<VarDescr>
10931093
// purpose: to merge consecutive `b.storeUint(0, 1).storeUint(1, 1)` into one "1 PUSHINT + 2 STU",
10941094
// when constant arguments are passed, keep them as a separate (fake) instruction, to be handled by optimizer later
10951095
bool value_and_len_is_const = z.is_int_const() && x.is_int_const();
1096-
if (value_and_len_is_const && G.settings.optimization_level >= 2) {
1096+
if (value_and_len_is_const && x.int_const >= 0 && z.int_const > 0 && z.int_const <= 256 && G.settings.optimization_level >= 2) {
10971097
// don't handle negative numbers or potential overflow, merging them is incorrect
1098-
bool value_is_safe = sgnd
1099-
? x.int_const >= 0 && z.int_const < 64 && x.int_const < (1ULL << (z.int_const->to_long() - 1))
1100-
: x.int_const >= 0;
1101-
if (value_is_safe && z.int_const > 0 && z.int_const <= (255 + !sgnd)) {
1098+
int len = static_cast<int>(z.int_const->to_long());
1099+
if (x.int_const->fits_bits(len, sgnd)) {
11021100
z.unused();
11031101
x.unused();
11041102
return AsmOp::Custom(loc, "MY_store_int"s + (sgnd ? "I " : "U ") + x.int_const->to_dec_string() + " " + z.int_const->to_dec_string(), 1);

0 commit comments

Comments
 (0)