Skip to content

[SR-12079] libdispatch SEGFAULT when using Foundation's FileHandle readabilityHandler on lots of pipes #3276

@weissi

Description

@weissi
Previous ID SR-12079
Radar rdar://problem/58997211
Original Reporter @weissi
Type Bug

Attachment: Download

Additional Detail from JIRA
Votes 1
Component/s Foundation
Labels Bug, Crash
Assignee None
Priority Medium

md5: 507eb4e7b2c1f88b3f62677d14f5efd3

Issue Description:

The following program always opens 1000 Pipe s (sequentially), then sets up a readabilityHandler for each of the pipes, then closes the other end of the pipe, and waits for the readabilityHandlers to send an empty Data meaning EOF.

This works for a while until we get a SEGFAULT in dispatch here

(lldb) run
......................Process 24 stopped
* thread #​2, name = 'File', stop reason = signal SIGSEGV: invalid address (fault address: 0xffff800013ff70b7)
    frame #​0: 0x00007ffff60b516a libdispatch.so`_dispatch_event_loop_drain + 1242
libdispatch.so`_dispatch_event_loop_drain:
->  0x7ffff60b516a <+1242>: movl   0x8(%rcx), %edx
    0x7ffff60b516d <+1245>: cmpl   $0x7fffffff, %edx         ; imm = 0x7FFFFFFF
    0x7ffff60b5173 <+1251>: je     0x7ffff60b5187            ; <+1271>
    0x7ffff60b5175 <+1253>: movl   $0x2, %edx
Target 0: (File) stopped.

[...]

* thread #&#8203;2, name = 'File', stop reason = signal SIGSEGV: invalid address (fault address: 0xffff800013ff70b7)
  * frame #&#8203;0: 0x00007ffff60b516a libdispatch.so`_dispatch_event_loop_drain + 1242
    frame #&#8203;1: 0x00007ffff60a8ea2 libdispatch.so`_dispatch_mgr_invoke + 146
    frame #&#8203;2: 0x00007ffff60a8dee libdispatch.so`_dispatch_mgr_thread + 126
    frame #&#8203;3: 0x00007ffff60ac993 libdispatch.so`_dispatch_worker_thread + 515
    frame #&#8203;4: 0x00007ffff6a826db libpthread.so.0`start_thread + 219
    frame #&#8203;5: 0x00007ffff5ba388f libc.so.6`clone + 63

Please note that the fault address is 0xffff800013ff70b7 and given that the pointer value ends in 7 and we're looking at a 32 bit load, this looks like a nice memory corruption to because that's an unaligned 32 bit load which is unlikely to be how the code is meant to work.

Credit to rignatus (JIRA User) for finding the initial issue that led to us debugging this together.

Repro:

On Linux

swiftc -O File.swift && ./File

With lldb in Docker (runnable from macOS)

# assuming File is in .
docker run --privileged --rm -v "$PWD:$PWD" -w "$PWD" -it norionomura/swift:nightly  bash -c 'swiftc -O File.swift && lldb --batch -o run -k "image list" -k "register read" -k "bt all" -k "exit 134" ./File'

program reproduced here

import Foundation

for i in 1..<1_000_000 {
    fputs(".", stdout)
    fflush(stdout)
    if i % 100 == 0 {
        fputs("\n", stdout)
    }
    let g = DispatchGroup()
    let ps = (0..<1000).map { _ in Pipe() }
    ps.forEach { p in
        var numberOfCalls = 0
        g.enter()
        p.fileHandleForReading.readabilityHandler = { handle in
            if handle.availableData.isEmpty {
                numberOfCalls += 1
                precondition(numberOfCalls == 1)
                g.leave()
            }
        }
    }
    ps.forEach { p in
        try! p.fileHandleForWriting.close()
    }
    g.wait()
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions