]> git.saurik.com Git - apple/objc4.git/blob - test/unload.m
objc4-437.3.tar.gz
[apple/objc4.git] / test / unload.m
1 #include "test.h"
2 #include <objc/runtime.h>
3 #include <dlfcn.h>
4 #include <unistd.h>
5
6 #include "unload.h"
7
8 static BOOL hasName(const char * const *names, const char *query)
9 {
10 const char *name;
11 while ((name = *names++)) {
12 if (strstr(name, query)) return YES;
13 }
14
15 return NO;
16 }
17
18 void cycle(void)
19 {
20 int i;
21 char buf[100];
22 unsigned int imageCount, imageCount0;
23 const char **names;
24 const char *name;
25
26 names = objc_copyImageNames(&imageCount0);
27 testassert(names);
28 free(names);
29
30 void *bundle = dlopen("unload2.out", RTLD_LAZY);
31 testassert(bundle);
32
33 names = objc_copyImageNames(&imageCount);
34 testassert(names);
35 testassert(imageCount == imageCount0 + 1);
36 testassert(hasName(names, "unload2.out"));
37 free(names);
38
39 Class small = objc_getClass("SmallClass");
40 Class big = objc_getClass("BigClass");
41 testassert(small);
42 testassert(big);
43
44 name = class_getImageName(small);
45 testassert(name);
46 testassert(strstr(name, "unload2.out"));
47 name = class_getImageName(big);
48 testassert(name);
49 testassert(strstr(name, "unload2.out"));
50
51 id o1 = [small new];
52 id o2 = [big new];
53 testassert(o1);
54 testassert(o2);
55
56 // give BigClass and BigClass->isa large method caches (4692641)
57 for (i = 0; i < 10000; i++) {
58 sprintf(buf, "method_%d", i);
59 SEL sel = sel_registerName(buf);
60 objc_msgSend(o2, sel);
61 objc_msgSend(o2->isa, sel);
62 }
63
64 [o1 free];
65 [o2 free];
66
67 if (objc_collecting_enabled()) objc_collect(OBJC_EXHAUSTIVE_COLLECTION | OBJC_WAIT_UNTIL_DONE);
68
69 int err = dlclose(bundle);
70 testassert(err == 0);
71 err = dlclose(bundle);
72 testassert(err == -1); // already closed
73
74 testassert(!objc_getClass("SmallClass"));
75 testassert(!objc_getClass("BigClass"));
76
77 names = objc_copyImageNames(&imageCount);
78 testassert(names);
79 testassert(imageCount == imageCount0);
80 testassert(! hasName(names, "unload2.out"));
81 free(names);
82
83 // these selectors came from the bundle
84 testassert(0 == strcmp("unload2_instance_method", sel_getName(sel_registerName("unload2_instance_method"))));
85 testassert(0 == strcmp("unload2_category_method", sel_getName(sel_registerName("unload2_category_method"))));
86 }
87
88 int main()
89 {
90 // fixme object_dispose() not aggressive enough?
91 if (objc_collecting_enabled()) succeed(__FILE__);
92
93 int count = 100;
94
95 cycle();
96 #if __LP64__
97 // fixme heap use goes up 512 bytes after the 2nd cycle only - bad or not?
98 cycle();
99 #endif
100
101 leak_mark();
102 while (count--) {
103 cycle();
104 }
105 leak_check(0);
106
107 // 5359412 Make sure dylibs with nothing other than image_info can close
108 void *dylib = dlopen("unload3.out", RTLD_LAZY);
109 testassert(dylib);
110 int err = dlclose(dylib);
111 testassert(err == 0);
112 err = dlclose(dylib);
113 testassert(err == -1); // already closed
114
115 // Make sure dylibs with real objc content cannot close
116 dylib = dlopen("unload4.out", RTLD_LAZY);
117 testassert(dylib);
118 err = dlclose(dylib);
119 testassert(err == 0);
120 err = dlclose(dylib);
121 testassert(err == 0); // dlopen from libobjc itself
122 err = dlclose(dylib);
123 testassert(err == -1); // already closed
124
125 succeed(__FILE__);
126 }