swiftlang / swift-corelibs-foundation

The Foundation Project, providing core utilities, internationalization, and OS independence
swift.org
Apache License 2.0
5.29k stars 1.13k forks source link

[SR-11605] NSRangeException when obtaining substring from NSPathStore2/NSBigMutableString under macOS 10.14 #3384

Open swift-ci opened 5 years ago

swift-ci commented 5 years ago
Previous ID SR-11605
Radar rdar://problem/56226571
Original Reporter 1024jp (JIRA User)
Type Bug
Environment Apple Swift version 5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7) Target: x86_64-apple-darwin18.7.0 macOS: 10.14.6 (18G95) Xcode: 11.1 (11A1027)
Additional Detail from JIRA | | | |------------------|-----------------| |Votes | 1 | |Component/s | Foundation | |Labels | Bug | |Assignee | @Catfish-Man | |Priority | Medium | md5: aa68f9cc8ccaab9b757ab0270295576d

Issue Description:

Description

An NSRangeException arises and the application crashes when getting substring with a Swift range via subscript brackets from a specific Foundation's inner string class instance.

This issue occurs only when a compile optimization is enabled and under macOS 10.14. When runs the code without optimization or under macOS 10.15, it works correctly (I haven't tried macOS 10.13 or other environments yet).

Furthermore, if the same code is written in Objective-C it works even under the same conditions. So, something would go wrong with the range translation between Swift \<-> ObjC.

Conditions

The conditions I found so far to reproduce this phenomenon are:

In addition, the same code works when I used Xcode 10.3 with Swift 5. But I'm not sure from when (from Xcode 11, 11.1, or from Swift 5.1?) it has been broken.

If not satisfy one of those conditions, the code works as excepted without throwing any exception.

Expected Result

Succeed in obtaining substring without any exception.

Steps to Reproduce the Issue

The followings are sample codes to reproduce those issues.

Run it with -O option under macOS 10.14.x.

$swift -O foo.swift

It will crash due to an NSRangeException.

Sample code for NSPathStore2

import Foundation

// create NSPathStore2 instance
let string = NSString(string: "foo").appendingPathComponent("bar")
print((string as NSString).className)  // -> NSPathStore2

let range = string.range(of: "foo/bar")!
let substring = string[range]  // -[NSPathStore2 characterAtIndex:]: index (7) beyond bounds (7)
print(substring)

Sample code for NSBigMutableString

import Foundation
import AppKit.NSTextStorage

// create NSBigMutableString instance via NSTextStorage
let bigString = String(repeating: "a", count: 513)  // 512+1 for NSBigMutableString
let string = NSTextStorage(string: bigString).string
print((string as NSString).className)  // -> NSBigMutableString

let range = string.range(of: "a", options: .backwards)!
let substring = string[range]  // -[NSBigMutableString characterAtIndex:]: Index 513 out of bounds; string length 513'
print(substring)
177d8476-2756-4152-91d7-984f74d3896c commented 5 years ago

@Catfish-Man , any ideas here?

belkadan commented 5 years ago

Guessing that was meant for (a different) @Catfish-Man?

Catfish-Man commented 5 years ago

Yeah. I'm going to look into this today most likely.

Catfish-Man commented 5 years ago

The primary change in NSPathStore2 between those releases was to support CFStringGetCharactersPtr, so presumably this is something that occurs on the non-contiguous path. I'll see if I can force that to happen on a newer system with a different string subclass.

Catfish-Man commented 5 years ago

Hmm. That hypothesis doesn't hold for NSBigMutableString though.

Catfish-Man commented 5 years ago

I believe this is fixed in https://github.com/apple/swift/pull/27779

Will attempt to confirm soon