Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
TLDR: do not use
tclone
as it's freed on library unload;interface
isany
,typeid
is vtable and can be easily overwritten withany_make
.This will still break if you change data layout or add new (unhandled) types, so it should be on par with C.
Here's an explanation of how I came up with that.
Let's try to see what's actually happening during the hot reload:
But why? Let's fire up the GDB:
Yeah, I can only agree with that. AAAAAAAAAAAAAAAA!
What's
*((void **)state+2)
? It'sstate.anim
, the instance ofFuture
interface (akaany
)Let's add watchpoint and see what updates it:
Mistery solved, I guess.
But this is not the end yet. If code layout changes even a little bit, we'll be greeted with
That's interesting... So, apparently, dynamic dispatch failed.
Let's patch vtables then. Shouldn't be too hard, right? Padme.jpeg
Since interface is basically an
any
containing a pointer and atypeid
(which is actually just a pointer to a global vtable), we can justCan your C++ or (safe) Rust do that? I don't fucking think so.
The actual implementation in this PR is a bit different so that this code would be closer to where
state.anim
is actually allocated.Of course, there are some limitations, so having language support would've been much better.
It's actually not that hard to implement by hooking into the allocator (so that it'll export hashmap of
typeid *
toString
before unload and optionally import after reload).I'll leave this as an exercise to the streamer.
EDIT: There is a
TrackingAllocator
which does almost that, but without thetypeid*
which needs to be tracked separately.