Skip to content

Commit

Permalink
Fall back on CoreFoundation for some core NSString/NSCFString behavio…
Browse files Browse the repository at this point in the history
…urs (#671)

* Use the _CFString internal methods from ForFoundationOnly in NSCFString.
* Replace our manual strings format parser with CoreFoundation's.
* Check lengths in -isAbsolutePath, -getCharacters:range: and NSCFURL's path code.

*NOTE*: NSString now properly throws range/index exceptions.
  • Loading branch information
DHowett authored Jul 21, 2016
1 parent acf58a9 commit e82015d
Show file tree
Hide file tree
Showing 9 changed files with 142 additions and 275 deletions.
34 changes: 30 additions & 4 deletions Frameworks/CoreFoundationAdditions/_NSCFString.mm
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
#include "_NSCFString.h"
#include <CoreFoundation/CFString.h>

@interface _NSCFTemporaryRootObject (NSString)
- (void)_raiseBoundsExceptionForSelector:(SEL)selector andIndex:(NSUInteger)index;
- (void)_raiseBoundsExceptionForSelector:(SEL)selector andRange:(NSRange)range;
@end

// ignore bridge cast warnings here. _NSCFString will be a subclass of NSString. It just
// doesn't realize it yet.
#pragma clang diagnostic push
Expand Down Expand Up @@ -59,19 +64,40 @@ + (instancetype)allocWithZone:(NSZone*)zone {

// NSString overrides
- (NSUInteger)length {
return CFStringGetLength(static_cast<CFStringRef>(self));
return _CFStringGetLength2(static_cast<CFStringRef>(self));
}

- (NSUInteger)hash {
return __CFStringHash(static_cast<CFStringRef>(self));
}

- (unichar)characterAtIndex:(NSUInteger)index {
return CFStringGetCharacterAtIndex(static_cast<CFStringRef>(self), index);
unichar ch = 0;
int err = _CFStringCheckAndGetCharacterAtIndex(static_cast<CFStringRef>(self), index, &ch);
if (err == _CFStringErrBounds) {
[self _raiseBoundsExceptionForSelector:_cmd andIndex:index];
return 0;
}
return ch;
}

- (void)getCharacters:(unichar*)buffer range:(NSRange)range {
return CFStringGetCharacters(static_cast<CFStringRef>(self), CFRange{ range.location, range.length }, buffer);
int err = _CFStringCheckAndGetCharacters(static_cast<CFStringRef>(self), CFRange{ range.location, range.length }, buffer);
if (err == _CFStringErrBounds) {
[self _raiseBoundsExceptionForSelector:_cmd andRange:range];
}
}

- (void)replaceCharactersInRange:(NSRange)range withString:(NSString*)replacement {
CFStringReplace(static_cast<CFMutableStringRef>(self), CFRange{ range.location, range.length }, static_cast<CFStringRef>(replacement));
int err = __CFStringCheckAndReplace(static_cast<CFMutableStringRef>(self), CFRange{ range.location, range.length }, static_cast<CFStringRef>(replacement));
switch (err) {
case _CFStringErrBounds:
[self _raiseBoundsExceptionForSelector:_cmd andRange:range];
break;
case _CFStringErrNotMutable:
[self doesNotRecognizeSelector:_cmd];
break;
}
}

- (instancetype)copyWithZone:(NSZone*)zone {
Expand Down
16 changes: 15 additions & 1 deletion Frameworks/CoreFoundationAdditions/_NSCFTemporaryRootObject.mm
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,19 @@
//******************************************************************************
#include "_NSCFTemporaryRootObject.h"

#include <Windows.h>

@implementation _NSCFTemporaryRootObject
@end
- (void)doesNotRecognizeSelector:(SEL)selector {
// According to the reference platform documentation, this method must never return.
EXCEPTION_RECORD record{
EXCEPTION_NONCONTINUABLE_EXCEPTION,
EXCEPTION_NONCONTINUABLE,
nullptr,
nullptr,
0,
{0}
};
RaiseFailFastException(&record, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS);
}
@end
2 changes: 1 addition & 1 deletion Frameworks/Foundation/NSCFMutableString.mm
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ - (instancetype)initWithUTF8String:(const char*)utf8str {

- (instancetype)initWithFormat:(id)formatStr arguments:(va_list)pReader {
CFMutableStringRef mutableRef = CFStringCreateMutable(kCFAllocatorDefault, 0);
CFStringAppendFormatAndArguments(mutableRef, nullptr, static_cast<CFStringRef>(formatStr), pReader);
_CFStringAppendFormatAndArgumentsAux(mutableRef, &_NSCFStringCopyDescription, nullptr, static_cast<CFStringRef>(formatStr), pReader);
return reinterpret_cast<NSMutableStringPrototype*>(static_cast<NSMutableString*>(mutableRef));
}

Expand Down
4 changes: 3 additions & 1 deletion Frameworks/Foundation/NSCFString.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@
@end

@interface NSMutableStringPrototype : NSMutableString
@end
@end

CFStringRef _NSCFStringCopyDescription(void* cfTypeRef, const void* locInfo);
16 changes: 10 additions & 6 deletions Frameworks/Foundation/NSCFString.mm
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
#include "BridgeHelpers.h"
#include "ForFoundationOnly.h"

CFStringRef _NSCFStringCopyDescription(void* cfTypeRef, const void* locInfo) {
return (CFStringRef)[[static_cast<id>(cfTypeRef) description] copy];
}

@implementation NSStringPrototype

PROTOTYPE_CLASS_REQUIRED_IMPLS(NSObject)
Expand All @@ -45,7 +49,7 @@ - (instancetype)initWithUTF8String:(const char*)utf8str {

- (instancetype)initWithFormat:(id)formatStr arguments:(va_list)pReader {
return reinterpret_cast<NSStringPrototype*>(static_cast<NSString*>(
CFStringCreateWithFormatAndArguments(kCFAllocatorDefault, nullptr, static_cast<CFStringRef>(formatStr), pReader)));
_CFStringCreateWithFormatAndArgumentsAux(kCFAllocatorDefault, &_NSCFStringCopyDescription, nullptr, static_cast<CFStringRef>(formatStr), pReader)));
}

- (instancetype)initWithBytes:(const void*)bytes length:(NSUInteger)length encoding:(NSStringEncoding)encoding {
Expand Down Expand Up @@ -89,12 +93,12 @@ - (instancetype)initWithFormat:(NSString*)format locale:(id)locale arguments:(va
CFStringRef str;

if (locale == nil) {
str = CFStringCreateWithFormatAndArguments(nullptr, nullptr, static_cast<CFStringRef>(format), argList);
str = _CFStringCreateWithFormatAndArgumentsAux(nullptr, &_NSCFStringCopyDescription, nullptr, static_cast<CFStringRef>(format), argList);
} else if ([locale isKindOfClass:[NSLocale class]] || [locale isKindOfClass:[NSDictionary class]]) {
str = CFStringCreateWithFormatAndArguments(kCFAllocatorDefault,
static_cast<CFDictionaryRef>(locale),
static_cast<CFStringRef>(format),
argList);
str = _CFStringCreateWithFormatAndArgumentsAux(kCFAllocatorDefault, &_NSCFStringCopyDescription,
static_cast<CFDictionaryRef>(locale),
static_cast<CFStringRef>(format),
argList);
} else {
[NSException raise:NSInvalidArgumentException format:@"Locale parameter must be a NSLocale or a NSDictionary."];
}
Expand Down
2 changes: 1 addition & 1 deletion Frameworks/Foundation/NSCFURL.mm
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ - (NSString*)path {
ret = [ret stringByRemovingPercentEncoding];

// Remove slashes from before drives
if (([ret hasPrefix:_NSGetSlashStr()]) && (_isLetter([ret characterAtIndex:1])) && ([ret characterAtIndex:2] == ':')) {
if ([ret length] >= 3 && ([ret hasPrefix:_NSGetSlashStr()]) && (_isLetter([ret characterAtIndex:1])) && ([ret characterAtIndex:2] == ':')) {
ret = [ret substringFromIndex:1];
}

Expand Down
Loading

0 comments on commit e82015d

Please sign in to comment.