Skip to content

[Swift] Fix scalar-key lookupByKey comparison and sortVectorOf* comparator - #9204

Open
bianyeyu wants to merge 1 commit into
google:masterfrom
bianyeyu:swift-fix-scalar-key-sorted-vectors
Open

[Swift] Fix scalar-key lookupByKey comparison and sortVectorOf* comparator#9204
bianyeyu wants to merge 1 commit into
google:masterfrom
bianyeyu:swift-fix-scalar-key-sorted-vectors

Conversation

@bianyeyu

Copy link
Copy Markdown

Summary

Swift code generation has never correctly implemented scalar-key sorted-vector support (it landed with the Swift generator in #5603). Two independent bugs make the feature unusable:

  1. lookupByKey compares the stored key against 0 instead of the search key. The scalar branch generated

    let comp = fbb.read(def: {{TYPE}}.self, position: Int(<offset>))
    if comp > 0 { ... } else if comp < 0 { ... } else { return element }

    so the binary search compares each stored key to 0, not to the search key. For unsigned keys every present non-zero value takes the comp > 0 branch (negative values take comp < 0 for signed keys), and a serialized 0 key is treated as a hit for any query. In the common case — a vector without a serialized 0 key — a lookup by a non-zero key returns nil.

  2. sortVectorOf* feeds scalar key slots into the string-oriented Table.compare. The sort does not order the vector by key: the inline scalar bytes are treated as a string uoffset, so the comparator reads unrelated buffer bytes. If the decoded string length is negative, Table.compare's for i in 0...minValue traps (Range requires lowerBound <= upperBound); whether that happens depends on nearby buffer contents — high-bit keys such as large UInt64 values make it more likely, but the same keys can also just sort in the wrong order.

Both bugs have been present since the Swift generator landed (#5603, January 2020).

Fix

  • lookupByKey: generate an explicit three-way comparison between the stored key value and the search key. Subtraction is deliberately avoided — unsigned subtraction can underflow and traps in Swift.
  • sortVectorOf*: branch on key type; scalar keys now compare the key values directly with <. The string-key code path is unchanged.

Verification

  • Code regenerated with scripts/generate_code.py; only the two Swift monster_test_generated.swift files change, and all string-key paths are byte-identical.
  • New regression tests in tests/swift/Tests/Flatbuffers/ScalarKeySortedVectorTests.swift:
    • lookupByNonZeroScalarKey — lookups by non-zero UInt16 keys hit the right element; absent keys return nil.
    • sortVectorOfScalarKeySortsAscendingsortVectorOfStat produces ascending key order and the result is searchable.
    • sortVectorOfHighUInt64KeyssortVectorOfReferrable with 0xFFFFFFFFFFFFFFF1…FFF3-class keys sorts into ascending order.

…rator

Scalar-key sorted vector support was never correctly implemented:
lookupByKey compared the stored key against 0 instead of the search
key, so non-zero-key lookups always returned nil; sortVectorOf* fed
scalar key slots into the string-oriented Table.compare, so vectors
were not sorted by key and high-bit scalar keys could trap the
runtime. Use an explicit three-way comparison for lookups (unsigned
subtraction would trap) and a direct scalar comparator for sorting.
@bianyeyu
bianyeyu requested a review from dbaileychess as a code owner August 20, 2026 17:27
@github-actions github-actions Bot added c++ codegen Involving generating code from schema swift labels Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ codegen Involving generating code from schema swift

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant