Skip to content

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

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions