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

NSData contentsOf expects files to never shrink and to always report st_size == number of readable bytes

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Resolved
    • Priority: Medium
    • Resolution: Done
    • Component/s: Foundation
    • Labels:
      None

      Description

      There's a number of bugs in NSData's file reading code: [Its code](https://github.com/apple/swift-corelibs-foundation/blob/43ecec27e47099e49aa2e668bdb6b00cb642850c/Foundation/NSData.swift#L457-L466) relies on two things that both are not true:
      1. files don't shrink
      2. `st_size` is equal to the number of readable bytes

      How does this code rely on those untrue conditions?

              var remaining = Int(info.st_size)
              var total = 0
              while remaining > 0 {
                  let amt = read(fd, data.advanced(by: total), remaining)
                  if amt < 0 {
                      break
                  }
                  remaining -= amt
                  total += amt
              }
      

      This will spin in a loop until it has read `remaining` bytes in total which might never happen: For one the file might have shrunk between that `fstat` and the `read` calls and on top of that some pseudo-files in Linux (especially in `/sys`) return a large `st_size` and you can't actually read any bytes. For example on my machine:

      $ ls -la /sys/devices/pnp0/00\:00/uevent
      -rw-r--r-- 1 root root 4096 Oct 15 13:54 /sys/devices/pnp0/00:00/uevent
      $ stat /sys/devices/pnp0/00\:00/uevent
        File: '/sys/devices/pnp0/00:00/uevent'
        Size: 4096      	Blocks: 0          IO Block: 4096   regular file
      Device: 77h/119d	Inode: 2450        Links: 1
      Access: (0644/-rw-r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
      Access: 2018-10-15 14:01:25.211472722 +0000
      Modify: 2018-10-15 14:01:25.211472722 +0000
      Change: 2018-10-15 14:01:25.211472722 +0000
       Birth: -
      

      so the file has `st_size = 4096` but

      $ cat /sys/devices/pnp0/00\:00/uevent | wc -c 
      0
      

      so we can't actually read anything from it... Testing this with `Foundation` shows this problem "nicely"

        1> import Foundation
        2> String(contentsOfFile: "/sys/devices/pnp0/00:00/uevent")
      [... hangs forever ...]
      

        Attachments

          Activity

            People

            • Assignee:
              millenomi Lily Vulcano
              Reporter:
              jw Johannes Weiss
            • Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: