swiftlang / swift-foundation

The Foundation project
Apache License 2.0
2.4k stars 159 forks source link

FileManager.default.currentDirectoryPath can crash if the working directory is deleted #946

Open jakepetroules opened 1 month ago

jakepetroules commented 1 month ago

Consider the following program:

import Foundation

print(FileManager.default.currentDirectoryPath)

let path = NSTemporaryDirectory() + "/" + UUID().uuidString
try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true)

_ = FileManager.default.changeCurrentDirectoryPath(path)

print(FileManager.default.currentDirectoryPath)

try FileManager.default.removeItem(atPath: path)

print(FileManager.default.currentDirectoryPath)

This will crash:

💣 Program crashed: System trap at 0x0000ffffa961ad08

Thread 0 "test" crashed:

0 0x0000ffffa961ad08 FileManager.currentDirectoryPath.getter + 88 in libFoundationEssentials.so
1 test_main + 1007 in test at /home/debian/Downloads/test/Sources/main.swift:17:27

    15│ try FileManager.default.removeItem(atPath: path)
    16│ 
    17│ print(FileManager.default.currentDirectoryPath)                                                      
      │                           ▲

2 0x0000ffffa8027740 <unknown> in libc.so.6
3 0x0000ffffa8027818 <unknown> in libc.so.6

Backtrace took 0.01s

...because currentDirectoryPath returns a non-optional String, and force unwraps the underlying optional string property, which returns nil if the getcwd function returns nil due to an error (one of these error conditions is that the current directory has been deleted, which can easily happen at runtime).

Since we can't change the return type for source/bincompat, we should do something a bit more principled than crashing. Can we instead return an empty string in that case?

kylesluder commented 1 month ago

How about returning "."?

Is there a property with better semantics that currentDirectoryPath can be deprecated in favor of?

jessezamora commented 1 month ago

Interesting, I just ran into this issue myself. I'm installing a Swift application from an RPM file, and that can remove the underlying directory for the app due to how installation is done. This causes the crash to happen sometimes, which is very interesting:

FoundationEssentials/SwiftFileManager.swift:289: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Current stack trace:
0    libswiftCore.so                    0x00000000b61d8008 _swift_stdlib_reportFatalErrorInFile + 108
1    libswiftCore.so                    0x00000000b5db25d8 <unavailable> + 1431000

Unfortunately I didn't get the full stack trace, but you get the idea.