Repository navigation
Conversation
Previously TypeBuilder would fail to properly replace all temporary types with globally canonical types when a type was used more than once. Consider this temporary type: ``` (struct (field (ref (struct)) (ref (struct)))) ``` This heap type contains two `(ref (struct))` each of which contains an empty `(struct)` heap type. The logic for avoiding duplicate scanning meant that the first inner `(struct)` was scanned, but the second one was not. The expectation was that this would be fine because both occurrences of `(ref (struct))` are backed by the same temporary `TypeInfo`, so replacing the inner type of one would update both at once. However, because scanning is depth-first, the second `(ref (struct))` is scanned after and therefore canonicalized before the first inner `(struct)`. Since `(ref (struct))` was canonicalized before its inner `(struct)`, the temporary `(struct)` heap-type was accidentally leaked into the global canonicalization of the type. This caused the global canonicalization to be incorrect and also caused use-after-free bugs once the TypeBuilder was disposed of. One solution would have been to calculate a topological sort of the types to determine the canonicalization order, but a simpler solution is to simply not worry about duplicate work, scanning and canonicalizing every occurrence of every type in the TypeBuilder's entries. This PR implements the simpler solution.
Member
Author
|
Unfortunately it turns out that the simple solution is insufficient :'( For more complex patterns of types, a similar thing happens where a type ends up being canonicalized before its children. The next simple solution would be to entirely remove the logic for avoiding visiting a node more than once, but that wouldn't work once we want to support recursive types. I think I need to do a topological sort on the types after all. Thankfully the code already collects a dependency graph, so this won't be too much extra code. |
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.
Previously TypeBuilder would fail to properly replace all temporary types with
globally canonical types when a type was used more than once. Consider this
temporary type:
This heap type contains two
(ref (struct))each of which contains an empty(struct)heap type. The logic for avoiding duplicate scanning meant that thefirst inner
(struct)was scanned, but the second one was not. The expectationwas that this would be fine because both occurrences of
(ref (struct))arebacked by the same temporary
TypeInfo, so replacing the inner type of onewould update both at once. However, because scanning is depth-first, the second
(ref (struct))is scanned after and therefore canonicalized before the firstinner
(struct). Since(ref (struct))was canonicalized before its inner(struct), the temporary(struct)heap-type was accidentally leaked into theglobal canonicalization of the type. This caused the global canonicalization to
be incorrect and also caused use-after-free bugs once the TypeBuilder was
disposed of.
One solution would have been to calculate a topological sort of the types to
determine the canonicalization order, but a simpler solution is to simply not
worry about duplicate work, scanning and canonicalizing every occurrence of
every type in the TypeBuilder's entries. This PR implements the simpler
solution.