1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // A crazy linker test to check that paths added with
6 // crazy_context_add_search_path() or
7 // crazy_context_add_search_path_from_address()
8 // have higher priority than the default ones (from LD_LIBRARY_PATH).
9 //
10 // This requires creating two temporary directories and placing there libraries
11 // with the same name, but different content
12 //
13 //   $TMPDIR1/libfoo.so   -> a copy of libfoo.so that contains the 'Foo' symbol.
14 //   $TMPDIR2/libfoo.so   -> a copy of libfoo2.so that contains the 'Foo2'
15 // symbol.
16 //
17 
18 #include <crazy_linker.h>
19 
20 #include "test_util.h"
21 
22 namespace {
23 
CheckLibraryCantLoad(const char * library_name,crazy_context_t * context)24 void CheckLibraryCantLoad(const char* library_name, crazy_context_t* context) {
25   crazy_library_t* library;
26 
27   if (crazy_library_open(&library, library_name, context))
28     Panic("Could load library %s, expected this not to be possible\n",
29           library_name);
30 }
31 
32 // Loads a library named |library_name| and checks that it contains
33 // the symbols listed in |wanted_symbols|, and none of the symbols
34 // listed in |unwanted_symbols|. After that, close the library and exit.
35 //
36 // Both |wanted_symbols| and |unwanted_symbols| are NULL-terminated
37 // arrays of strings.
CheckLibrary(const char * library_name,const char * const * wanted_symbols,const char * const * unwanted_symbols,crazy_context_t * context)38 void CheckLibrary(const char* library_name,
39                   const char* const* wanted_symbols,
40                   const char* const* unwanted_symbols,
41                   crazy_context_t* context) {
42   crazy_library_t* library;
43 
44   if (!crazy_library_open(&library, library_name, context))
45     Panic("Could not open library %s: %s\n", crazy_context_get_error(context));
46 
47   size_t failures = 0;
48 
49   if (wanted_symbols) {
50     for (; *wanted_symbols; ++wanted_symbols) {
51       const char* symbol_name = *wanted_symbols;
52       void* symbol_addr;
53       if (!crazy_library_find_symbol(library, symbol_name, &symbol_addr)) {
54         fprintf(stderr,
55                 "Could not find symbol '%s' in library '%s'!\n",
56                 symbol_name,
57                 library_name);
58         failures += 1;
59       }
60     }
61   }
62 
63   if (unwanted_symbols) {
64     for (; *unwanted_symbols; ++unwanted_symbols) {
65       const char* symbol_name = *unwanted_symbols;
66       void* symbol_addr;
67       if (crazy_library_find_symbol(library, symbol_name, &symbol_addr)) {
68         fprintf(stderr,
69                 "Found symbol '%s' in library '%s', none expected!\n",
70                 symbol_name,
71                 library_name);
72         failures += 1;
73       }
74     }
75   }
76 
77   if (failures > 0)
78     Panic("Found %d symbol failures in library %s\n", failures, library_name);
79 
80   crazy_library_close(library);
81 }
82 
83 }  // namespace
84 
main()85 int main() {
86   String exe_path = GetCurrentExecutableDirectory();
87 
88   TempDirectory temp_dir_1;
89   TempDirectory temp_dir_2;
90 
91   // List of symbols in original libfoo.so and libfoo2.so, respectively.
92   static const char* const kFooSymbols[] = {"Foo", NULL};
93   static const char* const kFoo2Symbols[] = {"Foo2", NULL};
94 
95   // Copy libfoo.so to $TMPDIR1/libfoo.so
96   CopyFile("libfoo.so", exe_path.c_str(), "libfoo.so", temp_dir_1.path());
97 
98   // Copy libfoo2.so to $TMPDIR2/libfoo.so
99   CopyFile("libfoo2.so", exe_path.c_str(), "libfoo.so", temp_dir_2.path());
100 
101   // Create a new context object.
102   crazy_context_t* context = crazy_context_create();
103   crazy_library_t* library;
104 
105   // Reset search paths to a non-existing directory. Check that the library
106   // can't be loaded.
107   setenv("LD_LIBRARY_PATH", "/this-directory-does-not-exist", 1);
108   crazy_context_reset_search_paths(context);
109   CheckLibraryCantLoad("libfoo.so", context);
110 
111   // Add the search path to the current executable, this should load the
112   // original
113   // libfoo.so.
114   crazy_context_add_search_path_for_address(context, (void*)&main);
115   CheckLibrary("libfoo.so", kFooSymbols, kFoo2Symbols, context);
116 
117   // Reset search paths to use $TMPDIR2 then $TMPDIR1
118   setenv("LD_LIBRARY_PATH", temp_dir_1.path(), 1);
119   crazy_context_reset_search_paths(context);
120   crazy_context_add_search_path(context, temp_dir_2.path());
121 
122   // Check that the copy of libfoo2.so is loaded.
123   CheckLibrary("libfoo.so", kFoo2Symbols, kFooSymbols, context);
124 
125   // Reset search paths to use only $TMPDIR1
126   crazy_context_reset_search_paths(context);
127 
128   // Check that the copy of libfoo.so is loaded.
129   CheckLibrary("libfoo.so", kFooSymbols, kFoo2Symbols, context);
130 
131   crazy_context_destroy(context);
132 
133   return 0;
134 }