]>
Commit | Line | Data |
---|---|---|
13ba007e A |
1 | // TEST_CFLAGS -Wl,-no_objc_category_merging |
2 | ||
3 | #include "test.h" | |
4 | #include "testroot.i" | |
5 | #include <string.h> | |
6 | #include <objc/runtime.h> | |
7 | ||
1807f628 A |
8 | #if __LP64__ |
9 | # define PTR " .quad " | |
10 | #else | |
11 | # define PTR " .long " | |
12 | #endif | |
13 | ||
13ba007e A |
14 | static int state = 0; |
15 | ||
16 | @interface Super : TestRoot @end | |
17 | @implementation Super | |
18 | -(void)instancemethod { fail("-instancemethod not overridden by category"); } | |
19 | +(void)method { fail("+method not overridden by category"); } | |
20 | @end | |
21 | ||
22 | @interface Super (Category) @end | |
23 | @implementation Super (Category) | |
24 | +(void)method { | |
25 | testprintf("in [Super(Category) method]\n"); | |
26 | testassert(self == [Super class]); | |
27 | testassert(state == 0); | |
28 | state = 1; | |
29 | } | |
30 | -(void)instancemethod { | |
31 | testprintf("in [Super(Category) instancemethod]\n"); | |
32 | testassert(object_getClass(self) == [Super class]); | |
33 | testassert(state == 1); | |
34 | state = 2; | |
35 | } | |
36 | @end | |
37 | ||
38 | @interface Super (PropertyCategory) | |
39 | @property int i; | |
40 | @property(class) int i; | |
41 | @end | |
42 | @implementation Super (PropertyCategory) | |
43 | - (int)i { return 0; } | |
44 | - (void)setI:(int)value { (void)value; } | |
45 | + (int)i { return 0; } | |
46 | + (void)setI:(int)value { (void)value; } | |
47 | @end | |
48 | ||
49 | // rdar://5086110 memory smasher in category with class method and property | |
50 | @interface Super (r5086110) | |
51 | @property int property5086110; | |
52 | @end | |
53 | @implementation Super (r5086110) | |
54 | +(void)method5086110 { | |
55 | fail("method method5086110 called!"); | |
56 | } | |
57 | - (int)property5086110 { fail("property5086110 called!"); return 0; } | |
58 | - (void)setProperty5086110:(int)value { fail("setProperty5086110 called!"); (void)value; } | |
59 | @end | |
60 | ||
61 | // rdar://25605427 incorrect handling of class properties in 10.11 and earlier | |
62 | @interface Super25605427 : TestRoot | |
63 | @property(class, readonly) int i; | |
64 | @end | |
65 | @implementation Super25605427 | |
66 | +(int)i { return 0; } | |
67 | @end | |
68 | ||
69 | @interface Super25605427 (r25605427a) | |
70 | @property(readonly) int r25605427a1; | |
71 | @end | |
72 | @implementation Super25605427 (r25605427a) | |
73 | -(int)r25605427a1 { return 0; } | |
74 | +(int)r25605427a2 { return 0; } | |
75 | @end | |
76 | ||
77 | @interface Super25605427 (r25605427b) | |
78 | @property(readonly) int r25605427b1; | |
79 | @end | |
80 | @implementation Super25605427 (r25605427b) | |
81 | -(int)r25605427b1 { return 0; } | |
82 | +(int)r25605427b2 { return 0; } | |
83 | @end | |
84 | ||
85 | @interface Super25605427 (r25605427c) | |
86 | @property(readonly) int r25605427c1; | |
87 | @end | |
88 | @implementation Super25605427 (r25605427c) | |
89 | -(int)r25605427c1 { return 0; } | |
90 | +(int)r25605427c2 { return 0; } | |
91 | @end | |
92 | ||
93 | @interface Super25605427 (r25605427d) | |
94 | @property(readonly) int r25605427d1; | |
95 | @end | |
96 | @implementation Super25605427 (r25605427d) | |
97 | -(int)r25605427d1 { return 0; } | |
98 | +(int)r25605427d2 { return 0; } | |
99 | @end | |
100 | ||
101 | ||
102 | @interface PropertyClass : Super { | |
103 | int q; | |
104 | } | |
105 | @property(readonly) int q; | |
106 | @end | |
107 | @implementation PropertyClass | |
108 | @synthesize q; | |
109 | @end | |
110 | ||
111 | @interface PropertyClass (PropertyCategory) | |
112 | @property int q; | |
113 | @end | |
114 | @implementation PropertyClass (PropertyCategory) | |
115 | @dynamic q; | |
116 | @end | |
117 | ||
118 | ||
1807f628 A |
119 | // Manually build a category that goes in __objc_catlist2. |
120 | #if __has_feature(ptrauth_calls) | |
121 | #define SIGNED_CATEGORY_IMP "@AUTH(ia,0,addr)" | |
122 | #else | |
123 | #define SIGNED_CATEGORY_IMP | |
124 | #endif | |
125 | asm( | |
126 | " .section __DATA,__objc_const \n" | |
127 | "L_catlist2CategoryName: \n" | |
128 | " .asciz \"Category_catlist2\" \n" | |
129 | "L_catlist2MethodString: \n" | |
130 | " .asciz \"catlist2Method\" \n" | |
131 | "L_catlist2MethodTypes: \n" | |
132 | " .asciz \"i16@0:8\" \n" | |
133 | ||
134 | " .p2align 3 \n" | |
135 | "l_OBJC_$_CATEGORY_INSTANCE_METHODS_Super_$_Category_catlist2: \n" | |
136 | " .long 24 \n" | |
137 | " .long 1 \n" | |
34d5b5e8 A |
138 | " " PTR " L_catlist2MethodString \n" |
139 | " " PTR " L_catlist2MethodTypes \n" | |
140 | " " PTR " _catlist2MethodImplementation" SIGNED_CATEGORY_IMP" \n" | |
1807f628 A |
141 | |
142 | " .p2align 3 \n" | |
143 | "l_OBJC_$_CATEGORY_Super_$_Category_catlist2: \n" | |
34d5b5e8 A |
144 | " " PTR " L_catlist2CategoryName \n" |
145 | " " PTR " _OBJC_CLASS_$_Super \n" | |
146 | " " PTR " l_OBJC_$_CATEGORY_INSTANCE_METHODS_Super_$_Category_catlist2 \n" | |
147 | " " PTR " 0 \n" | |
148 | " " PTR " 0 \n" | |
149 | " " PTR " 0 \n" | |
150 | " " PTR " 0 \n" | |
1807f628 A |
151 | " .long 64 \n" |
152 | " .space 4 \n" | |
153 | ||
154 | " .section __DATA,__objc_catlist2 \n" | |
155 | " .p2align 3 \n" | |
34d5b5e8 | 156 | " " PTR " l_OBJC_$_CATEGORY_Super_$_Category_catlist2 \n" |
1807f628 A |
157 | |
158 | " .text \n" | |
159 | ); | |
160 | ||
161 | @interface Super (Category_catlist2) | |
162 | - (int)catlist2Method; | |
163 | @end | |
164 | ||
165 | EXTERN_C int catlist2MethodImplementation(id self __unused, SEL _cmd __unused) { | |
166 | return 0; | |
167 | } | |
168 | ||
169 | ||
13ba007e A |
170 | int main() |
171 | { | |
172 | { | |
173 | // rdar://25605427 bugs in 10.11 and earlier when metaclass | |
174 | // has a property and category has metaclass additions. | |
175 | // Memory smasher in buildPropertyList (caught by guard malloc) | |
176 | Class cls = [Super25605427 class]; | |
177 | // Incorrect attachment of instance properties from category to metacls | |
178 | testassert(class_getProperty(cls, "r25605427d1")); | |
179 | testassert(! class_getProperty(object_getClass(cls), "r25605427d1")); | |
180 | } | |
181 | ||
182 | // methods introduced by category | |
183 | state = 0; | |
184 | [Super method]; | |
185 | [[Super new] instancemethod]; | |
186 | testassert(state == 2); | |
187 | ||
188 | // property introduced by category | |
189 | objc_property_t p = class_getProperty([Super class], "i"); | |
190 | testassert(p); | |
191 | testassert(0 == strcmp(property_getName(p), "i")); | |
192 | testassert(property_getAttributes(p)); | |
193 | ||
194 | objc_property_t p2 = class_getProperty(object_getClass([Super class]), "i"); | |
195 | testassert(p2); | |
196 | testassert(p != p2); | |
197 | testassert(0 == strcmp(property_getName(p2), "i")); | |
198 | testassert(property_getAttributes(p2)); | |
199 | ||
200 | // methods introduced by category's property | |
201 | Method m; | |
202 | m = class_getInstanceMethod([Super class], @selector(i)); | |
203 | testassert(m); | |
204 | m = class_getInstanceMethod([Super class], @selector(setI:)); | |
205 | testassert(m); | |
206 | ||
207 | m = class_getClassMethod([Super class], @selector(i)); | |
208 | testassert(m); | |
209 | m = class_getClassMethod([Super class], @selector(setI:)); | |
210 | testassert(m); | |
211 | ||
212 | // class's property shadowed by category's property | |
213 | objc_property_t *plist = class_copyPropertyList([PropertyClass class], NULL); | |
214 | testassert(plist); | |
215 | testassert(plist[0]); | |
216 | testassert(0 == strcmp(property_getName(plist[0]), "q")); | |
217 | testassert(0 == strcmp(property_getAttributes(plist[0]), "Ti,D")); | |
218 | testassert(plist[1]); | |
219 | testassert(0 == strcmp(property_getName(plist[1]), "q")); | |
220 | testassert(0 == strcmp(property_getAttributes(plist[1]), "Ti,R,Vq")); | |
221 | testassert(!plist[2]); | |
222 | free(plist); | |
223 | ||
1807f628 A |
224 | // method introduced by category in catlist2 |
225 | testassert([[Super new] catlist2Method] == 0); | |
226 | ||
13ba007e A |
227 | succeed(__FILE__); |
228 | } | |
229 |