diff --git a/site/source/docs/tools_reference/settings_reference.rst b/site/source/docs/tools_reference/settings_reference.rst index 36d449ba52adc..c524e4883f013 100644 --- a/site/source/docs/tools_reference/settings_reference.rst +++ b/site/source/docs/tools_reference/settings_reference.rst @@ -409,7 +409,9 @@ Print out exceptions in emscriptened code. DEMANGLE_SUPPORT ================ -If 1, export `demangle` and `stackTrace` helper function. +If 1, export `demangle` and `stackTrace` JS library functions. + +.. note:: This setting is deprecated .. _library_debug: diff --git a/src/library_legacy.js b/src/library_legacy.js index 1ed91cb6c8be8..bf0c0ef2cbb62 100644 --- a/src/library_legacy.js +++ b/src/library_legacy.js @@ -90,4 +90,34 @@ addToLibrary({ return 0; }, #endif + +#if LINK_AS_CXX + $demangle__deps: ['$withStackSave', '__cxa_demangle', 'free', '$stringToUTF8OnStack'], + $demangle: (func) => { + // If demangle has failed before, stop demangling any further function names + // This avoids an infinite recursion with malloc()->abort()->stackTrace()->demangle()->malloc()->... + demangle.recursionGuard = (demangle.recursionGuard|0)+1; + if (demangle.recursionGuard > 1) return func; + return withStackSave(() => { + try { + var s = func; + if (s.startsWith('__Z')) + s = s.substr(1); + var buf = stringToUTF8OnStack(s); + var status = stackAlloc(4); + var ret = ___cxa_demangle(buf, 0, 0, status); + if ({{{ makeGetValue('status', '0', 'i32') }}} === 0 && ret) { + return UTF8ToString(ret); + } + // otherwise, libcxxabi failed + } catch(e) { + } finally { + _free(ret); + if (demangle.recursionGuard < 2) --demangle.recursionGuard; + } + // failure when using libcxxabi, don't demangle + return func; + }); + }, +#endif }); diff --git a/src/library_stack_trace.js b/src/library_stack_trace.js index 90685b9dcb9c4..17e5c76e0fe82 100644 --- a/src/library_stack_trace.js +++ b/src/library_stack_trace.js @@ -5,43 +5,6 @@ */ var LibraryStackTrace = { -#if DEMANGLE_SUPPORT - $demangle__deps: ['$withStackSave', '__cxa_demangle', 'free', '$stringToUTF8OnStack'], -#endif - $demangle: (func) => { -#if DEMANGLE_SUPPORT - // If demangle has failed before, stop demangling any further function names - // This avoids an infinite recursion with malloc()->abort()->stackTrace()->demangle()->malloc()->... - demangle.recursionGuard = (demangle.recursionGuard|0)+1; - if (demangle.recursionGuard > 1) return func; - return withStackSave(() => { - try { - var s = func; - if (s.startsWith('__Z')) - s = s.substr(1); - var buf = stringToUTF8OnStack(s); - var status = stackAlloc(4); - var ret = ___cxa_demangle(buf, 0, 0, status); - if ({{{ makeGetValue('status', '0', 'i32') }}} === 0 && ret) { - return UTF8ToString(ret); - } - // otherwise, libcxxabi failed - } catch(e) { - } finally { - _free(ret); - if (demangle.recursionGuard < 2) --demangle.recursionGuard; - } - // failure when using libcxxabi, don't demangle - return func; - }); -#else // DEMANGLE_SUPPORT -#if ASSERTIONS - warnOnce('warning: build with -sDEMANGLE_SUPPORT to link in libcxxabi demangling'); -#endif // ASSERTIONS - return func; -#endif // DEMANGLE_SUPPORT - }, - $jsStackTrace: function() { var error = new Error(); if (!error.stack) { diff --git a/src/settings.js b/src/settings.js index 1fa50cb69e450..3298c928e6cd9 100644 --- a/src/settings.js +++ b/src/settings.js @@ -337,8 +337,9 @@ var EMULATE_FUNCTION_POINTER_CASTS = false; // [link] var EXCEPTION_DEBUG = false; -// If 1, export `demangle` and `stackTrace` helper function. +// If 1, export `demangle` and `stackTrace` JS library functions. // [link] +// [deprecated] var DEMANGLE_SUPPORT = false; // Print out when we enter a library call (library*.js). You can also unset diff --git a/test/test_core.py b/test/test_core.py index e4aab1e160b3c..31e873d4462ce 100644 --- a/test/test_core.py +++ b/test/test_core.py @@ -7213,7 +7213,6 @@ def test_emulate_function_pointer_casts(self): }) def test_demangle_stacks(self, extra_args): self.emcc_args += extra_args - self.set_setting('DEMANGLE_SUPPORT') self.set_setting('ASSERTIONS') # disable aggressive inlining in binaryen self.set_setting('BINARYEN_EXTRA_PASSES', '--one-caller-inline-max-function-size=1') @@ -7234,7 +7233,6 @@ def test_demangle_stacks_symbol_map(self): self.set_setting('BINARYEN_EXTRA_PASSES', '--one-caller-inline-max-function-size=1') self.set_setting('DEFAULT_LIBRARY_FUNCS_TO_INCLUDE', '$stackTrace') - self.set_setting('DEMANGLE_SUPPORT') self.set_setting('ENVIRONMENT', 'node,shell') if '-O' not in str(self.emcc_args) or '-O0' in self.emcc_args or '-O1' in self.emcc_args or '-g' in self.emcc_args: self.skipTest("without opts, we don't emit a symbol map") @@ -7943,7 +7941,6 @@ def test_modularize_closure_pre(self): @no_wasm2js('symbol names look different wasm2js backtraces') @also_with_wasm_bigint def test_emscripten_log(self): - self.set_setting('DEMANGLE_SUPPORT') if '-g' not in self.emcc_args: self.emcc_args.append('-g') self.emcc_args += ['-DRUN_FROM_JS_SHELL', '-Wno-deprecated-pragma'] diff --git a/test/test_other.py b/test/test_other.py index 7a8f24abecab4..7969dd3ab4c5f 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3466,10 +3466,13 @@ def test_syntax_only_invalid(self): self.assertContained("src.c:1:13: error: expected '}'", err) self.assertNotExists('a.out.js') + # `demangle` is a legacy JS function on longer used by emscripten + # TODO(sbc): Remove `demangle` and this test. def test_demangle(self): create_file('src.cpp', ''' #include #include + void two(char c) { EM_ASM(out(stackTrace())); } @@ -3547,10 +3550,10 @@ def test_demangle_cpp(self): self.do_runf('src.cpp', 'Waka::f::a23412341234::point()') - # Test that malloc() -> OOM -> abort() -> stackTrace() -> jsStackTrace() -> demangleAll() -> demangle() -> malloc() - # cycle will not produce an infinite loop. + # Test that malloc() -> OOM -> abort() -> stackTrace() -> jsStackTrace() + # cycle will not cycle back to malloc to produce an infinite loop. def test_demangle_malloc_infinite_loop_crash(self): - self.run_process([EMXX, test_file('malloc_demangle_infinite_loop.cpp'), '-g', '-sABORTING_MALLOC', '-sDEMANGLE_SUPPORT']) + self.run_process([EMXX, test_file('malloc_demangle_infinite_loop.cpp'), '-g', '-sABORTING_MALLOC']) output = self.run_js('a.out.js', assert_returncode=NON_ZERO) if output.count('Cannot enlarge memory arrays') > 5: print(output) @@ -8423,7 +8426,7 @@ def test_metadce_minimal_pthreads(self): 'except': (['-O2', '-fexceptions'], [], ['waka']), # noqa # exceptions does not pull in demangling by default, which increases code size 'mangle': (['-O2', '-fexceptions', - '-sDEMANGLE_SUPPORT'], [], ['waka']), # noqa + '-sDEMANGLE_SUPPORT', '-Wno-deprecated'], [], ['waka']), # noqa # Wasm EH's code size increase is smaller than that of Emscripten EH 'except_wasm': (['-O2', '-fwasm-exceptions'], [], ['waka']), # noqa # eval_ctors 1 can partially optimize, but runs into getenv() for locale diff --git a/tools/link.py b/tools/link.py index 7c8be90a73087..b38539e4eee82 100644 --- a/tools/link.py +++ b/tools/link.py @@ -701,6 +701,9 @@ def phase_linker_setup(options, state, newargs): if 'SUPPORT_ERRNO' in user_settings: diagnostics.warning('deprecated', 'SUPPORT_ERRNO is deprecated since emscripten no longer uses the setErrNo library function') + if 'DEMANGLE_SUPPORT' in user_settings: + diagnostics.warning('deprecated', 'DEMANGLE_SUPPORT is deprecated since mangled names no longer appear in stack traces') + if settings.EXTRA_EXPORTED_RUNTIME_METHODS: diagnostics.warning('deprecated', 'EXTRA_EXPORTED_RUNTIME_METHODS is deprecated, please use EXPORTED_RUNTIME_METHODS instead') settings.EXPORTED_RUNTIME_METHODS += settings.EXTRA_EXPORTED_RUNTIME_METHODS