Avoid mangling + demangling in jsifier.js (#13230)

We had a bug that only showed up with symbols that start with `$_`.
These happen to exist in `library_fetch.js` e.g:
`$__emscripten_fetch_xhr`.  In this case, when we mangle, we remove the
leading `$` giving `__emscripten_fetch_xhr`, and then if we demangle we
do that wrong thing and end up removing the `_` instead of re-adding the
  `$`.

This change avoids the round trip by always storing both the mangled
and demangled version of a given symbol.

See #12268
This commit is contained in:
Sam Clegg 2021-01-11 14:44:25 -08:00 коммит произвёл GitHub
Родитель ad430828f2
Коммит e099eca3f4
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
2 изменённых файлов: 28 добавлений и 21 удалений

Просмотреть файл

@ -28,11 +28,6 @@ function mangleCSymbolName(f) {
return f[0] == '$' ? f.substr(1) : '_' + f;
}
// Reverses C/JS name mangling: _foo -> foo, and foo -> $foo.
function demangleCSymbolName(f) {
return f[0] == '_' ? f.substr(1) : '$' + f;
}
// Splits out items that pass filter. Returns also the original sans the filtered
function splitter(array, filter) {
var splitOut = array.filter(filter);
@ -87,7 +82,8 @@ function JSify(data, functionsOnly) {
}
libFuncsToInclude.forEach(function(ident) {
data.functionStubs.push({
ident: mangleCSymbolName(ident)
identOrig: ident,
identMangled: mangleCSymbolName(ident)
});
});
}
@ -118,31 +114,32 @@ function JSify(data, functionsOnly) {
// In LLVM, exceptions generate a set of functions of form __cxa_find_matching_catch_1(), __cxa_find_matching_catch_2(), etc.
// where the number specifies the number of arguments. In Emscripten, route all these to a single function '__cxa_find_matching_catch'
// that variadically processes all of these functions using JS 'arguments' object.
if (item.ident.startsWith('___cxa_find_matching_catch_')) {
if (item.identMangled.startsWith('___cxa_find_matching_catch_')) {
if (DISABLE_EXCEPTION_THROWING) {
error('DISABLE_EXCEPTION_THROWING was set (likely due to -fno-exceptions), which means no C++ exception throwing support code is linked in, but exception catching code appears. Either do not set DISABLE_EXCEPTION_THROWING (if you do want exception throwing) or compile all source files with -fno-except (so that no exceptions support code is required); also make sure DISABLE_EXCEPTION_CATCHING is set to the right value - if you want exceptions, it should be off, and vice versa.');
return;
}
var num = +item.ident.split('_').slice(-1)[0];
var num = +item.identMangled.split('_').slice(-1)[0];
addCxaCatch(num);
// Continue, with the code below emitting the proper JavaScript based on
// what we just added to the library.
}
function addFromLibrary(ident, dependent) {
function addFromLibrary(item, dependent) {
// dependencies can be JS functions, which we just run
if (typeof item == 'function') return item();
var ident = item.identOrig;
var finalName = item.identMangled;
if (ident in addedLibraryItems) return '';
addedLibraryItems[ident] = true;
// dependencies can be JS functions, which we just run
if (typeof ident == 'function') return ident();
// don't process any special identifiers. These are looked up when processing the base name of the identifier.
if (isJsLibraryConfigIdentifier(ident)) {
return '';
}
var finalName = mangleCSymbolName(ident);
// if the function was implemented in compiled code, we just need to export it so we can reach it from JS
if (finalName in IMPLEMENTED_FUNCTIONS) {
EXPORTED_FUNCTIONS[finalName] = 1;
@ -182,13 +179,11 @@ function JSify(data, functionsOnly) {
// (not useful to warn/error multiple times)
LibraryManager.library[ident + '__docs'] = '/** @type {function(...*):?} */';
} else {
var realIdent = ident;
var target = "Module['" + mangleCSymbolName(realIdent) + "']";
var target = "Module['" + finalName + "']";
var assertion = '';
if (ASSERTIONS) {
var what = 'function';
assertion += 'if (!' + target + ') abort("external symbol \'' + realIdent + '\' is missing. perhaps a side module was not linked in? if this function was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment");\n';
assertion += 'if (!' + target + ') abort("external symbol \'' + ident + '\' is missing. perhaps a side module was not linked in? if this function was expected to arrive from a system library, try to build the MAIN_MODULE with EMCC_FORCE_STDLIBS=1 in the environment");\n';
}
var functionBody = assertion + "return " + target + ".apply(null, arguments);";
@ -274,9 +269,14 @@ function JSify(data, functionsOnly) {
}
});
});
if (VERBOSE) printErr('adding ' + finalName + ' and deps ' + deps + ' : ' + (snippet + '').substr(0, 40));
if (VERBOSE) {
printErr('adding ' + finalName + ' and deps ' + deps + ' : ' + (snippet + '').substr(0, 40));
}
var identDependents = ident + "__deps: ['" + deps.join("','")+"']";
function addDependency(dep) {
if (typeof dep !== 'function') {
dep = {identOrig: dep, identMangled: mangleCSymbolName(dep)};
}
return addFromLibrary(dep, identDependents + ', referenced by ' + dependent);
}
var depsText = (deps ? deps.map(addDependency).filter(function(x) { return x != '' }).join('\n') + '\n' : '');
@ -332,8 +332,7 @@ function JSify(data, functionsOnly) {
}
itemsDict.functionStub.push(item);
var shortident = demangleCSymbolName(item.ident);
item.JS = addFromLibrary(shortident, 'top-level compiled C/C++ code');
item.JS = addFromLibrary(item, 'top-level compiled C/C++ code');
}
// Final combiner

8
tests/test_other.py поставляемый
Просмотреть файл

@ -9713,6 +9713,14 @@ exec "$@"
proc = self.run_process([EMCC, path_from_root('tests', 'hello_world.c'), '--js-library=lib.js'], stderr=PIPE)
self.assertContained('warning: use of #ifdef in js library. Use #if instead.', proc.stderr)
def test_jslib_mangling(self):
create_test_file('lib.js', '''
mergeInto(LibraryManager.library, {
$__foo: function() { return 43; },
});
''')
self.run_process([EMCC, path_from_root('tests', 'hello_world.c'), '--js-library=lib.js', '-s', 'DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[$__foo]'])
def test_wasm2js_no_dynamic_linking(self):
for arg in ['-sMAIN_MODULE', '-sSIDE_MODULE', '-sRELOCATABLE']:
err = self.expect_fail([EMCC, path_from_root('tests', 'hello_world.c'), '-sMAIN_MODULE', '-sWASM=0'])