堆栈溢出 -[NSString(NSURLUtilities) stringByAddingPercentEncodingWithAllowedCharacters:]
Stack overflow in -[NSString(NSURLUtilities) stringByAddingPercentEncodingWithAllowedCharacters:]
来自http://www.openradar.me/20404230:
Method -[NSString(NSURLUtilities) stringByAddingPercentEncodingWithAllowedCharacters:] has a stack overflow issue, which can be reproduced with some strings containing hieroglyphs. In these cases __stack_chk_fail will abort the application when building for arm64 architecture, and stack will be corrupted when building for armv7.
来自 https://github.com/PavelTretyakov/nsstring-crash 的示例将在 iOS 8.2 上崩溃:
NSString *str = @"/Users/zaryanov/Movies/rootfolder/시티 오브 히어로 (City of Heroes)/로니 리 가드너 (1961년부터 2010년까지)는 1985 년에 살인죄로 사형을받은 유타 주에서 총살형 된 미국의 악당이었다. 1984 년에 그는 솔트 레이크 시티에서 강도 동안 바텐더를 살해.m4v";
str = [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
来自 https://gist.github.com/clowwindy/0d800f07a5e95e5c4dd0 的示例将在 iOS 8.1 上崩溃:
NSString *base64String = @"5a+55LqOTGF1bmNoZXLov5nnsbvkuqflk4HmnaXor7TvvIzlroPlvojlrrnmmJPorqnkurrku6zpmbflhaXov5nmmK/lt6Xlhbfov5jmmK/lubPlj7DnmoTkuonmiafkuK3jgILkuI3ov4flnKjmnY7mtpvnnIvmnaXvvIzov5nnp43kuonmiaflrozlhajmmK/kuIDkuKrkvKrlkb3popjvvIzlm6DkuLrkuIDmrL7kuqflk4HnlKjnmoTkurrlpJrkuoblroPoh6rnhLblsLHmmK/lubPlj7DvvIznlKjnmoTkurrlsJHkuoblroPku4DkuYjpg73kuI3mmK/jgILln7rkuo7mraTvvIzmnY7mtpvlhbblrp7lubbmsqHmnInov4flpJrnmoTljrvogIPomZFBUFVTIExhdW5jaGVy6KaB5YGa5bmz5Y+w6L+Y5piv5bel5YW377yM5LuW5oOz55qE5pu05aSa55qE5piv5aaC5L2V6Kej5Yaz55So5oi355qE6Zeu6aKY44CC5L2c5Li65LiA5Liq5Y2z55SoaU9T5Y+I55SoQW5kcm9pZOeahOeUqOaIt++8jOaIkeacrOS6uueahOS4gOS4quS9k+S8muWwseaYr2lQaG9uZeS8mue7meS6uuS4gOenjeS9oOi2iueUqOi2iuinieW+l+Wug+WlveeUqOeahOaEn+inie+8jOS9hkFuZHJvaWTlsLHkuI3kvJrjgILmiYDku6VBUFVTIExhdW5jaGVy546w5Zyo5bCx6KaB6Kej5Yaz6L+Z5Liq6Zq+6aKY77yM6K6pQW5kcm9pZOWPmOW+l+WlveeUqOOAgui/meS5n+aYr+S4uuS9leadjua2m+S8muivtOiHquW3seWBmueahOS4jeaYr+S4gOS4qkxhdW5jaGVy6ICM5piv5LiA5aWX4oCc55So5oi357O757uf4oCd44CC";
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
NSString *str = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
str = [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
来自 https://github.com/Alamofire/Alamofire/issues/206 的示例将在 iOS 7 到 iOS 8.2 崩溃:
let str = String(repeating: "一二三四五六七八九十", count: 2_000)
var allowedCharacterSet = CharacterSet.urlQueryAllowed
allowedCharacterSet.remove(charactersIn: ":#[]@!$&'()*+,;=")
_ = str.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
PrideChung 在 https://github.com/Alamofire/Alamofire/issues/206 中提供了内存问题解决方法的标识。以下描述随后被cnoon给出:
After much debugging, I was able to track this issue down to only occurring in Alamofire on iOS 8.1 and 8.2 using the iPhone 4S and iPhone 5 simulators. It is 100% reproducible, but is crashing in different ways depending on the size of the Chinese string that is passed in. It's always some form of a malloc error.
[...]
Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few hundred Chinese characters causes various malloc error crashes. To avoid this issue batching MUST be used for encoding.
而我受 AlamoFire 启发的实际解决方法是:
extension String {
// Due to an internal bug in iOS 7.x, 8.1 and 8.2, encoding more
// than a few hundred Unicode characters causes various malloc error crashes.
// To avoid this issue, batching MUST be used for encoding.
// - https://github.com/Alamofire/Alamofire/issues/206
// -
func safeAddingPercentEncoding(withAllowedCharacters allowedCharacters: CharacterSet) -> String? {
if #available(iOS 8.3, *) {
return addingPercentEncoding(withAllowedCharacters: allowedCharacters)
} else {
let batchSize = 50
var batchPosition = startIndex
var escaped = ""
while batchPosition != endIndex {
let range = batchPosition ..< (index(batchPosition, offsetBy: batchSize, limitedBy: endIndex) ?? endIndex)
guard let percentEncodedSubstring = substring(with: range).addingPercentEncoding(withAllowedCharacters: allowedCharacters) else {
return nil
}
escaped.append(percentEncodedSubstring)
batchPosition = range.upperBound
}
return escaped
}
}
}
来自http://www.openradar.me/20404230:
Method -[NSString(NSURLUtilities) stringByAddingPercentEncodingWithAllowedCharacters:] has a stack overflow issue, which can be reproduced with some strings containing hieroglyphs. In these cases __stack_chk_fail will abort the application when building for arm64 architecture, and stack will be corrupted when building for armv7.
来自 https://github.com/PavelTretyakov/nsstring-crash 的示例将在 iOS 8.2 上崩溃:
NSString *str = @"/Users/zaryanov/Movies/rootfolder/시티 오브 히어로 (City of Heroes)/로니 리 가드너 (1961년부터 2010년까지)는 1985 년에 살인죄로 사형을받은 유타 주에서 총살형 된 미국의 악당이었다. 1984 년에 그는 솔트 레이크 시티에서 강도 동안 바텐더를 살해.m4v";
str = [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
来自 https://gist.github.com/clowwindy/0d800f07a5e95e5c4dd0 的示例将在 iOS 8.1 上崩溃:
NSString *base64String = @"5a+55LqOTGF1bmNoZXLov5nnsbvkuqflk4HmnaXor7TvvIzlroPlvojlrrnmmJPorqnkurrku6zpmbflhaXov5nmmK/lt6Xlhbfov5jmmK/lubPlj7DnmoTkuonmiafkuK3jgILkuI3ov4flnKjmnY7mtpvnnIvmnaXvvIzov5nnp43kuonmiaflrozlhajmmK/kuIDkuKrkvKrlkb3popjvvIzlm6DkuLrkuIDmrL7kuqflk4HnlKjnmoTkurrlpJrkuoblroPoh6rnhLblsLHmmK/lubPlj7DvvIznlKjnmoTkurrlsJHkuoblroPku4DkuYjpg73kuI3mmK/jgILln7rkuo7mraTvvIzmnY7mtpvlhbblrp7lubbmsqHmnInov4flpJrnmoTljrvogIPomZFBUFVTIExhdW5jaGVy6KaB5YGa5bmz5Y+w6L+Y5piv5bel5YW377yM5LuW5oOz55qE5pu05aSa55qE5piv5aaC5L2V6Kej5Yaz55So5oi355qE6Zeu6aKY44CC5L2c5Li65LiA5Liq5Y2z55SoaU9T5Y+I55SoQW5kcm9pZOeahOeUqOaIt++8jOaIkeacrOS6uueahOS4gOS4quS9k+S8muWwseaYr2lQaG9uZeS8mue7meS6uuS4gOenjeS9oOi2iueUqOi2iuinieW+l+Wug+WlveeUqOeahOaEn+inie+8jOS9hkFuZHJvaWTlsLHkuI3kvJrjgILmiYDku6VBUFVTIExhdW5jaGVy546w5Zyo5bCx6KaB6Kej5Yaz6L+Z5Liq6Zq+6aKY77yM6K6pQW5kcm9pZOWPmOW+l+WlveeUqOOAgui/meS5n+aYr+S4uuS9leadjua2m+S8muivtOiHquW3seWBmueahOS4jeaYr+S4gOS4qkxhdW5jaGVy6ICM5piv5LiA5aWX4oCc55So5oi357O757uf4oCd44CC";
NSData *decodedData = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
NSString *str = [[NSString alloc] initWithData:decodedData encoding:NSUTF8StringEncoding];
str = [str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];
来自 https://github.com/Alamofire/Alamofire/issues/206 的示例将在 iOS 7 到 iOS 8.2 崩溃:
let str = String(repeating: "一二三四五六七八九十", count: 2_000)
var allowedCharacterSet = CharacterSet.urlQueryAllowed
allowedCharacterSet.remove(charactersIn: ":#[]@!$&'()*+,;=")
_ = str.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet)
PrideChung 在 https://github.com/Alamofire/Alamofire/issues/206 中提供了内存问题解决方法的标识。以下描述随后被cnoon给出:
After much debugging, I was able to track this issue down to only occurring in Alamofire on iOS 8.1 and 8.2 using the iPhone 4S and iPhone 5 simulators. It is 100% reproducible, but is crashing in different ways depending on the size of the Chinese string that is passed in. It's always some form of a malloc error.
[...]
Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few hundred Chinese characters causes various malloc error crashes. To avoid this issue batching MUST be used for encoding.
而我受 AlamoFire 启发的实际解决方法是:
extension String {
// Due to an internal bug in iOS 7.x, 8.1 and 8.2, encoding more
// than a few hundred Unicode characters causes various malloc error crashes.
// To avoid this issue, batching MUST be used for encoding.
// - https://github.com/Alamofire/Alamofire/issues/206
// -
func safeAddingPercentEncoding(withAllowedCharacters allowedCharacters: CharacterSet) -> String? {
if #available(iOS 8.3, *) {
return addingPercentEncoding(withAllowedCharacters: allowedCharacters)
} else {
let batchSize = 50
var batchPosition = startIndex
var escaped = ""
while batchPosition != endIndex {
let range = batchPosition ..< (index(batchPosition, offsetBy: batchSize, limitedBy: endIndex) ?? endIndex)
guard let percentEncodedSubstring = substring(with: range).addingPercentEncoding(withAllowedCharacters: allowedCharacters) else {
return nil
}
escaped.append(percentEncodedSubstring)
batchPosition = range.upperBound
}
return escaped
}
}
}