-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[stdlib] Set, Dictionary: Radically improved index validation #19576
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The mutation count will allow us to recognize and trap on invalid indices more reliably. (However, it won’t be foolproof — some invalid indices may pass through the checks.) - Change _scale to Int8 to make space for an extra Int32 without enlarging the storage header. - Add an _age field inside the new gap. - Initialize the age to a scrambled version of the storage address. - Generate a new counter for every newly allocated storage instance, except for identical copy-on-write copies. - Increment the mutation counter after every removal.
(For symmetry with Dictionary, which already has this check.)
Also add static_assert for Set/Dictionary storage header size.
Set and Dictionary will start using this shortly as their native index types.
@swift-ci please test |
@swift-ci please benchmark |
@swift-ci please test source compatibility |
Note: This is really only about native indices. Cocoa index validation and the interaction between Cocoa and native indices could use some improvements, too -- that's the next task on my list. |
Build comment file:Performance: -O
Code size: -O
Performance: -Osize
Code size: -Osize
Performance: -Onone
How to read the dataThe tables contain differences in performance which are larger than 8% and differences in code size which are larger than 1%.If you see any unexpected regressions, you should consider fixing the regressions before you merge the PR. Noise: Sometimes the performance results (not code size!) contain false alarms. Unexpected regressions which are marked with '(?)' are probably noise. If you see regressions which you cannot explain you can try to run the benchmarks again. If regressions still show up, please consult with the performance team (@eeckstein). Hardware Overview
|
That's weird -- this is the same package that started failing after #19500 landed. It failed only in the debug build, so this may actually be an unrelated a Hashable violation (i.e., a bug in the package). The detection of those is nondeterministic, so the failure would randomly come and go. |
fluent had some failures in PR testing over the last few days, but it's unclear to me if #19500 was still in play. I'll take a closer look. |
Hm, I can't seem to reproduce the failure with my local toolchain build. @swift-ci please test source compatibility |
…-level indices Native sets and (especially!) native dictionaries must support indexing with Cocoa indices — indices must be preserved when a Cocoa set/dictionary is converted to native. This is especially the case for Dictionaries that were converted because of a mutation restricted to values — such as those done through the Values view.
…sages Capital Index seems too nitpicky, somehow
This makes it a little easier to follow validation logic.
Like before, allow the use of Cocoa indices to access native sets/dictionaries, but approximate the same mutation count-based check as we do for native indices. - Ensure that native collections that were converted from Cocoa have an age generated from the address of the original Cocoa object. - To get the age of a Cocoa index, regenerate one from the object embedded in it. - Compare self.age to index.age and trap if it doesn’t match. # Conflicts: # stdlib/public/core/HashTable.swift
Affected operations: subscript(index:) remove(at:) Note that index(after:) is intentionally not on this list.
…tionaries Affected operations: subscript(index:) keys.subscript(index:) values.subscript(index:) (setter and _modify) remove(at:) swapAt(_:, _:) Note that index(after:) is intentionally not on this list.
…an internal error
Build failed |
@swift-ci please test macOS platform |
Build failed |
There is a missing compile-time conditional; I'll push a fix once the other tests finish. |
The source compat suite failed again. #19594 produced the same failure, which indicates it's an unrelated regression from earlier. (Quite probably caused by a Set/Dictionary bug, though.) I'm working to reproduce & fix it. However, I think it might be best to land this so that I don't have to split my brain between two separate codebases. |
@swift-ci please smoke test |
@swift-ci please test linux platform |
Build failed |
@swift-ci please test linux platform |
@swift-ci please smoke test |
@swift-ci please smoke test compiler performance |
(This part 2 of a resubmission of #19537; part 1 with the boring parts has landed already in #19574.)
Set and Dictionary invalidate all previously vended indices whenever one of these two operations occur:
Currently, we attempt to detect if someone reuses an invalid index or uses an index from an unrelated collection by simply verifying that it points to an occupied bucket. This isn't nearly enough.
We can detect invalid indices with a much higher degree of confidence by including a mutation counter in the storage header of every set/dictionary, and inside every native index.
Obviously this isn't a 100% foolproof method -- mutation counters can wrap around, or they can just happen to be initialized to the same value. However, checking the counter is a cheap and reasonably reliable way to catch accidental misuse:
rdar://problem/18191576