1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
|
#include "OldABI.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>
#include <sys/mman.h>
#include <malloc/malloc.h>
#include <objc/runtime.h>
#include <Foundation/Foundation.h>
// Implementation of ObjC classes
// with bits set to mimic the pre-stable Swift ABI
// and additional memory protection to detect mis-use
#if __has_include(<objc/objc-internal.h>)
#include <objc/objc-internal.h>
#else
extern "C" Class objc_initializeClassPair(Class superclass, const char *name, Class cls, Class metacls);
extern "C" id _objc_rootRetain(id);
extern "C" void _objc_rootRelease(id);
extern "C" id _objc_rootAutorelease(id);
extern "C" uintptr_t _objc_rootRetainCount(id);
extern "C" bool _objc_rootTryRetain(id);
extern "C" bool _objc_rootIsDeallocating(id);
#endif
// This class stands in for the pre-stable ABI's SwiftObject.
// Stable Swift's class is named Swift._SwiftObject (but mangled).
__attribute__((objc_root_class))
@interface SwiftObject { id isa; } @end
@implementation SwiftObject
+(void)initialize { }
+(id)allocWithZone:(struct _malloc_zone_t *)zone {
return class_createInstance(self, 0);
}
+(id)alloc { return [self allocWithZone:nil]; }
+(id)class { return self; }
-(id)class { return object_getClass(self); }
+(id)superclass { return class_getSuperclass(self); }
-(id)superclass { return class_getSuperclass([self class]); }
+(BOOL)isMemberOfClass:(Class)cls { return object_getClass(self) == cls; }
-(BOOL)isMemberOfClass:(Class)cls { return [self class] == cls; }
-(id)self { return self; }
-(BOOL)isProxy { return NO; }
-(struct _malloc_zone_t *)zone { return malloc_default_zone(); }
-(void)doesNotRecognizeSelector:(SEL)sel {
Class cls = [self class];
fprintf(stderr, "unrecognized selector %c[%s %s]\n",
class_isMetaClass(cls) ? '+' : '-',
class_getName(cls), sel_getName(sel));
abort();
}
+(id)retain { return self; }
+(void)release { }
+(id)autorelease { return self; }
+(uintptr_t)retainCount { return ~(uintptr_t)0; }
+(BOOL)_tryRetain { return YES; }
+(BOOL)_isDeallocating { return NO; }
-(id)retain { return _objc_rootRetain(self); }
-(void)release { _objc_rootRelease(self); }
-(id)autorelease { return _objc_rootAutorelease(self); }
-(uintptr_t)retainCount { return _objc_rootRetainCount(self); }
-(BOOL)_tryRetain { return _objc_rootTryRetain(self); }
-(BOOL)_isDeallocating { return _objc_rootIsDeallocating(self); }
-(void)dealloc { object_dispose(self); }
-(BOOL)isKindOfClass:(Class)other {
for (Class cls = object_getClass(self); cls; cls = class_getSuperclass(cls))
if (cls == other) return YES;
return NO;
}
+(BOOL)isSubclassOfClass:(Class)other {
for (Class cls = self; cls; cls = class_getSuperclass(cls))
if (cls == other) return YES;
return NO;
}
-(BOOL)respondsToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector(object_getClass(self), sel);
}
+(BOOL)instancesRespondToSelector:(SEL)sel {
if (!sel) return NO;
return class_respondsToSelector(self, sel);
}
-(uintptr_t)hash { return (uintptr_t)self; }
-(BOOL)isEqual:(id)other { return self == other; }
+(NSString *)description { return @"FakeSwiftObject class"; }
-(NSString *)description { return @"FakeSwiftObject instance"; }
-(NSString *)debugDescription { return [self description]; }
- (BOOL)isNSArray__ { return NO; }
- (BOOL)isNSCFConstantString__ { return NO; }
- (BOOL)isNSData__ { return NO; }
- (BOOL)isNSDate__ { return NO; }
- (BOOL)isNSDictionary__ { return NO; }
- (BOOL)isNSObject__ { return NO; }
- (BOOL)isNSOrderedSet__ { return NO; }
- (BOOL)isNSNumber__ { return NO; }
- (BOOL)isNSSet__ { return NO; }
- (BOOL)isNSString__ { return NO; }
- (BOOL)isNSTimeZone__ { return NO; }
- (BOOL)isNSValue__ { return NO; }
@end
static char *AllocTailGuardedPointer(size_t size) {
// Round up to page boundary.
size_t writeableSize = (size + PAGE_MAX_SIZE - 1) & ~(PAGE_MAX_SIZE - 1);
// Allocate writeable memory plus one guard page.
char *writeableBuffer = (char *)mmap(0, writeableSize + PAGE_MAX_SIZE,
PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (writeableBuffer == MAP_FAILED) abort();
// Mark the guard page inaccessible.
mprotect(writeableBuffer + writeableSize, PAGE_MAX_SIZE, 0);
// Scribble on the prefix.
memset(writeableBuffer, 0x55, writeableSize - size);
// Return the address just before the guard page.
// FIXME: this doesn't handle alignment properly,
// but we don't need to for this test's usage.
return writeableBuffer + writeableSize - size;
}
static Class CreateOldABISubclass(Class supercls, const char *name) {
// Allocate class and metaclass in tail-guarded memory.
// If the Swift runtime incorrectly tries to read Swift
// metadata from this class then it'll crash.
char *clsbuf = AllocTailGuardedPointer(5*sizeof(uintptr_t));
char *metabuf = AllocTailGuardedPointer(5*sizeof(uintptr_t));
Class result = objc_initializeClassPair(supercls, name,
(Class)clsbuf, (Class)metabuf);
// Set the old is-Swift bit in the class.
uintptr_t *words = (uintptr_t *)clsbuf;
words[4] |= 1;
return result;
}
static Class FakeOldABIClass;
__attribute__((constructor))
static void initialize(void) {
FakeOldABIClass = CreateOldABISubclass([SwiftObject class],
"_TtC6OldABI8Subclass");
}
bool CanTestOldABI() {
// These tests don't work until the stable ABI is using its designed bit.
// This check can be removed after SWIFT_CLASS_IS_SWIFT_MASK is made
// static everywhere.
Class cls = objc_getClass("_TtCs19__EmptyArrayStorage");
if (!cls) abort();
uintptr_t *words = (uintptr_t *)cls;
if ((words[4] & 3) != 2) return false; // wrong stable is-Swift bit
return true;
}
id AllocOldABIObject() {
return [FakeOldABIClass alloc];
}
|