Skip to content

Commit b3275eb

Browse files
authored
Add additional test for --check-stack-overflow (WebAssembly#2857)
This test verifies that functions in the llvm input source that do stack pointer manipulation get correctly handled by `wasm-emscripten-finalize --check-stack-overflow` (StackLimitEnforcer)
1 parent c451ca3 commit b3275eb

5 files changed

Lines changed: 230 additions & 32 deletions

File tree

scripts/test/generate_lld_tests.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def generate_wat_files(llvm_bin, emscripten_root):
3434
print('\n[ building wat files from C sources... ]\n')
3535

3636
lld_path = os.path.join(shared.options.binaryen_test, 'lld')
37-
for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp']):
37+
for src_file, ext in files_with_extensions(lld_path, ['.c', '.cpp', '.s']):
3838
print('..', src_file)
3939
obj_file = src_file.replace(ext, '.o')
4040

@@ -69,6 +69,7 @@ def generate_wat_files(llvm_bin, emscripten_root):
6969
'--export', '__wasm_call_ctors',
7070
'--export', '__data_end',
7171
'--global-base=568',
72+
'--no-gc-sections',
7273
]
7374
# We had a regression where this test only worked if debug names
7475
# were included.

scripts/test/lld.py

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -30,41 +30,43 @@ def args_for_finalize(filename):
3030
return ret
3131

3232

33+
def run_test(input_path):
34+
print('..', input_path)
35+
is_passive = '.passive.' in input_path
36+
mem_file = input_path + '.mem'
37+
extension_arg_map = {
38+
'.out': [],
39+
}
40+
if not is_passive:
41+
extension_arg_map.update({
42+
'.mem.out': ['--separate-data-segments', mem_file],
43+
})
44+
for ext, args in extension_arg_map.items():
45+
expected_file = input_path + ext
46+
if ext != '.out' and not os.path.exists(expected_file):
47+
continue
48+
49+
cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [input_path, '-S'] + args
50+
cmd += args_for_finalize(os.path.basename(input_path))
51+
actual = support.run_command(cmd)
52+
53+
if not os.path.exists(expected_file):
54+
print(actual)
55+
shared.fail_with_error('output ' + expected_file +
56+
' does not exist')
57+
shared.fail_if_not_identical_to_file(actual, expected_file)
58+
if ext == '.mem.out':
59+
with open(mem_file) as mf:
60+
mem = mf.read()
61+
shared.fail_if_not_identical_to_file(mem, input_path + '.mem.mem')
62+
os.remove(mem_file)
63+
64+
3365
def test_wasm_emscripten_finalize():
3466
print('\n[ checking wasm-emscripten-finalize testcases... ]\n')
3567

3668
for input_path in shared.get_tests(shared.get_test_dir('lld'), ['.wat', '.wasm']):
37-
print('..', input_path)
38-
is_passive = '.passive.' in input_path
39-
mem_file = input_path + '.mem'
40-
extension_arg_map = {
41-
'.out': [],
42-
}
43-
if not is_passive:
44-
extension_arg_map.update({
45-
'.mem.out': ['--separate-data-segments', mem_file],
46-
})
47-
for ext, ext_args in extension_arg_map.items():
48-
expected_file = input_path + ext
49-
if ext != '.out' and not os.path.exists(expected_file):
50-
continue
51-
52-
cmd = shared.WASM_EMSCRIPTEN_FINALIZE + [input_path, '-S'] + \
53-
ext_args
54-
cmd += args_for_finalize(os.path.basename(input_path))
55-
actual = support.run_command(cmd)
56-
57-
if not os.path.exists(expected_file):
58-
print(actual)
59-
shared.fail_with_error('output ' + expected_file +
60-
' does not exist')
61-
shared.fail_if_not_identical_to_file(actual, expected_file)
62-
if ext == '.mem.out':
63-
with open(mem_file) as mf:
64-
mem = mf.read()
65-
shared.fail_if_not_identical_to_file(mem, input_path +
66-
'.mem.mem')
67-
os.remove(mem_file)
69+
run_test(input_path)
6870

6971

7072
def update_lld_tests():

test/lld/basic_safe_stack.s

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Test that wasm-binaryen-finalize --check-stack-overflow correctly
2+
# inserts stack chekc handlers.
3+
4+
.globl stackRestore
5+
.globl stackAlloc
6+
7+
.globaltype __stack_pointer, i32
8+
9+
stackRestore:
10+
.functype stackRestore(i32) -> ()
11+
local.get 0
12+
global.set __stack_pointer
13+
end_function
14+
15+
stackAlloc:
16+
.functype stackAlloc(i32) -> (i32)
17+
.local i32, i32
18+
global.get __stack_pointer
19+
# Get arg 0 -> number of bytes to allocate
20+
local.get 0
21+
# Stack grows down. Subtract arg0 from __stack_pointer
22+
i32.sub
23+
# Align result by anding with ~15
24+
i32.const 0xfffffff0
25+
i32.and
26+
local.tee 1
27+
global.set __stack_pointer
28+
local.get 1
29+
end_function
30+
31+
.globl main
32+
main:
33+
.functype main () -> ()
34+
end_function
35+
36+
.export_name stackAlloc, stackAlloc
37+
.export_name stackSave, stackSave
38+
.export_name stackRestore, stackRestore

test/lld/basic_safe_stack.wat

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
(module
2+
(type $none_=>_none (func))
3+
(type $i32_=>_none (func (param i32)))
4+
(type $i32_=>_i32 (func (param i32) (result i32)))
5+
(memory $0 2)
6+
(table $0 1 1 funcref)
7+
(global $global$0 (mut i32) (i32.const 66112))
8+
(global $global$1 i32 (i32.const 568))
9+
(export "memory" (memory $0))
10+
(export "__wasm_call_ctors" (func $__wasm_call_ctors))
11+
(export "stackRestore" (func $stackRestore))
12+
(export "stackAlloc" (func $stackAlloc))
13+
(export "main" (func $main))
14+
(export "__data_end" (global $global$1))
15+
(func $__wasm_call_ctors
16+
)
17+
(func $stackRestore (param $0 i32)
18+
(global.set $global$0
19+
(local.get $0)
20+
)
21+
)
22+
(func $stackAlloc (param $0 i32) (result i32)
23+
(local $1 i32)
24+
(local $2 i32)
25+
(global.set $global$0
26+
(local.tee $1
27+
(i32.and
28+
(i32.sub
29+
(global.get $global$0)
30+
(local.get $0)
31+
)
32+
(i32.const -16)
33+
)
34+
)
35+
)
36+
(local.get $1)
37+
)
38+
(func $main
39+
)
40+
)
41+

test/lld/basic_safe_stack.wat.out

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
(module
2+
(type $none_=>_none (func))
3+
(type $i32_=>_none (func (param i32)))
4+
(type $i32_=>_i32 (func (param i32) (result i32)))
5+
(type $none_=>_i32 (func (result i32)))
6+
(import "env" "__handle_stack_overflow" (func $__handle_stack_overflow))
7+
(memory $0 2)
8+
(table $0 1 1 funcref)
9+
(global $global$0 (mut i32) (i32.const 66112))
10+
(global $global$1 i32 (i32.const 568))
11+
(global $__stack_limit (mut i32) (i32.const 0))
12+
(export "memory" (memory $0))
13+
(export "__wasm_call_ctors" (func $__wasm_call_ctors))
14+
(export "stackRestore" (func $stackRestore))
15+
(export "stackAlloc" (func $stackAlloc))
16+
(export "main" (func $main))
17+
(export "__data_end" (global $global$1))
18+
(export "__set_stack_limit" (func $__set_stack_limit))
19+
(export "stackSave" (func $stackSave))
20+
(export "__growWasmMemory" (func $__growWasmMemory))
21+
(func $__wasm_call_ctors
22+
(nop)
23+
)
24+
(func $stackRestore (param $0 i32)
25+
(local $1 i32)
26+
(if
27+
(i32.lt_u
28+
(local.tee $1
29+
(local.get $0)
30+
)
31+
(global.get $__stack_limit)
32+
)
33+
(call $__handle_stack_overflow)
34+
)
35+
(global.set $global$0
36+
(local.get $1)
37+
)
38+
)
39+
(func $stackAlloc (param $0 i32) (result i32)
40+
(local $1 i32)
41+
(local $2 i32)
42+
(local $3 i32)
43+
(block
44+
(if
45+
(i32.lt_u
46+
(local.tee $3
47+
(local.tee $1
48+
(i32.and
49+
(i32.sub
50+
(global.get $global$0)
51+
(local.get $0)
52+
)
53+
(i32.const -16)
54+
)
55+
)
56+
)
57+
(global.get $__stack_limit)
58+
)
59+
(call $__handle_stack_overflow)
60+
)
61+
(global.set $global$0
62+
(local.get $3)
63+
)
64+
)
65+
(local.get $1)
66+
)
67+
(func $main
68+
(nop)
69+
)
70+
(func $__set_stack_limit (param $0 i32)
71+
(global.set $__stack_limit
72+
(local.get $0)
73+
)
74+
)
75+
(func $stackSave (result i32)
76+
(global.get $global$0)
77+
)
78+
(func $__growWasmMemory (param $newSize i32) (result i32)
79+
(memory.grow
80+
(local.get $newSize)
81+
)
82+
)
83+
)
84+
(;
85+
--BEGIN METADATA --
86+
{
87+
"staticBump": 0,
88+
"tableSize": 1,
89+
"initializers": [
90+
"__wasm_call_ctors"
91+
],
92+
"declares": [
93+
"__handle_stack_overflow"
94+
],
95+
"externs": [
96+
],
97+
"exports": [
98+
"__wasm_call_ctors",
99+
"stackRestore",
100+
"stackAlloc",
101+
"main",
102+
"__set_stack_limit",
103+
"stackSave",
104+
"__growWasmMemory"
105+
],
106+
"namedGlobals": {
107+
"__data_end" : "568"
108+
},
109+
"invokeFuncs": [
110+
],
111+
"features": [
112+
],
113+
"mainReadsParams": 1
114+
}
115+
-- END METADATA --
116+
;)

0 commit comments

Comments
 (0)