Open wffurr opened 3 years ago
Here's a short example of how this works.
In the iframe's code, e.g. iframe.js
:
var emscriptenBinary = require('./my_emscripten_binary.js');
emscriptenBinary().then(instance => {
window.foo = new (instance.Foo)(); // initialize some embind type
window.parent.postMessage({type: 'ready'}, '*');
});
In the parent window's code, e.g. app.js
:
window.addEventListener('message', messageEvent => {
if (messageEvent.type === 'ready') {
const result = window.frames[0].foo.frob(); // Call an embind function that returns a string.
}
});
Note how the parent window calls into a function in an object on the iframe's window. All instanceof
checks in that call will fail because they will be checking against the prototype objects in the parent window's realm, not the iframe's.
The other advice in the O'Reilly book on handling this is to just not make cross-realm calls. I think we can make Emscripten robust against this though.
Note this can be worked around at a performance hit (especially for large strings) with -s TEXTDECODER=0
compilation option.
I hit the same problem in a different context.
When pthread is enabled, and a tab is duplicated (Chrome, right click tab -> Duplicate), somehow the buffer sent from wasm (via embind) is actually a SAB but instanceof SharedArrayBuffer
returns false. It causes a shared buffer being sent to TextDecoder
and triggers this exact same exception.
@jiulongw Does "duplicate tab" not just open a new tab with the same URL? Or does it involve an iframe somehow?
If it does not involve an iframe then it sounds like a browser bug, and we should file a bug on Chrome. Also we can file a bug if we are not sure either way.
I feel duplicating a tab is not simply a new tab with same URL. It carries some sort of state or context from the tab being duplicated.
I will try to repro it without involving Emscripten and open a bug to Chromium.
Either way, this patch might still be useful for people hitting this issue, given Symbol.toStringTag
is supported by major browsers, and faster than instanceof
.
String types via embind sometimes fail with:
When the embind functions are called through an iframe. The
instanceof
check inTextDecoderWrapper
fails when the object is from an iframe, which is a separate JavaScript realm.This is a known problem with
instanceof
checks and iframes:https://www.oreilly.com/library/view/speaking-javascript/9781449365028/ch17.html#cross-realm_instanceof https://jakearchibald.com/2017/arrays-symbols-realms/#multiple-realms https://esdiscuss.org/topic/cross-global-instanceof
For built-ins, the only real workaround is checking
foo.constructor.name
->ArrayBuffer
orObject.getPrototypeOf(foo).toString()
->[object ArrayBuffer]
.This should work in all WebAssembly-supporting browsers.