dyld-732.8.tar.gz
[apple/dyld.git] / testing / test-cases / _dyld_register_for_image_loads.dtest / main.cxx
1
2 // BUILD: $CC foo.c -dynamiclib -install_name $RUN_DIR/libfoo.dylib -o $BUILD_DIR/libfoo.dylib
3 // BUILD: $CXX main.cxx -o $BUILD_DIR/dyld_register_test.exe $BUILD_DIR/libfoo.dylib -DRUN_DIR="$RUN_DIR"
4 // BUILD: $CC foo.c -dynamiclib -install_name $RUN_DIR/libfoo2.dylib -o $BUILD_DIR/libfoo2.dylib
5 // BUILD: $CC foo.c -bundle -o $BUILD_DIR/foo.bundle
6 // BUILD: $CC up.c -dynamiclib -install_name $RUN_DIR/libup.dylib -o $BUILD_DIR/libup.dylib
7 // BUILD: $CC baz.c -dynamiclib -install_name $RUN_DIR/libbaz.dylib -o $BUILD_DIR/libbaz.dylib $BUILD_DIR/libup.dylib
8 // BUILD: $CC bar.c -dynamiclib -install_name $RUN_DIR/libbar.dylib -o $BUILD_DIR/libbar.dylib -Wl,-upward_library,$BUILD_DIR/libup.dylib -DRUN_DIR="$RUN_DIR"
9
10 // RUN: ./dyld_register_test.exe
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <dlfcn.h>
15 #include <mach-o/dyld.h>
16 #include <mach-o/dyld_priv.h>
17
18 #include <unordered_set>
19
20 extern "C" void foo();
21
22 extern mach_header __dso_handle;
23
24 static std::unordered_set<const mach_header*> sCurrentImages;
25 static bool expectedUnloadableState = false;
26
27 static void notify(const mach_header* mh, const char* path, bool unloadable)
28 {
29 fprintf(stderr, "mh=%p, path=%s, unloadable=%d\n", mh, path, unloadable);
30 if ( sCurrentImages.count(mh) != 0 ) {
31 printf("[FAIL] _dyld_register_for_image_loads: notified twice about %p\n", mh);
32 exit(0);
33 }
34 sCurrentImages.insert(mh);
35
36 const char* leaf = strrchr(path, '/');
37 if ( unloadable != expectedUnloadableState ) {
38 printf("[FAIL] _dyld_register_for_image_loads: image incorrectly marked unloadable(%s) but expected unloadable(%s) %p %s\n",
39 unloadable ? "true" : "true", expectedUnloadableState ? "true" : "false", mh, path);
40 exit(0);
41 }
42 }
43
44
45 int main()
46 {
47 printf("[BEGIN] _dyld_register_for_image_loads\n");
48
49 // Initially all images must not be unloadable as they are directly linked to the main executable
50 expectedUnloadableState = false;
51 _dyld_register_for_image_loads(&notify);
52
53 // verify we were notified about already loaded images
54 if ( sCurrentImages.count(&__dso_handle) == 0 ) {
55 printf("[FAIL] _dyld_register_for_image_loads() did not notify us about main executable\n");
56 exit(0);
57 }
58 const mach_header* libSysMH = dyld_image_header_containing_address((void*)&printf);
59 if ( sCurrentImages.count(libSysMH) == 0 ) {
60 printf("[FAIL] _dyld_register_for_image_loads() did not notify us about libsystem_c.dylib\n");
61 exit(0);
62 }
63 const mach_header* libFoo = dyld_image_header_containing_address((void*)&foo);
64 if ( sCurrentImages.count(libFoo) == 0 ) {
65 printf("[FAIL] _dyld_register_for_image_loads() did not notify us about libfoo.dylib\n");
66 exit(0);
67 }
68
69 // These dlopen's can be unloaded
70 expectedUnloadableState = true;
71
72 // verify we were notified about load of libfoo2.dylib
73 void* handle2 = dlopen(RUN_DIR "/libfoo2.dylib", RTLD_FIRST);
74 if ( handle2 == NULL ) {
75 printf("[FAIL] dlopen(\"%s\") failed with: %s\n", RUN_DIR "/libfoo.dylib", dlerror());
76 exit(0);
77 }
78 const void* libfoo2Foo = dlsym(handle2, "foo");
79 const mach_header* libfoo2MH = dyld_image_header_containing_address(libfoo2Foo);
80 if ( sCurrentImages.count(libfoo2MH) == 0 ) {
81 printf("[FAIL] _dyld_register_for_image_loads() did not notify us about libfoo2.dylib\n");
82 exit(0);
83 }
84
85 // verify we were notified about load of foo.bundle
86 void* handleB = dlopen(RUN_DIR "/foo.bundle", RTLD_FIRST);
87 if ( handleB == NULL ) {
88 printf("[FAIL] dlopen(\"%s\") failed with: %s\n", RUN_DIR "/foo.bundle", dlerror());
89 exit(0);
90 }
91 const void* libfooBFoo = dlsym(handle2, "foo");
92 const mach_header* libfooB = dyld_image_header_containing_address(libfooBFoo);
93 if ( sCurrentImages.count(libfooB) == 0 ) {
94 printf("[FAIL] _dyld_register_for_image_loads() did not notify us about foo.bundle\n");
95 exit(0);
96 }
97
98 // Upward linking with dlopen may confuse the notifier as we may try to notify twice on the upwardly linked image
99 // We test this with:
100 // libbar upward links libup
101 // libbar also dlopens libbaz
102 // libbaz links libup
103 // We should not get a duplicate notification on libup
104 void* handleBar = dlopen(RUN_DIR "/libbar.dylib", RTLD_FIRST);
105 if ( handleBar == NULL ) {
106 printf("[FAIL] dlopen(\"%s\") failed with: %s\n", RUN_DIR "/libbar.dylib", dlerror());
107 exit(0);
108 }
109
110 printf("[PASS] _dyld_register_for_image_loads\n");
111 return 0;
112 }
113