swiftlang / swift

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

Runtime crash "outlined init with take of any ..." #61403

Open plamenterziev opened 2 years ago

plamenterziev commented 2 years ago

Describe the bug Crash in Release mode or if Optimization Level of Swift Compiler - Code Generation is Optimize for Speed [-O]. It works as expected in Debug mode.

Steps To Reproduce

  1. Paste the following into a .swift file and run it:

    
    protocol Delegate<T> {
    associatedtype T
    
    func f(t: T)
    }

class ConcreteClass: Delegate { func f(t: Int) { } }

class A {

private let delegate: any Delegate<T>

init(delegate: any Delegate<T>) {
    self.delegate = delegate
}

}

let a = A(delegate: ConcreteClass())


2. It crashes with the following:

0 0x0000000100003b49 in outlined init with take of any Delegate<Self.Delegate.T == Int> ()

1 0x0000000100003ac4 in specialized A.init(delegate:) [inlined] at /Users/plamen/Projects/Tests/TestCrash2/TestCrash2/main.swift:25

2 0x0000000100003ab7 in specialized A.__allocating_init(delegate:) [inlined] at /Users/plamen/Projects/Tests/TestCrash2/TestCrash2/main.swift:24

3 0x0000000100003a96 in main at /Users/plamen/Projects/Tests/TestCrash2/TestCrash2/main.swift:29

4 0x000000010001952e in start ()


**Expected behavior**
The code runs fine without any crashes when is Optimised for speed

**Screenshots**
[Attached screenshot with the crash] https://i.stack.imgur.com/SgVUk.png

**Environment (please fill out the following information)**
 - OS: macOS 12.5
 - Xcode Version: 14.0.1
Jumhyn commented 2 years ago

I'm able to reproduce as well:

% swiftc --version
swift-driver version: 1.62.8 Apple Swift version 5.7 (swiftlang-5.7.0.127.4 clang-1400.0.29.50)
Target: x86_64-apple-macosx12.0
Process 98546 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0xfffffffffffffff8)
    frame #0: 0x0000000100003a69 test`outlined init with take of any test.Delegate<Self.test.Delegate.T == Swift.Int> + 25
test`outlined init with take of any test.Delegate<Self.test.Delegate.T == Swift.Int>:
->  0x100003a69 <+25>: movq   -0x8(%rax), %rcx
    0x100003a6d <+29>: movq   %rbx, %rdi
    0x100003a70 <+32>: movq   %r14, %rsi
    0x100003a73 <+35>: movq   %rax, %rdx
Target 0: (test) stopped.
(lldb) di -f
test`outlined init with take of any test.Delegate<Self.test.Delegate.T == Swift.Int>:
    0x100003a50 <+0>:  pushq  %rbp
    0x100003a51 <+1>:  movq   %rsp, %rbp
    0x100003a54 <+4>:  pushq  %r14
    0x100003a56 <+6>:  pushq  %rbx
    0x100003a57 <+7>:  movq   %rsi, %rbx
    0x100003a5a <+10>: movq   %rdi, %r14
    0x100003a5d <+13>: leaq   0x46a4(%rip), %rdi        ; demangling cache variable for type metadata for any test.Delegate<Self.test.Delegate.T == Swift.Int>
    0x100003a64 <+20>: callq  0x100003a20               ; __swift_instantiateConcreteTypeFromMangledName
->  0x100003a69 <+25>: movq   -0x8(%rax), %rcx
    0x100003a6d <+29>: movq   %rbx, %rdi
    0x100003a70 <+32>: movq   %r14, %rsi
    0x100003a73 <+35>: movq   %rax, %rdx
    0x100003a76 <+38>: callq  *0x20(%rcx)
    0x100003a79 <+41>: movq   %rbx, %rax
    0x100003a7c <+44>: popq   %rbx
    0x100003a7d <+45>: popq   %r14
    0x100003a7f <+47>: popq   %rbp
    0x100003a80 <+48>: retq   
    0x100003a81 <+49>: nopw   %cs:(%rax,%rax)
    0x100003a8b <+59>: nopl   (%rax,%rax)

Looks like __swift_instantiateConcreteTypeFromMangledName is failing?

xedin commented 2 years ago

/cc @slavapestov

slavapestov commented 2 years ago

This looks like a backward deployment scenario, so the Swift runtime cannot demangle a constrained existential type. We shouldn't be using the mangling in this case.

AnthonyLatsis commented 2 years ago

Cannot reproduce on main.

slavapestov commented 2 years ago

@AnthonyLatsis You have to use an old OS and link against the OS runtime not the just-built runtime.

AnthonyLatsis commented 2 years ago

I see. But why is the demangler not hit with optimizations disabled? The inlined init seems like the only considerable difference.

Jumhyn commented 2 years ago

Yeah, maybe it's been fixed on main but I was not compiling with any back-deployment setup, just the vanilla swiftc version depicted in my comment.

hborla commented 2 years ago

Running on any OS that does not have the new runtime support for constrained existential types is a backward deployment scenario.

You have to use an old OS

Note that you don't necessarily have to be using an old OS - using the current macOS 12 is also considered "back deployment" here.

plamenterziev commented 2 years ago

Is there any easy temporary workaround except building without optimization? Even if need some more boilerplate code.

slavapestov commented 2 years ago

Try changing the stored property to have an unconstrained existential type, and add a computed property that does a downcast:

private let _delegate: any Delegate

private var delegate: any Delegate<T> {
  return _delegate as! any Delegate<T>
}
plamenterziev commented 2 years ago

@slavapestov - the above requires to have min deployment target of macOS 13.0 or iOS 16.0 in order to compile which is not an option in my case. However if I disable the optimizations only for the init method and seems to work fine:

@_optimize(none)
init(delegate: any Delegate<T>) {
    self.delegate = delegate
}

It is not the best I guess but at least does not require to disable the optimizations for the whole app.

tr1ckyf0x commented 2 years ago

Looks like it still reproduces in Xcode 14.1 (Swift 5.7.1)

hborla commented 1 year ago

I believe this was fixed by https://github.com/apple/swift/pull/61646

tr1ckyf0x commented 1 year ago

Still reproduces on Xcode 14.2 RC (14C18). iOS 15.7. Project to test: https://github.com/tr1ckyf0x/wakeonlan-ios branch feature/hostList_refactoring

AnthonyLatsis commented 1 year ago

It is fixed on the main branch (5.8), but most likely will not make it into a 5.7 patch release; not to be expected anyway.

tr1ckyf0x commented 1 year ago

@AnthonyLatsis Could you, please, tell, when to expect 5.8?

AnthonyLatsis commented 1 year ago

You can get a rough idea from looking at the dates of previous releases in this repo. I can only guess myself. I trust you understand the odds of someone disclosing the schedule are next to zero, even if known.

nolanw commented 1 year ago

The same change appears on the release/5.7 branch as 1145332c05a1b0e2914aa4dcf9345933a83182fd, so maybe it will appear in a subsequent 5.7 patch release? Or perhaps it did not fix the issue, if Xcode 14.2 RC includes that change.

AnthonyLatsis commented 1 year ago

The same change appears on the release/5.7 branch as https://github.com/apple/swift/commit/1145332c05a1b0e2914aa4dcf9345933a83182fd, so maybe it will appear in a subsequent 5.7 patch release

Oh, sounds like it should then.

if Xcode 14.2 RC includes that change

Handing this question over to @hborla

hborla commented 1 year ago

I believe the fix is included in Xcode 14.2 RC (14C18). @aschwaighofer is this test case different from the one you fixed?

ivan-gaydamakin commented 1 year ago

tested on the released xcode 14.2 simulator ios 15.5 no crash

gspiers commented 1 year ago

I can also confirm no crash on iOS 15.5 Simulator using Xcode 14.2 (14C18).

But I added the following code and have a warning in the console. Not sure if that's expected or not:

...
let a = A(delegate: ConcreteClass())
dump(a)

warning: the Swift runtime was unable to demangle the type of field 'delegate'. the mangled type name is ' \323,\373\377xXj': TypeDecoder.h:1282: Node kind 194 " \323,\373\377xXj" - unexpected kind. this field will show up as an empty tuple in Mirrors