Skip to content

Possible regression in 1.12.0: SIGSEGV during LogEvent value copy on Linux x86_64 #456

@cgsergey

Description

@cgsergey

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions