You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Unexpected release of a managed pointer in wrapper.call #20095
In my C++ library there's a class that manages a list (vector) of std::unique_ptr and hence manages the life time of the objects (in this case instances of a Token class). When any of the tokens is needed the raw pointer is passed around, but of course must not be managed elsewhere.
One of the consumers of a token pointer is a listener class, which is bound with embind and its methods can be overriden in JS. The wrapper is defined as:
When the syntaxError method is called (from the wrapper code) it does everything nicely, but when it returns, the token value is deleted, even though it is managed by a unique_ptr. Is that a bug, a gotcha or an error on my side and how can I prevent the premature release?
Work Around
I just found a work around to avoid the premature release, by calling offendingSymbol.clone() in the syntaxError method body, though that looks a bit hackish to me...
You are saying that calling syntaxError is somehow causing call to delete offendingSymbol ? I don't see how or why that might be. Do you have a backtrace to see exactly where this delete call is coming from? Give that `offendingSymbol is simply a raw pointer that seems rather odd.
and checking that shows there're even more bad delete calls. The first parameter is the parser instance which is currently running, and the last parameter (arg5) is just the address to a C++ ref, which cannot be deleted. I wonder what's going on here.
@sbc100 Do you think this is a bug in emscripten? It doesn't look like it's intended, but maybe there's an extra aspect to consider, which is not (prominently) mentioned in the docs?
I imagine its some nuance about how smart pointers work under embind, and I would guess its working as indended, but I don't know enough about embind and smart pointers to know for sure.
@brendandahl is OOO all this week but I would imagine he will know for sure.
I'd say this is a bug. Usually when using val::call with raw pointers you'll get the error Implicitly binding raw pointers is illegal. It only allows copies of objects to be sent across so the behaviour of deleting the object makes sense. I'm not quite sure yet why that error doesn't also trigger when using wrapper::call since that uses val::call.
Would be good if I could say embind to not touch a raw pointer at all. No deletion, no copy, no management and so on. Usually, when a C++ library uses a raw pointer it has good idea how to manage that anyway. Things get complicated when you create a C++ instance in JS, though. Tricky ...
Small correction to my comment above... The problem is not unique to wrapper::call it also affects val::call e.g.:
val window = val::global("window");
Foo foo;
window.call<void>("invoke", &foo); // Fails to compile
Foo* fooPtr = &foo;
window.call<void>("invoke", fooPtr); // Compiles fine
I'm not sure of the original intention, but I'm guessing that both of those lines should fail to compile since they both are using raw pointers. val::call takes a universal reference which trips up the static_assert that checks if a pointer is sent.
We should probably fix the assert and also make it so call supports policies like allow_raw_pointers().
Activity
sbc100 commentedon Aug 22, 2023
You are saying that calling
syntaxErroris somehow causing call todelete offendingSymbol? I don't see how or why that might be. Do you have a backtrace to see exactly where this delete call is coming from? Give that `offendingSymbol is simply a raw pointer that seems rather odd.@brendandahl might have more insight.
mike-lischke commentedon Aug 23, 2023
Here's the code from the generated method caller (which calls the
syntaxErrormethod in JS):and checking that shows there're even more bad delete calls. The first parameter is the parser instance which is currently running, and the last parameter (arg5) is just the address to a C++ ref, which cannot be deleted. I wonder what's going on here.
mike-lischke commentedon Aug 28, 2023
@sbc100 Do you think this is a bug in emscripten? It doesn't look like it's intended, but maybe there's an extra aspect to consider, which is not (prominently) mentioned in the docs?
sbc100 commentedon Aug 28, 2023
I imagine its some nuance about how smart pointers work under embind, and I would guess its working as indended, but I don't know enough about embind and smart pointers to know for sure.
@brendandahl is OOO all this week but I would imagine he will know for sure.
brendandahl commentedon Sep 7, 2023
I'd say this is a bug. Usually when using
val::callwith raw pointers you'll get the errorImplicitly binding raw pointers is illegal. It only allows copies of objects to be sent across so the behaviour of deleting the object makes sense. I'm not quite sure yet why that error doesn't also trigger when usingwrapper::callsince that usesval::call.mike-lischke commentedon Sep 7, 2023
Would be good if I could say embind to not touch a raw pointer at all. No deletion, no copy, no management and so on. Usually, when a C++ library uses a raw pointer it has good idea how to manage that anyway. Things get complicated when you create a C++ instance in JS, though. Tricky ...
brendandahl commentedon Sep 7, 2023
Small correction to my comment above... The problem is not unique to
wrapper::callit also affectsval::calle.g.:I'm not sure of the original intention, but I'm guessing that both of those lines should fail to compile since they both are using raw pointers.
val::calltakes a universal reference which trips up the static_assert that checks if a pointer is sent.We should probably fix the assert and also make it so
callsupports policies likeallow_raw_pointers().embind: Don't automatically destroy arguments passed into val calls.
embind: Don't automatically destroy arguments passed into val calls.
embind: Don't automatically destroy arguments passed into val calls.
embind: Don't automatically destroy arguments passed into val calls. (#…