Skip to content

Commit 9288d0f

Browse files
committed
embind: Add workaround for unstable type-ids when requiring type
Due to TypeIDs not being stable between modules when the type info is not visible outside the side-module, embind fails to look up the registered type for a TypeID that has been registered from another module. This is for example the case for emscripten::val, which is registered by embind.cpp. If another module uses the templated val(T&& value) constructor, it will result in a call to _emval_take_value where the passed type id is resolved in the context of the calling module. If these two differ, it will result in a binding error thrown: BindingError: emval::as has unknown type N10emscripten3valE As long as we can't guarantee stable type-ids across modules, we work around the issue by looking for a matching existing registered type based on the type name, and if one is found we register the missing type-id with the same information. Fixes: #16711
1 parent c092f82 commit 9288d0f

File tree

2 files changed

+46
-1
lines changed

2 files changed

+46
-1
lines changed

src/embind/embind.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ var LibraryEmbind = {
298298
$registeredPointers: {},
299299

300300
$registerType__deps: [
301-
'$awaitingDependencies', '$registeredTypes',
301+
'$awaitingDependencies', '$registeredTypes', '$getTypeName',
302302
'$typeDependencies', '$throwBindingError',
303303
'$whenDependentTypesAreResolved'],
304304
$registerType__docs: '/** @param {Object=} options */',
@@ -319,6 +319,12 @@ var LibraryEmbind = {
319319
}
320320
}
321321

322+
#if SIDE_MODULE || MAIN_MODULE
323+
// Store type name as well, which may or may not match the registered
324+
// name, depending on mangling and the actual calls to register_foo.
325+
registeredInstance.typeName = getTypeName(rawType);
326+
#endif
327+
322328
registeredTypes[rawType] = registeredInstance;
323329
delete typeDependencies[rawType];
324330

@@ -416,6 +422,20 @@ var LibraryEmbind = {
416422
$requireRegisteredType: function(rawType, humanName) {
417423
var impl = registeredTypes[rawType];
418424
if (undefined === impl) {
425+
#if SIDE_MODULE || MAIN_MODULE
426+
// Fallback, in case of shared libraries, where the TypeID (rawType)
427+
// for each type is not stable across library boundaries.
428+
var typeName = getTypeName(rawType);
429+
for (const typeId in registeredTypes) {
430+
var type = registeredTypes[typeId];
431+
if (type.typeName == typeName) {
432+
registerType(rawType, type, {
433+
ignoreDuplicateRegistrations: true,
434+
});
435+
return type;
436+
}
437+
}
438+
#endif
419439
throwBindingError(humanName + " has unknown type " + getTypeName(rawType));
420440
}
421441
return impl;

test/test_core.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7684,6 +7684,31 @@ def test_embind_no_rtti_followed_by_rtti(self):
76847684
self.emcc_args += ['-lembind', '-fno-rtti', '-frtti']
76857685
self.do_run(src, '418\ndotest returned: 42\n')
76867686

7687+
@needs_dylink
7688+
def test_embind_type_registration_when_typeid_is_not_stable(self):
7689+
# See test_dylink_typeid
7690+
self.emcc_args += ['-lembind', '-fvisibility=hidden']
7691+
self.dylink_test(header=r'''
7692+
#include <emscripten.h>
7693+
#include <emscripten/bind.h>
7694+
#include <emscripten/val.h>
7695+
#include <stdio.h>
7696+
''', main=r'''
7697+
#include "header.h"
7698+
int main() {
7699+
emscripten::val intVal(42);
7700+
emscripten::val valVal(intVal);
7701+
puts("success");
7702+
return 0;
7703+
}
7704+
''', side=r'''
7705+
#include "header.h"
7706+
__attribute__((constructor)) void kaboom() {
7707+
emscripten::val intVal(42);
7708+
emscripten::val valVal(intVal);
7709+
}
7710+
''', expected=['success'], need_reverse=False)
7711+
76877712
@no_wasm64('webidl not compatible with MEMORY64 yet')
76887713
@parameterized({
76897714
'': ('DEFAULT', False),

0 commit comments

Comments
 (0)