1
1
#import < string.h>
2
2
#import " NSSlowTaggedLocalizedString.h"
3
3
#import < dlfcn.h>
4
+ #import < objc/runtime.h>
5
+
6
+ // If and when CF starts linking Swift we may need to rethink this
7
+ #import < CoreFoundation/CoreFoundation.h>
4
8
5
9
@implementation NSSlowTaggedLocalizedString
6
10
7
- uintptr_t *obfuscator;
8
- void (*_objc_registerTaggedPointerClass)(uint16_t tag, Class cls);
11
+ typedef struct _NSRange {
12
+ uint64_t location;
13
+ uint64_t length;
14
+ } NSRange ;
9
15
10
16
+ (instancetype ) createTestString {
11
17
#if __LP64__
12
- if (obfuscator == NULL ) {
13
- obfuscator = dlsym (RTLD_DEFAULT, " objc_debug_taggedpointer_obfuscator" );
14
- *obfuscator = 0 ;
15
- _objc_registerTaggedPointerClass = dlsym (RTLD_DEFAULT, " _objc_registerTaggedPointerClass" );
16
- (*_objc_registerTaggedPointerClass)(0 , self); // 0 would be unsafe if we loaded Foundation, but we aren't doing that
17
- }
18
- #if __x86_64__
19
- return (id )(void *)(uintptr_t )1 ; // x86_64 uses the LSB as the tag bit, and we want tag 0
20
- #else
21
- return (id )(void *)(uintptr_t )(1llu << 63 ); // MSB everywhere else
22
- #endif
18
+ static dispatch_once_t onceToken;
19
+ dispatch_once (&onceToken, ^{
20
+ Class tagClass = objc_lookUpClass (" NSTaggedPointerString" );
21
+ Class ourClass = [NSSlowTaggedLocalizedString class ];
22
+
23
+ Method fastCString = class_getInstanceMethod (ourClass, @selector (_fastCStringContents: ));
24
+ class_replaceMethod (tagClass, @selector (_fastCStringContents: ), method_getImplementation (fastCString), method_getTypeEncoding (fastCString));
25
+
26
+ Method length = class_getInstanceMethod (ourClass, @selector (length ));
27
+ class_replaceMethod (tagClass, @selector (length ), method_getImplementation (length), method_getTypeEncoding (length));
28
+
29
+ Method charIndex = class_getInstanceMethod (ourClass, @selector (characterAtIndex: ));
30
+ class_replaceMethod (tagClass, @selector (characterAtIndex: ), method_getImplementation (charIndex), method_getTypeEncoding (charIndex));
31
+
32
+ Method fastChars = class_getInstanceMethod (ourClass, @selector (_fastCharacterContents ));
33
+ class_replaceMethod (tagClass, @selector (_fastCharacterContents ), method_getImplementation (fastChars), method_getTypeEncoding (fastChars));
34
+
35
+ Method retain = class_getInstanceMethod (ourClass, @selector (retain ));
36
+ class_replaceMethod (tagClass, @selector (retain ), method_getImplementation (retain), method_getTypeEncoding (retain));
37
+
38
+ Method release = class_getInstanceMethod (ourClass, @selector (release ));
39
+ class_replaceMethod (tagClass, @selector (release ), method_getImplementation (release), method_getTypeEncoding (release));
40
+
41
+ Method typeID = class_getInstanceMethod (ourClass, @selector (_cfTypeID ));
42
+ class_replaceMethod (tagClass, @selector (_cfTypeID ), method_getImplementation (typeID), method_getTypeEncoding (typeID));
43
+
44
+ Method description = class_getInstanceMethod (ourClass, @selector (description ));
45
+ class_replaceMethod (tagClass, @selector (description ), method_getImplementation (description), method_getTypeEncoding (description));
46
+
47
+ Method getBytes = class_getInstanceMethod (ourClass, @selector (getBytes:maxLength:usedLength:encoding:options:range:remainingRange: ));
48
+ class_replaceMethod (tagClass, @selector (getBytes:maxLength:usedLength:encoding:options:range:remainingRange: ), method_getImplementation (getBytes), method_getTypeEncoding (getBytes));
49
+ });
50
+ return (NSSlowTaggedLocalizedString *)(void *)CFStringCreateWithCString (NULL , " a" , kCFStringEncodingASCII ); // make a tagged pointer string
23
51
#else
24
52
return nil ;
25
53
#endif
@@ -29,7 +57,11 @@ + (instancetype) createTestString {
29
57
30
58
+ (void ) setContents : (const char *)newContents {
31
59
const char *oldContents = contents;
32
- contents = strdup (newContents);
60
+ if (newContents) {
61
+ contents = strdup (newContents);
62
+ } else {
63
+ contents = NULL ;
64
+ }
33
65
free ((void *)oldContents);
34
66
}
35
67
@@ -46,6 +78,7 @@ - (id)copyWithZone:(id)unused {
46
78
}
47
79
48
80
- (uint16_t )characterAtIndex : (NSUInteger )index {
81
+ abort ();
49
82
if (index >= [self length ]) {
50
83
// throw the appropriate exception
51
84
abort ();
@@ -57,4 +90,27 @@ - (void *) _fastCharacterContents {
57
90
return nil ;
58
91
}
59
92
93
+ - (id ) retain { return self; }
94
+ - (oneway void ) release {}
95
+
96
+ - (uint64_t )_cfTypeID {
97
+ return 7 ; // CFString
98
+ }
99
+
100
+ - (id ) description {
101
+ return self;
102
+ }
103
+
104
+ - (BOOL )getBytes : (void *)buffer maxLength : (uint64_t )max usedLength : (uint64_t *)used encoding : (uint64_t )encoding options : (uint64_t )options range : (NSRange )range remainingRange : (NSRange *)leftover {
105
+ strncpy (buffer, contents, max);
106
+ if (strlen (contents) > max) {
107
+ leftover->location = max;
108
+ leftover->length = strlen (contents) - max;
109
+ return false ;
110
+ }
111
+ leftover->location = 0 ;
112
+ leftover->length = 0 ;
113
+ return true ;
114
+ }
115
+
60
116
@end
0 commit comments