-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Closed
Description
| Previous ID | SR-7526 |
| Radar | None |
| Original Reporter | felix91gr (JIRA User) |
| Type | Bug |
| Status | Resolved |
| Resolution | Done |
Environment
Linux, Elementary OS 0.4 Loki
Ubuntu Upstream: 16.04 LTS
Additional Detail from JIRA
| Votes | 0 |
| Component/s | Foundation |
| Labels | Bug, Linux, RunTimeCrash |
| Assignee | felix91gr (JIRA) |
| Priority | Medium |
md5: aaf24b7256119e57a9c2578dec9efffb
Issue Description:
Hi. Open the `REPL` on linux and try this:
1> import Foundation
2> NSString(string: "/").resolvingSymlinksInPath
3> NSString(string: "/lib/").resolvingSymlinksInPathIt crashes on the first attempt but not the second one. Prying open the implementation on the `corelibs` repo:
public var resolvingSymlinksInPath: String {
var components = pathComponents
guard !components.isEmpty else {
return _swiftObject
}
// TODO: pathComponents keeps final path separator if any. Check that logic.
if components.last == "/" {
components.removeLast()
}
let isAbsolutePath = components.first == "/"
var resolvedPath = components.removeFirst()
for component in components {
switch component {
case "", ".":
break
case ".." where isAbsolutePath:
resolvedPath = resolvedPath._bridgeToObjectiveC().deletingLastPathComponent
default:
resolvedPath = resolvedPath._bridgeToObjectiveC().appendingPathComponent(component)
if let destination = FileManager.default._tryToResolveTrailingSymlinkInPath(resolvedPath) {
resolvedPath = destination
}
}
}
let privatePrefix = "/private"
resolvedPath = resolvedPath._tryToRemovePathPrefix(privatePrefix) ?? resolvedPath
return resolvedPath
}And then running it on the `REPL`:
Welcome to Swift version 4.1 (swift-4.1-RELEASE). Type :help for assistance.
1> import Foundation
2> let source = NSString(string: "/")
source: Foundation.NSString = {
Foundation.NSObject = {}
_cfinfo = {
info = 1920
pad = 0
}
_storage = "/"
}
3> var components = source.pathComponents
components: [String] = 1 value {
[0] = "/"
}
4> components.last
$R0: String? = "/"
5> components.removeLast()
$R1: String = "/"
6> components.first == "/"
$R2: Bool = false
7> components.removeFirst()
Fatal error: Can't remove first element from an empty collection
Current stack trace:
0 libswiftCore.so 0x00007ffff7ce2750 _swift_stdlib_reportFatalError + 171
1 libswiftCore.so 0x00007ffff7a50ad6 <unavailable> + 1366742
2 libswiftCore.so 0x00007ffff7c8b383 <unavailable> + 3703683
3 libswiftCore.so 0x00007ffff7a50ad6 <unavailable> + 1366742
4 libswiftCore.so 0x00007ffff7bbcd80 <unavailable> + 2858368
5 libswiftCore.so 0x00007ffff7a3e000 RangeReplaceableCollection.removeFirst() + 398
Execution interrupted. Enter code to recover and continue.
Enter LLDB commands to investigate (type :help for assistance.)
Process 15909 stopped
* thread #​1, name = 'repl_swift', stop reason = signal SIGILL: illegal instruction operand
frame #​0: 0x00007ffff7bbcd80 libswiftCore.so`function signature specialization <Arg[2] = Dead, Arg[3] = Dead> of Swift._fatalErrorMessage(Swift.StaticString, Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 96
libswiftCore.so`function signature specialization <Arg[2] = Dead, Arg[3] = Dead> of Swift._fatalErrorMessage(Swift.StaticString, Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never:
-> 0x7ffff7bbcd80 <+96>: ud2
0x7ffff7bbcd82: nopw %cs:(%rax,%rax)
libswiftCore.so`function signature specialization <Arg[0] = Owned To Guaranteed and Exploded, Arg[1] = Exploded> of Swift.String._compareDeterministicUnicodeCollation(Swift.String) -> Swift.Int:
0x7ffff7bbcd90 <+0>: pushq %rbp
0x7ffff7bbcd91 <+1>: movq %rsp, %rbp
Target 0: (repl_swift) stopped.
8> Clearly this part is the problem:
if components.last == "/" {
components.removeLast()
}For a path like "/" which has only one character, "resolvingSymlinksInPath" should return "/" or whatever the symlink for it might be (can "/" have symlinks? Anyway...). Therefore the code should look something like this:
if components.last == "/" && components.count > 1 {
components.removeLast()
}