Skip to content

Commit bb31177

Browse files
committed
Fix lsan test suite
1 parent 982138e commit bb31177

File tree

9 files changed

+76
-40
lines changed

9 files changed

+76
-40
lines changed

emcc.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2134,12 +2134,18 @@ def check_memory_setting(setting):
21342134
else:
21352135
settings.UBSAN_RUNTIME = 2
21362136

2137-
if 'leak' in sanitize:
2138-
settings.USE_LSAN = 1
2139-
default_setting('EXIT_RUNTIME', 1)
2140-
2141-
if settings.LINKABLE:
2142-
exit_with_error('LSan does not support dynamic linking')
2137+
sanitizer_mem = 0
2138+
if sanitize:
2139+
# sanitizers do at least 9 page allocs of a single page during startup.
2140+
sanitizer_mem += webassembly.WASM_PAGE_SIZE * 9
2141+
sanitizer_mem += 2097152 * 10
2142+
# we also allocate at least 11 "regions". Each region is kRegionSize (2 << 20) but
2143+
# MmapAlignedOrDieOnFatalError adds another 2 << 20 for alignment.
2144+
sanitizer_mem += (1 << 21) * 11
2145+
# When running in the threaded mode asan needs to allocate an array of kMaxNumberOfThreads
2146+
# (1 << 22) pointers. See compiler-rt/lib/asan/asan_thread.cpp.
2147+
if settings.USE_PTHREADS:
2148+
sanitizer_mem += (1 << 22) * 4
21432149

21442150
if 'address' in sanitize:
21452151
settings.USE_ASAN = 1
@@ -2213,6 +2219,18 @@ def check_memory_setting(setting):
22132219

22142220
if settings.LINKABLE:
22152221
exit_with_error('ASan does not support dynamic linking')
2222+
elif 'leak' in sanitize:
2223+
settings.USE_LSAN = 1
2224+
default_setting('EXIT_RUNTIME', 1)
2225+
2226+
if settings.LINKABLE:
2227+
exit_with_error('LSan does not support dynamic linking')
2228+
2229+
if sanitizer_mem:
2230+
# Increase the size of the initial memory according to how much memory
2231+
# we think the sanitizers will use.
2232+
logger.debug(f'adding {sanitizer_mem} bytes of memory for sanitizer support')
2233+
settings.INITIAL_MEMORY += sanitizer_mem
22162234

22172235
if sanitize and settings.GENERATE_SOURCE_MAP:
22182236
settings.LOAD_SOURCE_MAP = 1

system/lib/compiler-rt/lib/lsan/lsan_interceptors.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(),
394394
#endif
395395

396396
#if SANITIZER_EMSCRIPTEN
397+
#define __ATTRP_C11_THREAD ((void*)(uptr)-1)
397398
extern "C" {
398399
int emscripten_builtin_pthread_create(void *thread, void *attr,
399400
void *(*callback)(void *), void *arg);
@@ -452,7 +453,7 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
452453
ENSURE_LSAN_INITED;
453454
EnsureMainThreadIDIsCorrect();
454455
__sanitizer_pthread_attr_t myattr;
455-
if (!attr) {
456+
if (!attr || attr == __ATTRP_C11_THREAD) {
456457
pthread_attr_init(&myattr);
457458
attr = &myattr;
458459
}

system/lib/compiler-rt/lib/sanitizer_common/sanitizer_emscripten.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,7 @@ void ListOfModules::init() {
6060

6161
void ListOfModules::fallbackInit() { clear(); }
6262

63-
SANITIZER_WEAK_ATTRIBUTE int
64-
real_sigaction(int signum, const void *act, void *oldact);
65-
6663
int internal_sigaction(int signum, const void *act, void *oldact) {
67-
#if !SANITIZER_GO
68-
if (&real_sigaction)
69-
return real_sigaction(signum, act, oldact);
70-
#endif
7164
return sigaction(signum, (const struct sigaction *)act,
7265
(struct sigaction *)oldact);
7366
}

tests/core/test_dynamic_cast.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,6 @@ struct Derived : Support {};
1616
int main() {
1717
Support* p = new Derived;
1818
dynamic_cast<Derived*>(p)->f();
19+
delete p;
20+
return 0;
1921
}

tests/core/test_em_asm_2.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,11 @@ int main()
102102
i = EM_ASM_INT("{console.log('5. got int ' + $0); return 7.5;}", 42); printf("5. returned int %d\n", i);
103103

104104
printf("\nEM_ASM_INT: Return an integer in a single brief statement.\n");
105-
i = EM_ASM_INT(return HEAP8.length); printf("1. returned statement %d\n", i);
106-
i = EM_ASM_INT("return HEAP8.length+1"); printf("2. returned statement %d\n", i);
107-
i = EM_ASM_INT({"return HEAP8.length+2"}); printf("3. returned statement %d\n", i);
108-
i = EM_ASM_INT({return HEAP8.length+3}); printf("4. returned statement %d\n", i);
109-
i = EM_ASM_INT("return HEAP8.length+4"); printf("5. returned statement %d\n", i);
105+
i = EM_ASM_INT(return 42); printf("1. returned statement %d\n", i);
106+
i = EM_ASM_INT("return 42+1"); printf("2. returned statement %d\n", i);
107+
i = EM_ASM_INT({"return 42+2"}); printf("3. returned statement %d\n", i);
108+
i = EM_ASM_INT({return 42+3}); printf("4. returned statement %d\n", i);
109+
i = EM_ASM_INT("return 42+4"); printf("5. returned statement %d\n", i);
110110

111111
// Note that expressions do not evaluate to return values, but the "return" keyword is needed. That is, the following line would return undefined and store i <- 0.
112112
// i = EM_ASM_INT(HEAP8.length); printf("returned statement %d\n", i);

tests/core/test_em_asm_2.out

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ EM_ASM_INT: Return an integer back.
113113
5. returned int 7
114114

115115
EM_ASM_INT: Return an integer in a single brief statement.
116-
1. returned statement 16777216
117-
2. returned statement 16777217
118-
3. returned statement 16777218
119-
4. returned statement 16777219
120-
5. returned statement 16777220
116+
1. returned statement 42
117+
2. returned statement 43
118+
3. returned statement 44
119+
4. returned statement 45
120+
5. returned statement 46
121121

122122
EM_ASM_DOUBLE: Pass no parameters, return a double.
123123
1. returning double

tests/core/test_emptyclass.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ struct Randomized {
1212
};
1313

1414
int main(int argc, const char *argv[]) {
15-
new Randomized(55);
16-
15+
Randomized(55);
1716
return 0;
1817
}

tests/test_core.py

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ def can_do_standalone(self):
146146
self.get_setting('STACK_OVERFLOW_CHECK', 0) < 2 and \
147147
not self.get_setting('MINIMAL_RUNTIME') and \
148148
not self.get_setting('SAFE_HEAP') and \
149-
'-fsanitize=address' not in self.emcc_args
149+
'-fsanitize=address' not in self.emcc_args and \
150+
'-fsanitize=leak' not in self.emcc_args
150151

151152

152153
def also_with_wasmfs(func):
@@ -602,6 +603,7 @@ def test_align64(self):
602603
''')
603604

604605
@no_asan('asan errors on corner cases we check')
606+
@no_lsan('lsan errors on corner cases we check')
605607
def test_aligned_alloc(self):
606608
self.do_runf(test_file('test_aligned_alloc.c'), '',
607609
emcc_args=['-Wno-non-power-of-two-alignment'])
@@ -815,6 +817,7 @@ def test_stack_placement(self):
815817
self.do_core_test('test_stack_placement.c')
816818

817819
@no_asan('asan does not support main modules')
820+
@no_lsan('asan does not support main modules')
818821
@no_wasm2js('MAIN_MODULE support')
819822
def test_stack_placement_pic(self):
820823
self.set_setting('TOTAL_STACK', 1024)
@@ -1210,7 +1213,8 @@ def test_exceptions_allowed(self):
12101213
# empty list acts the same as fully disabled
12111214
self.assertEqual(empty_size, disabled_size)
12121215
# big change when we disable exception catching of the function
1213-
self.assertGreater(size - empty_size, 0.01 * size)
1216+
if '-fsanitize=leak' not in self.emcc_args:
1217+
self.assertGreater(size - empty_size, 0.01 * size)
12141218
# full disable can remove a little bit more
12151219
self.assertLess(disabled_size, fake_size)
12161220

@@ -1495,6 +1499,7 @@ def test_segfault(self):
14951499
14961500
struct Classey {
14971501
virtual void doIt() = 0;
1502+
virtual ~Classey() = default;
14981503
};
14991504
15001505
struct D1 : Classey {
@@ -1509,11 +1514,11 @@ def test_segfault(self):
15091514
return 0;
15101515
});
15111516
1512-
int main(int argc, char **argv)
1513-
{
1517+
int main(int argc, char **argv) {
15141518
Classey *p = argc == 100 ? new D1() : (Classey*)%s;
15151519
15161520
p->doIt();
1521+
delete p;
15171522
15181523
return 0;
15191524
}
@@ -1696,7 +1701,7 @@ def test_emscripten_api(self):
16961701
self.set_setting('EXPORTED_FUNCTIONS', ['_main', '_save_me_aimee'])
16971702
self.do_core_test('test_emscripten_api.cpp')
16981703

1699-
if '-fsanitize=address' not in self.emcc_args:
1704+
if '-fsanitize=address' not in self.emcc_args and '-fsanitize=leak' not in self.emcc_args:
17001705
# test EXPORT_ALL (this is not compatible with asan, which doesn't
17011706
# support dynamic linking at all or the LINKING flag)
17021707
self.set_setting('EXPORTED_FUNCTIONS', [])
@@ -1838,7 +1843,6 @@ def test_em_asm(self):
18381843
self.do_core_test('test_em_asm.cpp', force_c=True)
18391844

18401845
# Tests various different ways to invoke the EM_ASM(), EM_ASM_INT() and EM_ASM_DOUBLE() macros.
1841-
@no_asan('Cannot use ASan: test depends exactly on heap size')
18421846
def test_em_asm_2(self):
18431847
self.do_core_test('test_em_asm_2.cpp')
18441848
self.emcc_args.append('-std=gnu89')
@@ -1847,7 +1851,6 @@ def test_em_asm_2(self):
18471851
# Tests various different ways to invoke the MAIN_THREAD_EM_ASM(), MAIN_THREAD_EM_ASM_INT() and MAIN_THREAD_EM_ASM_DOUBLE() macros.
18481852
# This test is identical to test_em_asm_2, just search-replaces EM_ASM to MAIN_THREAD_EM_ASM on the test file. That way if new
18491853
# test cases are added to test_em_asm_2.cpp for EM_ASM, they will also get tested in MAIN_THREAD_EM_ASM form.
1850-
@no_asan('Cannot use ASan: test depends exactly on heap size')
18511854
def test_main_thread_em_asm(self):
18521855
src = read_file(test_file('core/test_em_asm_2.cpp'))
18531856
create_file('src.cpp', src.replace('EM_ASM', 'MAIN_THREAD_EM_ASM'))
@@ -1898,10 +1901,8 @@ def test_em_asm_direct(self):
18981901
'linked_c': (['-s', 'MAIN_MODULE'], True),
18991902
})
19001903
def test_em_js(self, args, force_c):
1901-
if 'MAIN_MODULE' in args and not self.is_wasm():
1902-
self.skipTest('main module support for non-wasm')
1903-
if '-fsanitize=address' in self.emcc_args:
1904-
self.skipTest('no dynamic library support in asan yet')
1904+
if 'MAIN_MODULE' in args:
1905+
self.check_dylink()
19051906
self.emcc_args += args + ['-s', 'EXPORTED_FUNCTIONS=_main,_malloc']
19061907

19071908
self.do_core_test('test_em_js.cpp', force_c=force_c)
@@ -2034,6 +2035,7 @@ def test_memorygrowth_3_force_fail_reallocBuffer(self):
20342035
'grow': (['-sALLOW_MEMORY_GROWTH', '-sMAXIMUM_MEMORY=18MB'],)
20352036
})
20362037
@no_asan('requires more memory when growing')
2038+
@no_lsan('requires more memory when growing')
20372039
def test_aborting_new(self, args):
20382040
# test that C++ new properly errors if we fail to malloc when growth is
20392041
# enabled, with or without growth
@@ -2042,6 +2044,7 @@ def test_aborting_new(self, args):
20422044

20432045
@no_wasm2js('no WebAssembly.Memory()')
20442046
@no_asan('ASan alters the memory size')
2047+
@no_lsan('LSan alters the memory size')
20452048
def test_module_wasm_memory(self):
20462049
self.emcc_args += ['--pre-js', test_file('core/test_module_wasm_memory.js')]
20472050
self.set_setting('IMPORTED_MEMORY')
@@ -5157,6 +5160,7 @@ def test_utf8_invalid(self):
51575160
def test_minimal_runtime_utf8_invalid(self):
51585161
self.set_setting('EXPORTED_RUNTIME_METHODS', ['UTF8ToString', 'stringToUTF8'])
51595162
self.set_setting('MINIMAL_RUNTIME')
5163+
self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')]
51605164
for decoder_mode in [False, True]:
51615165
self.set_setting('TEXTDECODER', decoder_mode)
51625166
print(str(decoder_mode))
@@ -5727,6 +5731,7 @@ def test_whets(self):
57275731
# node is slower, and fail on 64-bit
57285732
@require_v8
57295733
@no_asan('depends on the specifics of memory size, which for asan we are forced to increase')
5734+
@no_lsan('depends on the specifics of memory size, which for lsan we are forced to increase')
57305735
def test_dlmalloc_inline(self):
57315736
# needed with typed arrays
57325737
self.set_setting('INITIAL_MEMORY', '128mb')
@@ -5738,6 +5743,7 @@ def test_dlmalloc_inline(self):
57385743
# node is slower, and fail on 64-bit
57395744
@require_v8
57405745
@no_asan('depends on the specifics of memory size, which for asan we are forced to increase')
5746+
@no_lsan('depends on the specifics of memory size, which for lsan we are forced to increase')
57415747
def test_dlmalloc(self):
57425748
# needed with typed arrays
57435749
self.set_setting('INITIAL_MEMORY', '128mb')
@@ -5769,11 +5775,13 @@ def test_dlmalloc(self):
57695775

57705776
# Tests that a large allocation should gracefully fail
57715777
@no_asan('the memory size limit here is too small for asan')
5778+
@no_lsan('the memory size limit here is too small for lsan')
57725779
def test_dlmalloc_large(self):
57735780
self.emcc_args += ['-s', 'ABORTING_MALLOC=0', '-s', 'ALLOW_MEMORY_GROWTH=1', '-s', 'MAXIMUM_MEMORY=128MB']
57745781
self.do_runf(test_file('dlmalloc_test_large.c'), '0 0 0 1')
57755782

57765783
@no_asan('asan also changes malloc, and that ends up linking in new twice')
5784+
@no_lsan('lsan also changes malloc, and that ends up linking in new twice')
57775785
def test_dlmalloc_partial(self):
57785786
# present part of the symbols of dlmalloc, not all
57795787
src = read_file(test_file('new.cpp')).replace('{{{ NEW }}}', 'new int').replace('{{{ DELETE }}}', 'delete') + '''
@@ -5787,6 +5795,7 @@ def test_dlmalloc_partial(self):
57875795
self.do_run(src, 'new 4!\n*1,0*')
57885796

57895797
@no_asan('asan also changes malloc, and that ends up linking in new twice')
5798+
@no_lsan('lsan also changes malloc, and that ends up linking in new twice')
57905799
def test_dlmalloc_partial_2(self):
57915800
if 'SAFE_HEAP' in str(self.emcc_args):
57925801
self.skipTest('we do unsafe stuff here')
@@ -6273,7 +6282,7 @@ def do_test():
62736282
self.set_setting('ALLOW_MEMORY_GROWTH', 0)
62746283
do_test()
62756284

6276-
if '-fsanitize=address' in self.emcc_args:
6285+
if '-fsanitize=address' in self.emcc_args or '-fsanitize=leak' in self.emcc_args:
62776286
# In ASan mode we need a large initial memory (or else wasm-ld fails).
62786287
# The OpenJPEG CMake will build several executables (which we need parts
62796288
# of in our testing, see above), so we must enable the flag for them all.
@@ -7598,6 +7607,7 @@ def test_asyncify_during_exit(self):
75987607
self.do_core_test('test_asyncify_during_exit.cpp', emcc_args=['-DNO_ASYNC'], out_suffix='_no_async')
75997608

76007609
@no_asan('asyncify stack operations confuse asan')
7610+
@no_lsan('undefined symbol __global_base')
76017611
@no_wasm2js('dynamic linking support in wasm2js')
76027612
def test_asyncify_main_module(self):
76037613
self.set_setting('ASYNCIFY', 1)
@@ -7623,7 +7633,7 @@ def test_emscripten_lazy_load_code(self, conditional):
76237633
second_size = os.path.getsize('emscripten_lazy_load_code.wasm.lazy.wasm')
76247634
print('first wasm size', first_size)
76257635
print('second wasm size', second_size)
7626-
if not conditional and self.is_optimizing() and '-g' not in self.emcc_args:
7636+
if not conditional and self.is_optimizing() and '-g' not in self.emcc_args and '-fsanitize=leak' not in self.emcc_args:
76277637
# If the call to lazy-load is unconditional, then the optimizer can dce
76287638
# out more than half
76297639
self.assertLess(first_size, 0.6 * second_size)
@@ -7688,6 +7698,7 @@ def verify_broken(args=['0']):
76887698

76897699
# Test basic wasm2js functionality in all core compilation modes.
76907700
@no_asan('no wasm2js support yet in asan')
7701+
@no_lsan('no wasm2js support yet in lsan')
76917702
def test_wasm2js(self):
76927703
if not self.is_wasm():
76937704
self.skipTest('redundant to test wasm2js in wasm2js* mode')
@@ -7703,6 +7714,7 @@ def test_wasm2js(self):
77037714
self.assertNotExists('test_hello_world.js.mem')
77047715

77057716
@no_asan('no wasm2js support yet in asan')
7717+
@no_lsan('no wasm2js support yet in lsan')
77067718
def test_maybe_wasm2js(self):
77077719
if not self.is_wasm():
77087720
self.skipTest('redundant to test wasm2js in wasm2js* mode')
@@ -7872,10 +7884,12 @@ def test_brk(self):
78727884
# Tests that we can use the dlmalloc mallinfo() function to obtain information
78737885
# about malloc()ed blocks and compute how much memory is used/freed.
78747886
@no_asan('mallinfo is not part of ASan malloc')
7887+
@no_lsan('mallinfo is not part of LSan malloc')
78757888
def test_mallinfo(self):
78767889
self.do_runf(test_file('mallinfo.cpp'), 'OK.')
78777890

78787891
@no_asan('cannot replace malloc/free with ASan')
7892+
@no_lsan('cannot replace malloc/free with LSan')
78797893
def test_wrap_malloc(self):
78807894
self.do_runf(test_file('wrap_malloc.cpp'), 'OK.')
78817895

@@ -7952,6 +7966,7 @@ def test_minimal_runtime_no_declare_asm_module_exports(self):
79527966
self.set_setting('WASM_ASYNC_COMPILATION', 0)
79537967
self.maybe_closure()
79547968
self.set_setting('MINIMAL_RUNTIME')
7969+
self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')]
79557970
self.do_runf(test_file('declare_asm_module_exports.cpp'), 'jsFunction: 1')
79567971

79577972
# Tests that -s MINIMAL_RUNTIME=1 works well in different build modes
@@ -7977,6 +7992,7 @@ def test_minimal_runtime_hello_world(self, args):
79777992
@no_asan('TODO: ASan support in minimal runtime')
79787993
def test_minimal_runtime_hello_printf(self, extra_setting):
79797994
self.set_setting('MINIMAL_RUNTIME')
7995+
self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')]
79807996
self.set_setting(extra_setting)
79817997
# $FS is not fully compatible with MINIMAL_RUNTIME so fails with closure
79827998
# compiler. lsan also pulls in $FS
@@ -7988,6 +8004,7 @@ def test_minimal_runtime_hello_printf(self, extra_setting):
79888004
@no_asan('TODO: ASan support in minimal runtime')
79898005
def test_minimal_runtime_safe_heap(self):
79908006
self.set_setting('MINIMAL_RUNTIME')
8007+
self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')]
79918008
self.set_setting('SAFE_HEAP')
79928009
# $FS is not fully compatible with MINIMAL_RUNTIME so fails with closure
79938010
# compiler.
@@ -8000,6 +8017,7 @@ def test_minimal_runtime_safe_heap(self):
80008017
@no_asan('TODO: ASan support in minimal runtime')
80018018
def test_minimal_runtime_global_initializer(self):
80028019
self.set_setting('MINIMAL_RUNTIME')
8020+
self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')]
80038021
self.maybe_closure()
80048022
self.do_runf(test_file('test_global_initializer.cpp'), 't1 > t0: 1')
80058023

@@ -8010,6 +8028,7 @@ def test_return_address(self):
80108028

80118029
@no_wasm2js('TODO: sanitizers in wasm2js')
80128030
@no_asan('-fsanitize-minimal-runtime cannot be used with ASan')
8031+
@no_lsan('-fsanitize-minimal-runtime cannot be used with LSan')
80138032
def test_ubsan_minimal_too_many_errors(self):
80148033
self.emcc_args += ['-fsanitize=undefined', '-fsanitize-minimal-runtime']
80158034
if not self.is_wasm():
@@ -8022,6 +8041,7 @@ def test_ubsan_minimal_too_many_errors(self):
80228041

80238042
@no_wasm2js('TODO: sanitizers in wasm2js')
80248043
@no_asan('-fsanitize-minimal-runtime cannot be used with ASan')
8044+
@no_lsan('-fsanitize-minimal-runtime cannot be used with LSan')
80258045
def test_ubsan_minimal_errors_same_place(self):
80268046
self.emcc_args += ['-fsanitize=undefined', '-fsanitize-minimal-runtime']
80278047
if not self.is_wasm():
@@ -8527,6 +8547,7 @@ def test_minimal_runtime_emscripten_get_exported_function(self):
85278547
# Could also test with -s ALLOW_TABLE_GROWTH=1
85288548
self.set_setting('RESERVED_FUNCTION_POINTERS', 2)
85298549
self.set_setting('MINIMAL_RUNTIME')
8550+
self.emcc_args += ['--pre-js', test_file('minimal_runtime_exit_handling.js')]
85308551
self.emcc_args += ['-lexports.js']
85318552
self.do_core_test('test_get_exported_function.cpp')
85328553

0 commit comments

Comments
 (0)