]> git.saurik.com Git - apple/objc4.git/blob - test/unload.m
objc4-680.tar.gz
[apple/objc4.git] / test / unload.m
1 // xpc leaks memory in dlopen(). Disable it.
2 // TEST_ENV XPC_SERVICES_UNAVAILABLE=1
3 /*
4 TEST_BUILD
5 $C{COMPILE} $DIR/unload4.m -o unload4.dylib -dynamiclib
6 $C{COMPILE_C} $DIR/unload3.c -o unload3.dylib -dynamiclib
7 $C{COMPILE} $DIR/unload2.m -o unload2.bundle -bundle
8 $C{COMPILE} $DIR/unload.m -o unload.out
9 END
10 */
11
12 #include "test.h"
13 #include <objc/runtime.h>
14 #include <dlfcn.h>
15 #include <unistd.h>
16
17 #include "unload.h"
18
19 #if __has_feature(objc_arc)
20
21 int main()
22 {
23 testwarn("rdar://11368528 confused by Foundation");
24 succeed(__FILE__);
25 }
26
27 #else
28
29 static id forward_handler(void)
30 {
31 return 0;
32 }
33
34 static BOOL hasName(const char * const *names, const char *query)
35 {
36 const char *name;
37 while ((name = *names++)) {
38 if (strstr(name, query)) return YES;
39 }
40
41 return NO;
42 }
43
44 void cycle(void)
45 {
46 int i;
47 char buf[100];
48 unsigned int imageCount, imageCount0;
49 const char **names;
50 const char *name;
51
52 names = objc_copyImageNames(&imageCount0);
53 testassert(names);
54 free(names);
55
56 void *bundle = dlopen("unload2.bundle", RTLD_LAZY);
57 testassert(bundle);
58
59 names = objc_copyImageNames(&imageCount);
60 testassert(names);
61 testassert(imageCount == imageCount0 + 1);
62 testassert(hasName(names, "unload2.bundle"));
63 free(names);
64
65 Class small = objc_getClass("SmallClass");
66 Class big = objc_getClass("BigClass");
67 testassert(small);
68 testassert(big);
69
70 name = class_getImageName(small);
71 testassert(name);
72 testassert(strstr(name, "unload2.bundle"));
73 name = class_getImageName(big);
74 testassert(name);
75 testassert(strstr(name, "unload2.bundle"));
76
77 id o1 = [small new];
78 id o2 = [big new];
79 testassert(o1);
80 testassert(o2);
81
82 // give BigClass and BigClass->isa large method caches (4692641)
83 // Flush caches part way through to test large empty caches.
84 for (i = 0; i < 3000; i++) {
85 sprintf(buf, "method_%d", i);
86 SEL sel = sel_registerName(buf);
87 ((void(*)(id, SEL))objc_msgSend)(o2, sel);
88 ((void(*)(id, SEL))objc_msgSend)(object_getClass(o2), sel);
89 }
90 _objc_flush_caches(object_getClass(o2));
91 for (i = 0; i < 17000; i++) {
92 sprintf(buf, "method_%d", i);
93 SEL sel = sel_registerName(buf);
94 ((void(*)(id, SEL))objc_msgSend)(o2, sel);
95 ((void(*)(id, SEL))objc_msgSend)(object_getClass(o2), sel);
96 }
97
98 RELEASE_VAR(o1);
99 RELEASE_VAR(o2);
100
101 testcollect();
102
103 int err = dlclose(bundle);
104 testassert(err == 0);
105 err = dlclose(bundle);
106 testassert(err == -1); // already closed
107
108 testassert(objc_getClass("SmallClass") == NULL);
109 testassert(objc_getClass("BigClass") == NULL);
110
111 names = objc_copyImageNames(&imageCount);
112 testassert(names);
113 testassert(imageCount == imageCount0);
114 testassert(! hasName(names, "unload2.bundle"));
115 free(names);
116
117 // these selectors came from the bundle
118 testassert(0 == strcmp("unload2_instance_method", sel_getName(sel_registerName("unload2_instance_method"))));
119 testassert(0 == strcmp("unload2_category_method", sel_getName(sel_registerName("unload2_category_method"))));
120
121 // This protocol came from the bundle.
122 // It isn't unloaded cleanly (rdar://20664713), but neither
123 // may it cause the protocol table to crash after unloading.
124 testassert(objc_getProtocol("SmallProtocol"));
125 }
126
127
128 int main()
129 {
130 // fixme object_dispose() not aggressive enough?
131 if (objc_collectingEnabled()) succeed(__FILE__);
132
133 objc_setForwardHandler((void*)&forward_handler, (void*)&forward_handler);
134
135 #if defined(__arm__) || defined(__arm64__)
136 int count = 10;
137 #else
138 int count = is_guardmalloc() ? 10 : 100;
139 #endif
140
141 cycle();
142 #if __LP64__
143 // fixme heap use goes up 512 bytes after the 2nd cycle only - bad or not?
144 cycle();
145 #endif
146
147 leak_mark();
148 while (count--) {
149 cycle();
150 }
151 leak_check(0);
152
153 // 5359412 Make sure dylibs with nothing other than image_info can close
154 void *dylib = dlopen("unload3.dylib", RTLD_LAZY);
155 testassert(dylib);
156 int err = dlclose(dylib);
157 testassert(err == 0);
158 err = dlclose(dylib);
159 testassert(err == -1); // already closed
160
161 // Make sure dylibs with real objc content cannot close
162 dylib = dlopen("unload4.dylib", RTLD_LAZY);
163 testassert(dylib);
164 err = dlclose(dylib);
165 testassert(err == 0);
166 err = dlclose(dylib);
167 testassert(err == 0); // dlopen from libobjc itself
168 err = dlclose(dylib);
169 testassert(err == -1); // already closed
170
171 succeed(__FILE__);
172 }
173
174 #endif