swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.66k stars 10.38k forks source link

IRGen createTypeMetadataAccessFunction crash #67861

Open aetherealtech opened 1 year ago

aetherealtech commented 1 year ago

Description

The following code causes the compiler to crash:

@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
public struct MakeExplode<Element, Source: Sequence> where Source.Element == () async -> Element {}

Steps to reproduce Add the above code to a file in a Swift package and attempt to compile. The essential part seems to be the constraint to an async function whose return type is another type parameter (removing async or replacing Element with a specific type like Int avoids the crash).

Expected behavior The code should either compile or trigger a compile error, but not a crash.

Environment

Stack trace:

SwiftStackTrace.txt

Kyle-Ye commented 1 year ago

Using Xcode 15 beta 6 can also reproduce this bug. But it looks it will only occur when building for iOS device.

If we build it against iOS simulator or macOS, it will not crash.

Also if we add platform info in Package.swift (eg. platforms: [.iOS(.v16)],), it will not crash.

When debugging when the latest release/5.9 toolchain. It will be reproducible no matter we give it the iOS/iOS simulator/macOS compile arguments.

The crash is due to the following assert (type->hasTypeParameter() is true)

IRGenModule::getAddrOfTypeMetadataAccessFunction(CanType type,
                                              ForDefinition_t forDefinition) {
  assert(!type->hasArchetype() && !type->hasTypeParameter());
  ...
}
Kyle-Ye commented 1 year ago

Narrow down this issue to the implementation of mangledNameIsUnknownToDeployTarget

The open source Swift crash:

image image

The Xcode's private Swift crash: SwiftStackTrace.txt

And here is the test result when we set different platform version for Package.swift (Eventually will be -target arm64-apple-iosYY)

Test Package(~2KB) 👇 67861.zip

No iOS platform version set explicitly:

Checking the flag, it was implicit inferred as iOS12 for swift-tools-version: 5.9

❌ Xcode + Device (compiler crash on other place) ✅ Xcode + Simulator ❌ SwiftToolchain + Device (remove stack-check flag) ❌ SwiftToolchain + Simulator

iOS 13: ❌ Xcode + Device (compiler crash on other place) ✅ Xcode + Simulator ❌ SwiftToolchain + Device (remove stack-check flag) ❌ SwiftToolchain + Simulator

iOS 14: ✅ Xcode + Device ✅ Xcode + Simulator ❌ SwiftToolchain + Device (remove stack-check flag) ❌ SwiftToolchain + Simulator

iOS 15+: ✅ Xcode + Device ✅ Xcode + Simulator ✅ SwiftToolchain + Device (remove stack-check flag) ✅ SwiftToolchain + Simulator

The tested Device and Simulator's OS version are all iOS 17.

Xcode means Xcode 15 beta 6

SwiftToolchain means the latest Open-Source Swift 5.9(1ce02ad6eed0033901ba330b574dd326a8310f6f) (With a cherry-pick of ivfsstatcache support patch on llvm branch) ✅ means it compiled successfully ❌ means it crashed as the screenshot

The SwiftToolchain result is somehow expected. We will get a result of true when we evaluate mangledNameIsUnknownToDeployTarget for the second type if the target version is smaller than iOS 15.

And then we will eventually hit the assert in getAddrOfTypeMetadataAccessFunction.

<= iOS 14
runtimeCompatVersion = 5.3 and minimumSupportedRuntimeVersion = 5.5

>= iOS 15
runtimeCompatVersion = 5.5 and minimumSupportedRuntimeVersion = 5.5
// If the minimum deployment target's runtime demangler wouldn't understand
// this mangled name, then fall back to generating a "mangled name" with a
// symbolic reference with a callback function.
if (mangledNameIsUnknownToDeployTarget(IGM, type)) {
  return getTypeRefByFunction(IGM, sig, type);
}

bool swift::irgen::mangledNameIsUnknownToDeployTarget(IRGenModule &IGM,
                                                      CanType type) {
  if (auto runtimeCompatVersion = getSwiftRuntimeCompatibilityVersionForTarget(
          IGM.Context.LangOpts.Target)) {
    if (auto minimumSupportedRuntimeVersion =
            getRuntimeVersionThatSupportsDemanglingType(type)) {
      if (*runtimeCompatVersion < *minimumSupportedRuntimeVersion) {
        return true;
      }
    }
  }
  return false;
}

The OP's crash is probably hit the case of

Kyle-Ye commented 1 year ago

We may fix the issue on the open-source Swift side. But it probably will not solve the original issue.

And I do hope someone at Apple who is familiar with Xcode's private Swift fork can help take a look at this.

Tell us why Xcode's Swift will not crash for "iOS 14" test case. And why it will crash for iOS 13- iOS device platform.

Kyle-Ye commented 1 year ago

cc @AnthonyLatsis