]> git.saurik.com Git - apple/objc4.git/blob - test/readClassPair.m
objc4-818.2.tar.gz
[apple/objc4.git] / test / readClassPair.m
1 /*
2 TEST_RUN_OUTPUT
3 objc\[\d+\]: Class Sub is implemented in both [^\s]+ \(0x[0-9a-f]+\) and [^\s]+ \(0x[0-9a-f]+\)\. One of the two will be used\. Which one is undefined\.
4 OK: readClassPair.m
5 END
6 */
7
8 #include "test.h"
9 #include <objc/objc-internal.h>
10
11 // Reuse evil-class-def.m as a non-evil class definition.
12
13 #define EVIL_SUPER 0
14 #define EVIL_SUPER_META 0
15 #define EVIL_SUB 0
16 #define EVIL_SUB_META 0
17
18 #define OMIT_SUPER 1
19 #define OMIT_NL_SUPER 1
20 #define OMIT_SUB 1
21 #define OMIT_NL_SUB 1
22
23 #include "evil-class-def.m"
24
25 int main()
26 {
27 // This definition is ABI and is never allowed to change.
28 testassert(OBJC_MAX_CLASS_SIZE == 32*sizeof(void*));
29
30 struct objc_image_info ii = { 0, 0 };
31
32 // Read a root class.
33 testassert(!objc_getClass("Super"));
34
35 extern intptr_t OBJC_CLASS_$_Super[OBJC_MAX_CLASS_SIZE/sizeof(void*)];
36 Class Super = objc_readClassPair((__bridge Class)(void*)&OBJC_CLASS_$_Super, &ii);
37 testassert(Super);
38
39 testassert(objc_getClass("Super") == Super);
40 testassert(0 == strcmp(class_getName(Super), "Super"));
41 testassert(class_getSuperclass(Super) == nil);
42 testassert(class_getClassMethod(Super, @selector(load)));
43 testassert(class_getInstanceMethod(Super, @selector(load)));
44 testassert(class_getInstanceVariable(Super, "super_ivar"));
45 testassert(class_getInstanceSize(Super) == sizeof(void*));
46 [Super load];
47
48 // Read a non-root class.
49 testassert(!objc_getClass("Sub"));
50
51 // Clang assumes too much alignment on this by default (rdar://problem/60881608),
52 // so tell it that it's only as aligned as an intptr_t.
53 extern _Alignas(intptr_t) intptr_t OBJC_CLASS_$_Sub[OBJC_MAX_CLASS_SIZE/sizeof(void*)];
54 // Make a duplicate of class Sub for use later.
55 intptr_t Sub2_buf[OBJC_MAX_CLASS_SIZE/sizeof(void*)];
56 memcpy(Sub2_buf, &OBJC_CLASS_$_Sub, sizeof(Sub2_buf));
57 // Re-sign the isa and super pointers in the new location.
58 ((Class __ptrauth_objc_isa_pointer *)(void *)Sub2_buf)[0] = ((Class __ptrauth_objc_isa_pointer *)(void *)&OBJC_CLASS_$_Sub)[0];
59 ((Class __ptrauth_objc_super_pointer *)(void *)Sub2_buf)[1] = ((Class __ptrauth_objc_super_pointer *)(void *)&OBJC_CLASS_$_Sub)[1];
60
61 Class Sub = objc_readClassPair((__bridge Class)(void*)&OBJC_CLASS_$_Sub, &ii);
62 testassert(Sub);
63
64 testassert(0 == strcmp(class_getName(Sub), "Sub"));
65 testassert(objc_getClass("Sub") == Sub);
66 testassert(class_getSuperclass(Sub) == Super);
67 testassert(class_getClassMethod(Sub, @selector(load)));
68 testassert(class_getInstanceMethod(Sub, @selector(load)));
69 testassert(class_getInstanceVariable(Sub, "sub_ivar"));
70 testassert(class_getInstanceSize(Sub) == 2*sizeof(void*));
71 [Sub load];
72
73 // Reading a class whose name already exists succeeds
74 // with a duplicate warning.
75 Class Sub2 = objc_readClassPair((__bridge Class)(void*)Sub2_buf, &ii);
76 testassert(Sub2);
77 testassert(Sub2 != Sub);
78 testassert(objc_getClass("Sub") == Sub); // didn't change
79 testassert(0 == strcmp(class_getName(Sub2), "Sub"));
80 testassert(class_getSuperclass(Sub2) == Super);
81 testassert(class_getClassMethod(Sub2, @selector(load)));
82 testassert(class_getInstanceMethod(Sub2, @selector(load)));
83 testassert(class_getInstanceVariable(Sub2, "sub_ivar"));
84 testassert(class_getInstanceSize(Sub2) == 2*sizeof(void*));
85 [Sub2 load];
86
87 succeed(__FILE__);
88 }