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