Conversation
luerl:put_private/3 holds values that are deliberately unreachable from
Lua. gc/1's root set did not include them, so the collector freed the
tables underneath any reference kept there and the embedder's next
decode/2 failed with a badkey on a reclaimed index - a use-after-free
with a delayed and confusing failure.
Adds a regression test, which fails on develop with {badkey,14}.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
luerl:put_private/3is documented as putting "a privateValueunderKeythat is not exposed to the runtime".
luerl_heap:gc/1's root set is[Meta..., G | Stk]plus the call stack (luerl_heap.erl:601-602) and doesnot include the private store.
So a reference kept there is unreachable from the collector's point of view.
The collector frees the table underneath it, the reference survives as an
opaque term, and the embedder's next
decode/2fails on a reclaimed index:The failure is delayed and does not point at the collection that caused it,
and the API is exactly the one that invites keeping a reference there.
Adding the store to the root set is one line. Included is a regression test,
which fails on
developwith{badkey,14}.Verification
rebar3 eunit31/0 (30 existing plus the new test) andrebar3 ct11/11.Found while investigating unbounded Luerl memory growth in a game backend.
The workaround without this is to anchor the value in a global for the
duration of the collection and remove it straight after, which is visible to
script code in between.