|
7 | 7 | # noqa: E241 |
8 | 8 |
|
9 | 9 | from __future__ import print_function |
| 10 | +from functools import wraps |
10 | 11 | import difflib |
11 | 12 | import filecmp |
12 | 13 | import glob |
@@ -64,6 +65,7 @@ def uses_canonical_tmp(func): |
64 | 65 | This decorator takes care of cleaning the directory after the |
65 | 66 | test to satisfy the leak detector. |
66 | 67 | """ |
| 68 | + @wraps(func) |
67 | 69 | def decorated(self): |
68 | 70 | # Before running the test completely remove the canonical_tmp |
69 | 71 | if os.path.exists(self.canonical_temp_dir): |
@@ -134,6 +136,19 @@ def do_other_test(self, dirname, emcc_args=[], run_args=[]): |
134 | 136 | seen = run_js('a.out.js', args=run_args, stderr=PIPE, full_output=True) + '\n' |
135 | 137 | self.assertContained(expected, seen) |
136 | 138 |
|
| 139 | + def do_smart_test(self, source, literals=[], regexes=[], emcc_args=[], run_args=[], assert_returncode=0): |
| 140 | + shutil.copyfile(source, 'test.cpp') |
| 141 | + run_process([PYTHON, EMCC, 'test.cpp'] + emcc_args) |
| 142 | + seen = run_js('a.out.js', args=run_args, stderr=PIPE, full_output=True, |
| 143 | + assert_returncode=assert_returncode) + '\n' |
| 144 | + |
| 145 | + for literal in literals: |
| 146 | + self.assertContained([literal], seen) |
| 147 | + |
| 148 | + for regex in regexes: |
| 149 | + if not re.search(regex, seen): |
| 150 | + self.fail('Expected regex "%s" to match on:\n%s' % (regex, seen)) |
| 151 | + |
137 | 152 | def expect_fail(self, cmd, **args): |
138 | 153 | """Run a subprocess and assert that it returns non-zero. |
139 | 154 |
|
@@ -9233,3 +9248,35 @@ def test(code): |
9233 | 9248 | assert lf - 900 <= f <= lf - 500 |
9234 | 9249 | # both is a little bigger still |
9235 | 9250 | assert both - 100 <= lf <= both - 50 |
| 9251 | + |
| 9252 | + @no_fastcomp('lsan not supported on fastcomp') |
| 9253 | + def test_lsan_leaks(self): |
| 9254 | + self.do_smart_test(path_from_root('tests', 'other', 'test_lsan_leaks.c'), |
| 9255 | + emcc_args=['-fsanitize=leak', '-s', 'ALLOW_MEMORY_GROWTH=1'], |
| 9256 | + assert_returncode=None, literals=[ |
| 9257 | + 'Direct leak of 2048 byte(s) in 1 object(s) allocated from', |
| 9258 | + 'Direct leak of 1337 byte(s) in 1 object(s) allocated from', |
| 9259 | + 'Direct leak of 42 byte(s) in 1 object(s) allocated from', |
| 9260 | + ]) |
| 9261 | + |
| 9262 | + @no_fastcomp('lsan not supported on fastcomp') |
| 9263 | + def test_lsan_stack_trace(self): |
| 9264 | + self.do_smart_test(path_from_root('tests', 'other', 'test_lsan_leaks.c'), |
| 9265 | + emcc_args=['-fsanitize=leak', '-s', 'ALLOW_MEMORY_GROWTH=1', '-g4'], |
| 9266 | + assert_returncode=None, literals=[ |
| 9267 | + 'Direct leak of 2048 byte(s) in 1 object(s) allocated from', |
| 9268 | + 'Direct leak of 1337 byte(s) in 1 object(s) allocated from', |
| 9269 | + 'Direct leak of 42 byte(s) in 1 object(s) allocated from', |
| 9270 | + ], regexes=[ |
| 9271 | + r'(?m)in malloc.*wasm-function', |
| 9272 | + r'(?m)in f\(\) /.*/test\.cpp:6:21$', |
| 9273 | + r'(?m)in main /.*/test\.cpp:10:16$', |
| 9274 | + r'(?m)in main /.*/test\.cpp:12:3$', |
| 9275 | + r'(?m)in main /.*/test\.cpp:13:3$', |
| 9276 | + ]) |
| 9277 | + |
| 9278 | + @no_fastcomp('lsan not supported on fastcomp') |
| 9279 | + def test_lsan_no_leak(self): |
| 9280 | + self.do_smart_test(path_from_root('tests', 'other', 'test_lsan_no_leak.c'), |
| 9281 | + emcc_args=['-fsanitize=leak', '-s', 'ALLOW_MEMORY_GROWTH=1'], |
| 9282 | + regexes=[r'^\s*$']) |
0 commit comments