swiftlang / swift

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

[SR-11676] Throwing Optional @objc protocol method segfaults compiler #54085

Open tkrajacic opened 4 years ago

tkrajacic commented 4 years ago
Previous ID SR-11676
Radar rdar://problem/56672140
Original Reporter @tkrajacic
Type Bug

Attachment: Download

Environment Version 11.1 (11A1027) Catalina 10.15 (19A602)
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug, CompilerCrash | |Assignee | None | |Priority | Medium | md5: f43cf0c4761bc1c331095ebf1466908d

Issue Description:

Given

@objc public protocol ImporterInterface: AnyObject {
    @objc optional func importWindowController() throws -> NSWindowController
}

class Muppet: NSObject, ImporterInterface {
    func importWindowController() throws -> NSWindowController { NSWindowController() }
}

This will segfault the compiler:

var controller: NSWindowController?

func applicationDidFinishLaunching(_ aNotification: Notification) {
   let muppet: ImporterInterface = Muppet()
   controller = try! muppet.importWindowController?()
}

where using `importWindowController!()` works and also making the protocol requirement not optional.

Crash output

1.  While emitting IR SIL function "@$sSAySo7NSErrorCSgGSgSo18NSWindowControllerCSgIegyo_AGs5Error_pIegozo_TR".
 for <<debugloc at "<compiler-generated>":0:0>>0  swift                    0x000000010b1e7eb3 PrintStackTraceSignalHandler(void*) + 51
1  swift                    0x000000010b1e7686 SignalHandler(int) + 358
2  libsystem_platform.dylib 0x00007fff651b3b1d _sigtramp + 29
3  libsystem_malloc.dylib   0x00007fff65171cc6 tiny_malloc_should_clear + 272
4  swift                    0x0000000106ecb563 swift::irgen::addNativeArgument(swift::irgen::IRGenFunction&, swift::irgen::Explosion&, swift::SILParameterInfo, swift::irgen::Explosion&, bool) + 851
5  swift                    0x0000000106ecfd0e swift::irgen::CallEmission::setArgs(swift::irgen::Explosion&, bool, swift::irgen::WitnessMetadata*) + 846
6  swift                    0x0000000107095a72 (anonymous namespace)::IRGenSILFunction::visitFullApplySite(swift::FullApplySite) + 2050
7  swift                    0x000000010707612a swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 9866
8  swift                    0x0000000106f25517 swift::irgen::IRGenerator::emitLazyDefinitions() + 9303
9  swift                    0x0000000107052f20 performIRGeneration(swift::IRGenOptions&, swift::ModuleDecl*, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::StringRef, swift::PrimarySpecificPaths const&, llvm::LLVMContext&, swift::SourceFile*, llvm::GlobalVariable**) + 1344
10 swift                    0x0000000106e3f5aa performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 36682
11 swift                    0x0000000106e32e54 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 6820
12 swift                    0x0000000106dc03c3 main + 1219
13 libdyld.dylib            0x00007fff64fae405 start + 1
error: Segmentation fault: 11 (in target 'OptionalThrowingSegfault' from project 'OptionalThrowingSegfault')

A sample project for your experimentation pleasure is attached

belkadan commented 4 years ago

@swift-ci create

belkadan commented 4 years ago

With asserts:

Assertion failed: (blockTy->getNumParameters() == funcTy->getNumParameters() && "block and function types don't match"), function buildBlockToFuncThunkBody, file /Volumes/Data/swift-public/swift/lib/SILGen/SILGenBridging.cpp, line 813.
Stack dump:
0.  Program arguments: /Volumes/Data/swift-public/build/ninja/swift-macosx-x86_64/bin/swift -frontend -c -primary-file - -target x86_64-apple-darwin18.7.0 -enable-objc-interop -sdk /Volumes/Data/Applications/Xcode11.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.Internal.sdk -color-diagnostics -module-name main -o /var/folders/_d/dmrgv26d3bs6lkrks9z825_w0000gn/T/--07983d.o 
1.  Swift version 5.1-dev (LLVM af1f73e9e9, Swift 886c0b0407)
2.  While emitting SIL for 'applicationDidFinishLaunching(_:)' (at <stdin>:14:1)
3.  While silgen emitFunction SIL function "@$s4main29applicationDidFinishLaunchingyy10Foundation12NotificationVF".
 for 'applicationDidFinishLaunching(_:)' (at <stdin>:14:1)

which makes sense if we're modeling this as a closure value, because "closures don't throw through parameters".

theblixguy commented 4 years ago

Reproducer that doesn't depend on AppKit:

import Foundation

@objc public class Foo: NSObject {}

@objc public protocol Bar: AnyObject {
  @objc optional func getFoo() throws -> Foo
}

class ImplementsBar: NSObject, Bar {
  func getFoo() throws -> Foo { Foo() }
}

func crash() {
  let bar: Bar = ImplementsBar()
  let _ = try! bar.getFoo?()
}