Unexpected pointer in the middle of a swift enum type metadata

Hi,

I am fighting a strange issue in unit tests of my iOS application. I use Apple Swift version 5.3.2 (swiftlang-1200.0.45 clang-1200.0.32.28) and unfortunately I am unable to quickly verify the issue against latest Swift compiler. Sorry, I will try to verify the issue on the latest Swift version and I will try to pinpoint the minimal scenario to reproduce it, but before that I have a question regarding Swift ABI – just to make sure I took the right direction. Can anyone verify the technical details I shared right below?

My unit tests crash when I pass an Equatable enum into XCTAssertEqual. XCTAssertEqual tries to read an argument metadata, but this causes the stack pointer to be broken, which in turn causes EXC_BAD_INSTRUCTION on the nearest callq instruction.

I see an anomaly in the enum metadata:

  • a value witness table pointer comes first,
  • then some unexpected pointer,
  • then a kind,
  • finally a nominal type descriptor.

I am not sure if I haven't missed anything reading ABI docs, but this unexpected pointer seems unusual. As far as I know kind value should appear immediately after the value witness table pointer. XCTAssertEqual tries to get a value witness table at offset -0x8 from the type metadata, but instead of value witness table – it gets a pointer to something different.
E26pBNlX0AQy7Gs

My question is: is it correct for a full type metadata to have value witness table separated from kind value by any additional data? Please help :pray:

Looking at the runtime code (see TargetEnumMetadata and super classes) and IR generated for a toy example, that seems like a codegen bug.

1 Like

Thank you for your assistance! I managed to reproduce the issue in a sample project. I pushed it to github repo. Broken metadata is clearly visible in compiled main executable.

$ nm -n LinkingDemo | grep OMf -A 1
000000010000c0d8 s _$s6LibAAA8EnumAAA0OMf
000000010000c0e0 S _$s6LibAAA8EnumAAA0ON
--
000000010000c160 s _$s6LibAAA8EnumAAA1OMf
000000010000c168 S _$s6LibAAA8EnumAAA1ON
--
000000010000c1e8 s _$s6LibAAA8EnumAAA2OMf
000000010000c1f0 s _$s6LibBBB8EnumBBB0OWV  👈 HERE
--
000000010000c2e0 s _$s6LibBBB8EnumBBB0OMf
000000010000c2e8 S _$s6LibBBB8EnumBBB0ON
--
000000010000c2f8 s _$s6LibAAA8EnumAAA3OMf
000000010000c300 s _$s6LibBBB8EnumBBB1OWV  👈 HERE
--
000000010000c3f0 s _$s6LibBBB8EnumBBB1OMf
000000010000c3f8 S _$s6LibBBB8EnumBBB1ON
--
000000010000c408 s _$s6LibAAA8EnumAAA4OMf
000000010000c410 s _$s6LibBBB8EnumBBB2OWV  👈 HERE
--
000000010000c500 s _$s6LibBBB8EnumBBB2OMf
000000010000c508 S _$s6LibBBB8EnumBBB2ON
--

I was not able to reproduce the issue with SPM project setup. The issue disappears after linking all the libraries explicitly in the executable target settings. I am not sure if this is a linker bug or just undefined behavior. :sweat_smile: