File: OldABI.mm

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (172 lines) | stat: -rw-r--r-- 5,978 bytes parent folder | download
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];
}