Skip to content

Commit 4683dfa

Browse files
TSCBasic: handle empty paths in WindowsPath(validatingRelativePath:)
We may not invoke `fileSystemRepresentation` on an empty string as per the API contract for the function. Add guards to prevent that. In order to make this behaviour consistency more visible, reorder the constructors to collate the absolute path and relative path handling. Co-authored-by: Tristan Labelle <[email protected]>
1 parent d8681ff commit 4683dfa

File tree

1 file changed

+26
-25
lines changed

1 file changed

+26
-25
lines changed

Sources/TSCBasic/Path.swift

+26-25
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,15 @@ private struct WindowsPath: Path, Sendable {
527527
self.string = string
528528
}
529529

530-
init(normalizingAbsolutePath path: String) {
531-
let normalized: UnsafePointer<Int8> = path.fileSystemRepresentation
532-
defer { normalized.deallocate() }
530+
private static func repr(_ path: String) -> String {
531+
guard !path.isEmpty else { return "" }
532+
let representation: UnsafePointer<Int8> = path.fileSystemRepresentation
533+
defer { representation.deallocate() }
534+
return String(cString: representation)
535+
}
533536

534-
self.init(string: String(cString: normalized)
535-
.withCString(encodedAs: UTF16.self) { pwszPath in
537+
init(normalizingAbsolutePath path: String) {
538+
self.init(string: Self.repr(path).withCString(encodedAs: UTF16.self) { pwszPath in
536539
var canonical: PWSTR!
537540
_ = PathAllocCanonicalize(pwszPath,
538541
ULONG(PATHCCH_ALLOW_LONG_PATHS.rawValue),
@@ -541,6 +544,14 @@ private struct WindowsPath: Path, Sendable {
541544
})
542545
}
543546

547+
init(validatingAbsolutePath path: String) throws {
548+
let realpath = Self.repr(path)
549+
if !Self.isAbsolutePath(realpath) {
550+
throw PathValidationError.invalidAbsolutePath(path)
551+
}
552+
self.init(normalizingAbsolutePath: path)
553+
}
554+
544555
init(normalizingRelativePath path: String) {
545556
if path.isEmpty || path == "." {
546557
self.init(string: ".")
@@ -553,28 +564,18 @@ private struct WindowsPath: Path, Sendable {
553564
}
554565
}
555566

556-
init(validatingAbsolutePath path: String) throws {
557-
let fsr: UnsafePointer<Int8> = path.fileSystemRepresentation
558-
defer { fsr.deallocate() }
559-
560-
let realpath = String(cString: fsr)
561-
if !Self.isAbsolutePath(realpath) {
562-
throw PathValidationError.invalidAbsolutePath(path)
563-
}
564-
self.init(normalizingAbsolutePath: path)
565-
}
566-
567567
init(validatingRelativePath path: String) throws {
568-
let fsr: UnsafePointer<Int8> = path.fileSystemRepresentation
569-
defer { fsr.deallocate() }
570-
571-
let realpath: String = String(cString: fsr)
572-
// Treat a relative path as an invalid relative path...
573-
if Self.isAbsolutePath(realpath) ||
574-
realpath.first == "~" || realpath.first == "\\" {
575-
throw PathValidationError.invalidRelativePath(path)
568+
if path.isEmpty || path == "." {
569+
self.init(string: ".")
570+
} else {
571+
let realpath: String = Self.repr(path)
572+
// Treat a relative path as an invalid relative path...
573+
if Self.isAbsolutePath(realpath) ||
574+
realpath.first == "~" || realpath.first == "\\" {
575+
throw PathValidationError.invalidRelativePath(path)
576+
}
577+
self.init(normalizingRelativePath: path)
576578
}
577-
self.init(normalizingRelativePath: path)
578579
}
579580

580581
func suffix(withDot: Bool) -> String? {

0 commit comments

Comments
 (0)