mirror of
https://github.com/apple/swift.git
synced 2026-06-20 15:42:51 +02:00
5b97cb7c1f
- **Explanation**: Fixes a crash with key paths on 32-bit platforms reproducible for types that have 16-byte alignment. The intended bit layout of `ComputedArgumentSize` in `KeyPath` on 32-bit is: ``` ┌───────┬───────────┐ │ bits │ field │ ├───────┼───────────┤ │ 0–27 │ size │ ├───────┼───────────┤ │ 28–29 │ padding │ ├───────┼───────────┤ │ 30–31 │ alignment │ └───────┴───────────┘ ``` Currently, `alignmentMask = 0x6000_0000`, i.e. bits 29–30, not 30–31. It overlaps paddingMask (bits 28–29) at bit 29, meaning that alignment and padding unintentionally share a bit. With `alignmentShift = 30`, storing `shift = 2 << 30` places 1 at bit 31, which the mask doesn't cover. Correct value is `0xC000_0000` covers bits 30–31, which matches `alignmentShift = 30` so both `shift = 1` and `shift = 2` round-trip, and it does not overlap with `paddingMask = 0x3000_0000` (bits 28–29). It also mirrors the 64-bit layout (top bits of the word reserved for alignment, just 2 of them instead of 1). - **Scope**: Limited to 32-bit platforms. - **Issues**: rdar://175799967 - **Risk**: Low due to increased test coverage. - **Testing**: Previously crashing on 32-bit platforms sample code is now added to the test suite.
53 lines
1.8 KiB
Swift
53 lines
1.8 KiB
Swift
// RUN: %target-run-simple-swift
|
|
// RUN: %target-run-simple-swift(-O)
|
|
// REQUIRES: executable_test
|
|
// UNSUPPORTED: use_os_stdlib
|
|
// UNSUPPORTED: back_deployment_runtime
|
|
|
|
// Regression test for a 32-bit-only mask-overlap bug in `ComputedArgumentSize`
|
|
// (`stdlib/public/core/KeyPath.swift`).
|
|
|
|
import StdlibUnittest
|
|
|
|
let tests = TestSuite("KeyPath32Bit")
|
|
|
|
struct Inner {
|
|
let base: Int
|
|
subscript(idx: SIMD4<Int32>) -> Int {
|
|
return base + Int(idx[0]) + Int(idx[1]) + Int(idx[2]) + Int(idx[3])
|
|
}
|
|
}
|
|
|
|
struct Outer {
|
|
var inner: Inner
|
|
}
|
|
|
|
tests.test("appended keypath with 16-byte-aligned subscript argument") {
|
|
// Precondition: SIMD4<Int32> must have 16-byte alignment on this target.
|
|
// If a future stdlib change demotes the alignment, this test would stop
|
|
// exercising the bug's codepath — assert loudly instead of silently.
|
|
expectEqual(16, MemoryLayout<SIMD4<Int32>>.alignment)
|
|
expectEqual(16, MemoryLayout<SIMD4<Int32>>.size)
|
|
|
|
let arg = SIMD4<Int32>(1, 2, 3, 4)
|
|
|
|
// The leaf keypath captures a 16-aligned argument.
|
|
let leaf: KeyPath<Inner, Int> = \Inner.[arg]
|
|
|
|
// `appending(path:)` forces the buggy `calculateAppendedKeyPathSize` /
|
|
// `_storeInto` paths that read `.alignment` back from the leaf component's
|
|
// header. Under the buggy mask, the read returns 0; the appended buffer is
|
|
// under-allocated; projection traps inside the stdlib.
|
|
let composed: KeyPath<Outer, Int> = (\Outer.inner).appending(path: leaf)
|
|
|
|
// Normal keypath projection. On a correct stdlib this returns the expected
|
|
// value. On a buggy stdlib it traps before returning, which lit records as
|
|
// a non-zero exit code (test FAIL).
|
|
let observed = Outer(inner: Inner(base: 100))[keyPath: composed]
|
|
|
|
// 100 (base) + 1 + 2 + 3 + 4 = 110.
|
|
expectEqual(110, observed)
|
|
}
|
|
|
|
runAllTests()
|