Summary
After upgrading swift-log from 1.11.0 to 1.12.0, a Linux Swift server
crash-loops with SIGSEGV (exit code 139) every time a code path that
emits a log line through a multiplexed handler chain executes. The
same binary on macOS does not crash. Pinning swift-log back to
1.11.x stops the crash entirely.
Crash signature (identical across hundreds of occurrences)
*** Program crashed: Bad pointer dereference at 0x0000000000000068 ***
Thread N "...default-qos" crashed:
0 swift_retain + 47
1 initializeWithCopy for LogEvent + 159
2 outlined init with copy of LogEvent + 28
3 closure #1 in <user closure that wraps an HTTP call> + 2095
4 ...async thunks...
N Tracer.withSpan<A>(...)
N+1 user code that called the logger
Register dump at the fault:
rax 0x0000000000000000
rcx 0x0000000000000068 // offset being dereferenced
rdi 0x0000000200000000 // pointer passed to swift_retain
Environment
- swift-log: 1.12.0 (regression vs 1.11.0)
- swift-otel: 1.1.0 (depends on swift-log >= 1.12.0)
- swift-distributed-tracing: 1.x
- Swift toolchain: 6.x release build
- OS: Ubuntu 24.04 LTS, x86_64
- macOS Apple Silicon: same source, no crash
Setup
Logging is bootstrapped with a MultiplexLogHandler chain that
contains an intercepting wrapper around a stdout handler, plus the
OTel.makeLoggingBackend factory. Any Logger.log(level:_:metadata:)
call from a function that wraps the body in withSpan reliably
triggers the crash within ~2 minutes of process startup.
Suspect
PR #425 in 1.12.0 added error: (any Error)? to LogEvent. The new
field is an existential (~5-word container holding a class reference
in one of its slots). rdi = 0x0000000200000000 looks like
uninitialized memory decoded as Some(class_ref) — high bits set,
low bits zero. swift_retain then dereferences the refcount field
at offset 0x68 from NULL, faulting at address 0x68.
Possible underlying causes (speculation):
- Compiler bug in
Optional<any Error> spare-bit / tag-byte encoding
on Linux x86_64
- @inlinable
Logger.log inlining the 1.11.0 LogEvent layout into
a caller that links 1.12.0 swift-log
- A field-init order issue where the legacy 7-arg
LogEvent.init
delegates to the new 8-arg init and the error slot is observed
uninitialized under value-witness copy
What we tried
| Combination |
Result |
| swift-log 1.11.0 + swift-otel 1.0.5 |
stable, no restarts in 10+ min |
| swift-log 1.12.0 + swift-otel 1.1.0 |
crashes ~every 2 min on every alloc |
| swift-log 1.12.0 + swift-otel 1.0.5 (downgrade attempt) |
still crashes |
The third row isolates swift-log 1.12.0 as the regression — the
swift-otel version doesn't matter.
Expected behavior
LogEvent constructed via the legacy 7-arg init (which delegates
to the new 8-arg init with error: nil) should be safe to copy
through a MultiplexLogHandler chain without retaining a bogus
existential.
Happy to provide additional diagnostic output (debug-symbolicated
trace, minimal reproducer) if helpful.
Summary
After upgrading swift-log from 1.11.0 to 1.12.0, a Linux Swift server
crash-loops with SIGSEGV (exit code 139) every time a code path that
emits a log line through a multiplexed handler chain executes. The
same binary on macOS does not crash. Pinning swift-log back to
1.11.x stops the crash entirely.
Crash signature (identical across hundreds of occurrences)
Register dump at the fault:
Environment
Setup
Logging is bootstrapped with a
MultiplexLogHandlerchain thatcontains an intercepting wrapper around a stdout handler, plus the
OTel.makeLoggingBackendfactory. AnyLogger.log(level:_:metadata:)call from a function that wraps the body in
withSpanreliablytriggers the crash within ~2 minutes of process startup.
Suspect
PR #425 in 1.12.0 added
error: (any Error)?toLogEvent. The newfield is an existential (~5-word container holding a class reference
in one of its slots).
rdi = 0x0000000200000000looks likeuninitialized memory decoded as
Some(class_ref)— high bits set,low bits zero.
swift_retainthen dereferences the refcount fieldat offset
0x68from NULL, faulting at address0x68.Possible underlying causes (speculation):
Optional<any Error>spare-bit / tag-byte encodingon Linux x86_64
Logger.loginlining the 1.11.0 LogEvent layout intoa caller that links 1.12.0 swift-log
LogEvent.initdelegates to the new 8-arg init and the
errorslot is observeduninitialized under value-witness copy
What we tried
The third row isolates swift-log 1.12.0 as the regression — the
swift-otel version doesn't matter.
Expected behavior
LogEventconstructed via the legacy 7-arg init (which delegatesto the new 8-arg init with
error: nil) should be safe to copythrough a
MultiplexLogHandlerchain without retaining a bogusexistential.
Happy to provide additional diagnostic output (debug-symbolicated
trace, minimal reproducer) if helpful.