Uploaded image for project: 'Swift'
  1. Swift
  2. SR-12079

libdispatch SEGFAULT when using Foundation's FileHandle readabilityHandler on lots of pipes

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Open
    • Priority: Medium
    • Resolution: Unresolved
    • Component/s: Foundation
    • Labels:

      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 #2, name = 'File', stop reason = signal SIGSEGV: invalid address (fault address: 0xffff800013ff70b7)
        * frame #0: 0x00007ffff60b516a libdispatch.so`_dispatch_event_loop_drain + 1242
          frame #1: 0x00007ffff60a8ea2 libdispatch.so`_dispatch_mgr_invoke + 146
          frame #2: 0x00007ffff60a8dee libdispatch.so`_dispatch_mgr_thread + 126
          frame #3: 0x00007ffff60ac993 libdispatch.so`_dispatch_worker_thread + 515
          frame #4: 0x00007ffff6a826db libpthread.so.0`start_thread + 219
          frame #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 Raul Ignatus 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()
      }
      

        Attachments

          Activity

            People

            Assignee:
            Unassigned Unassigned
            Reporter:
            jw Johannes Weiss
            Votes:
            1 Vote for this issue
            Watchers:
            3 Start watching this issue

              Dates

              Created:
              Updated: