swiftlang / swift

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

[SR-15083] atexit crashes when program isn't compiled #57409

Open keith opened 3 years ago

keith commented 3 years ago
Previous ID SR-15083
Radar rdar://problem/82178690
Original Reporter @keith
Type Bug
Environment Xcode 12.5.1 (12E507)
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 0 | |Component/s | | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: 2fb980592e70fa6a0d23375733021075

Issue Description:

With this code:

import Foundation
atexit { print("done") }

You get this crash:

% swift /tmp/foo.swift
Please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project and the crash backtrace.
0  swift-frontend           0x0000000106b886e0 llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 52
1  swift-frontend           0x0000000106b87858 llvm::sys::RunSignalHandlers() + 128
2  swift-frontend           0x0000000106b88cb0 SignalHandler(int) + 292
3  libsystem_platform.dylib 0x00000001a2162c44 _sigtramp + 56
4  libsystem_c.dylib        0x00000001a203f5e0 __cxa_finalize_ranges + 424
5  libsystem_c.dylib        0x00000001a203f948 exit + 60
6  libdyld.dylib            0x00000001a2135434 start + 8
zsh: segmentation fault  PATH="/usr/bin:/bin" swift /tmp/foo.swift

When you compile the file and run the produced binary instead, it does not crash:

% swiftc /tmp/foo.swift -o /tmp/foo
% /tmp/foo
done

You get the same behavior on Linux:

# swiftc -version
Swift version 5.4.2 (swift-5.4.2-RELEASE)
Target: x86_64-unknown-linux-gnu

# swift /tmp/foo.swift
JIT session error: Symbols not found: [ atexit ]
Failed to materialize symbols: { (main, { $ss5print_9separator10terminatoryypd_S2StFfA0_, $ss27_finalizeUninitializedArrayySayxGABnlF, $ss5print_9separator10terminatoryypd_S2StFfA1_, main, _swift_FORCE_LOAD_$_swiftGlibc_$_foo, $sSa12_endMutationyyF }) }

# swiftc /tmp/foo.swift -o /tmp/foo
# /tmp/foo
done
CodaFi commented 3 years ago

This could be a consequence of autolinking info not being picked up by the JIT linker. @lhames

lhames commented 3 years ago

Those failure modes are different. On Linux it's failing to resolve atexit and terminating cleanly with an error. On Darwin it's crashing.

I'm not sure why atexit wouldn't be found on Linux – from memory Immediate mode is dlsym'ing to find process symbols and I would have expected all processes to contain atexit. It's a good thing we don't find the process atexit symbol though, because...

On Darwin we are finding the process atexit symbol and calling it registering to register the handler, but that's not what we want: the JIT'd code will have been torn down by the time the containing process runs the atexit handlers.

I think the best solution is to update Swift Immediate mode to use the ORC runtime, and teach the ORC runtime to interpose atexit (it's already interposing __cxa_atexit for C++ destructors – atexit should be even easier). Darwin platform support is already in-tree in LLVM, we just need to add atexit interposition. Linux platform support should land in the LLVM mainline later today or tomorrow (good timing!).

CodaFi commented 3 years ago

The ORC runtime lives in compiler-rt these days, right? Should we start turning on `COMPILER_RT_BUILD_ORC`?

lhames commented 3 years ago

It should build by default if you're building the compiler-rt project, unless you explicitly disable it.

If you're building compiler-rt and the ORC runtime isn't showing up please let me know. (And in that case you probably can explicitly enable it as a workaround).

typesanitizer commented 3 years ago

@swift-ci create