Bug Summary

File:projects/compiler-rt/lib/cfi/cfi.cc
Warning:line 231, column 9
Access to field 'st_name' results in a dereference of a null pointer (loaded from variable 'p')

Annotated Source Code

1//===-------- cfi.cc ------------------------------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the runtime support for the cross-DSO CFI.
11//
12//===----------------------------------------------------------------------===//
13
14#include <assert.h>
15#include <elf.h>
16#include <link.h>
17#include <string.h>
18#include <sys/mman.h>
19
20typedef ElfW(Phdr)Elf64_Phdr Elf_Phdr;
21typedef ElfW(Ehdr)Elf64_Ehdr Elf_Ehdr;
22
23#include "interception/interception.h"
24#include "sanitizer_common/sanitizer_common.h"
25#include "sanitizer_common/sanitizer_flag_parser.h"
26#include "ubsan/ubsan_init.h"
27#include "ubsan/ubsan_flags.h"
28
29#ifdef CFI_ENABLE_DIAG1
30#include "ubsan/ubsan_handlers.h"
31#endif
32
33using namespace __sanitizer;
34
35namespace __cfi {
36
37#define kCfiShadowLimitsStorageSize4096 4096 // 1 page
38// Lets hope that the data segment is mapped with 4K pages.
39// The pointer to the cfi shadow region is stored at the start of this page.
40// The rest of the page is unused and re-mapped read-only.
41static union {
42 char space[kCfiShadowLimitsStorageSize4096];
43 struct {
44 uptr start;
45 uptr size;
46 } limits;
47} cfi_shadow_limits_storage
48 __attribute__((aligned(kCfiShadowLimitsStorageSize4096)));
49static constexpr uptr kShadowGranularity = 12;
50static constexpr uptr kShadowAlign = 1UL << kShadowGranularity; // 4096
51
52static constexpr uint16_t kInvalidShadow = 0;
53static constexpr uint16_t kUncheckedShadow = 0xFFFFU;
54
55// Get the start address of the CFI shadow region.
56uptr GetShadow() {
57 return cfi_shadow_limits_storage.limits.start;
58}
59
60uptr GetShadowSize() {
61 return cfi_shadow_limits_storage.limits.size;
62}
63
64// This will only work while the shadow is not allocated.
65void SetShadowSize(uptr size) {
66 cfi_shadow_limits_storage.limits.size = size;
67}
68
69uptr MemToShadowOffset(uptr x) {
70 return (x >> kShadowGranularity) << 1;
71}
72
73uint16_t *MemToShadow(uptr x, uptr shadow_base) {
74 return (uint16_t *)(shadow_base + MemToShadowOffset(x));
75}
76
77typedef int (*CFICheckFn)(u64, void *, void *);
78
79// This class reads and decodes the shadow contents.
80class ShadowValue {
81 uptr addr;
82 uint16_t v;
83 explicit ShadowValue(uptr addr, uint16_t v) : addr(addr), v(v) {}
84
85public:
86 bool is_invalid() const { return v == kInvalidShadow; }
87
88 bool is_unchecked() const { return v == kUncheckedShadow; }
89
90 CFICheckFn get_cfi_check() const {
91 assert(!is_invalid() && !is_unchecked())((!is_invalid() && !is_unchecked()) ? static_cast<
void> (0) : __assert_fail ("!is_invalid() && !is_unchecked()"
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 91, __PRETTY_FUNCTION__))
;
92 uptr aligned_addr = addr & ~(kShadowAlign - 1);
93 uptr p = aligned_addr - (((uptr)v - 1) << kShadowGranularity);
94 return reinterpret_cast<CFICheckFn>(p);
95 }
96
97 // Load a shadow value for the given application memory address.
98 static const ShadowValue load(uptr addr) {
99 uptr shadow_base = GetShadow();
100 uptr shadow_offset = MemToShadowOffset(addr);
101 if (shadow_offset > GetShadowSize())
102 return ShadowValue(addr, kInvalidShadow);
103 else
104 return ShadowValue(
105 addr, *reinterpret_cast<uint16_t *>(shadow_base + shadow_offset));
106 }
107};
108
109class ShadowBuilder {
110 uptr shadow_;
111
112public:
113 // Allocate a new empty shadow (for the entire address space) on the side.
114 void Start();
115 // Mark the given address range as unchecked.
116 // This is used for uninstrumented libraries like libc.
117 // Any CFI check with a target in that range will pass.
118 void AddUnchecked(uptr begin, uptr end);
119 // Mark the given address range as belonging to a library with the given
120 // cfi_check function.
121 void Add(uptr begin, uptr end, uptr cfi_check);
122 // Finish shadow construction. Atomically switch the current active shadow
123 // region with the newly constructed one and deallocate the former.
124 void Install();
125};
126
127void ShadowBuilder::Start() {
128 shadow_ = (uptr)MmapNoReserveOrDie(GetShadowSize(), "CFI shadow");
129 VReport(1, "CFI: shadow at %zx .. %zx\n", shadow_, shadow_ + GetShadowSize())do { if ((uptr)Verbosity() >= (1)) Report("CFI: shadow at %zx .. %zx\n"
, shadow_, shadow_ + GetShadowSize()); } while (0)
;
130}
131
132void ShadowBuilder::AddUnchecked(uptr begin, uptr end) {
133 uint16_t *shadow_begin = MemToShadow(begin, shadow_);
134 uint16_t *shadow_end = MemToShadow(end - 1, shadow_) + 1;
135 memset(shadow_begin, kUncheckedShadow,
136 (shadow_end - shadow_begin) * sizeof(*shadow_begin));
137}
138
139void ShadowBuilder::Add(uptr begin, uptr end, uptr cfi_check) {
140 assert((cfi_check & (kShadowAlign - 1)) == 0)(((cfi_check & (kShadowAlign - 1)) == 0) ? static_cast<
void> (0) : __assert_fail ("(cfi_check & (kShadowAlign - 1)) == 0"
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 140, __PRETTY_FUNCTION__))
;
141
142 // Don't fill anything below cfi_check. We can not represent those addresses
143 // in the shadow, and must make sure at codegen to place all valid call
144 // targets above cfi_check.
145 begin = Max(begin, cfi_check);
146 uint16_t *s = MemToShadow(begin, shadow_);
147 uint16_t *s_end = MemToShadow(end - 1, shadow_) + 1;
148 uint16_t sv = ((begin - cfi_check) >> kShadowGranularity) + 1;
149 for (; s < s_end; s++, sv++)
150 *s = sv;
151}
152
153#if SANITIZER_LINUX1
154void ShadowBuilder::Install() {
155 MprotectReadOnly(shadow_, GetShadowSize());
156 uptr main_shadow = GetShadow();
157 if (main_shadow) {
158 // Update.
159 void *res = mremap((void *)shadow_, GetShadowSize(), GetShadowSize(),
160 MREMAP_MAYMOVE1 | MREMAP_FIXED2, (void *)main_shadow);
161 CHECK(res != MAP_FAILED)do { __sanitizer::u64 v1 = (u64)((res != ((void *) -1))); __sanitizer
::u64 v2 = (u64)(0); if (__builtin_expect(!!(!(v1 != v2)), 0)
) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 161, "(" "(res != ((void *) -1))" ") " "!=" " (" "0" ")", v1
, v2); } while (false)
;
162 } else {
163 // Initial setup.
164 CHECK_EQ(kCfiShadowLimitsStorageSize, GetPageSizeCached())do { __sanitizer::u64 v1 = (u64)((4096)); __sanitizer::u64 v2
= (u64)((GetPageSizeCached())); if (__builtin_expect(!!(!(v1
== v2)), 0)) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 164, "(" "(4096)" ") " "==" " (" "(GetPageSizeCached())" ")"
, v1, v2); } while (false)
;
165 CHECK_EQ(0, GetShadow())do { __sanitizer::u64 v1 = (u64)((0)); __sanitizer::u64 v2 = (
u64)((GetShadow())); if (__builtin_expect(!!(!(v1 == v2)), 0)
) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 165, "(" "(0)" ") " "==" " (" "(GetShadow())" ")", v1, v2);
} while (false)
;
166 cfi_shadow_limits_storage.limits.start = shadow_;
167 MprotectReadOnly((uptr)&cfi_shadow_limits_storage,
168 sizeof(cfi_shadow_limits_storage));
169 CHECK_EQ(shadow_, GetShadow())do { __sanitizer::u64 v1 = (u64)((shadow_)); __sanitizer::u64
v2 = (u64)((GetShadow())); if (__builtin_expect(!!(!(v1 == v2
)), 0)) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 169, "(" "(shadow_)" ") " "==" " (" "(GetShadow())" ")", v1
, v2); } while (false)
;
170 }
171}
172#else
173#error not implemented
174#endif
175
176// This is a workaround for a glibc bug:
177// https://sourceware.org/bugzilla/show_bug.cgi?id=15199
178// Other platforms can, hopefully, just do
179// dlopen(RTLD_NOLOAD | RTLD_LAZY)
180// dlsym("__cfi_check").
181uptr find_cfi_check_in_dso(dl_phdr_info *info) {
182 const ElfW(Dyn)Elf64_Dyn *dynamic = nullptr;
183 for (int i = 0; i < info->dlpi_phnum; ++i) {
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
5
Assuming the condition is true
6
Loop condition is true. Entering loop body
184 if (info->dlpi_phdr[i].p_type == PT_DYNAMIC2) {
3
Assuming the condition is false
4
Taking false branch
7
Assuming the condition is true
8
Taking true branch
185 dynamic =
186 (const ElfW(Dyn)Elf64_Dyn *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
187 break;
9
Execution continues on line 190
188 }
189 }
190 if (!dynamic) return 0;
10
Assuming 'dynamic' is non-null
11
Taking false branch
191 uptr strtab = 0, symtab = 0, strsz = 0;
12
'symtab' initialized to 0
192 for (const ElfW(Dyn)Elf64_Dyn *p = dynamic; p->d_tag != PT_NULL0; ++p) {
13
Assuming the condition is true
14
Loop condition is true. Entering loop body
19
Assuming the condition is false
20
Loop condition is false. Execution continues on line 201
193 if (p->d_tag == DT_SYMTAB6)
15
Assuming the condition is false
16
Taking false branch
194 symtab = p->d_un.d_ptr;
195 else if (p->d_tag == DT_STRTAB5)
17
Assuming the condition is true
18
Taking true branch
196 strtab = p->d_un.d_ptr;
197 else if (p->d_tag == DT_STRSZ10)
198 strsz = p->d_un.d_ptr;
199 }
200
201 if (symtab > strtab) {
21
Taking false branch
202 VReport(1, "Can not handle: symtab > strtab (%p > %zx)\n", symtab, strtab)do { if ((uptr)Verbosity() >= (1)) Report("Can not handle: symtab > strtab (%p > %zx)\n"
, symtab, strtab); } while (0)
;
203 return 0;
204 }
205
206 // Verify that strtab and symtab are inside of the same LOAD segment.
207 // This excludes VDSO, which has (very high) bogus strtab and symtab pointers.
208 int phdr_idx;
209 for (phdr_idx = 0; phdr_idx < info->dlpi_phnum; phdr_idx++) {
22
Loop condition is true. Entering loop body
210 const Elf_Phdr *phdr = &info->dlpi_phdr[phdr_idx];
211 if (phdr->p_type == PT_LOAD1) {
23
Assuming the condition is true
24
Taking true branch
212 uptr beg = info->dlpi_addr + phdr->p_vaddr;
213 uptr end = beg + phdr->p_memsz;
214 if (strtab >= beg && strtab + strsz < end && symtab >= beg &&
25
Assuming 'symtab' is >= 'beg'
27
Taking true branch
215 symtab < end)
26
Assuming 'symtab' is < 'end'
216 break;
28
Execution continues on line 219
217 }
218 }
219 if (phdr_idx == info->dlpi_phnum) {
29
Taking false branch
220 // Nope, either different segments or just bogus pointers.
221 // Can not handle this.
222 VReport(1, "Can not handle: symtab %p, strtab %zx\n", symtab, strtab)do { if ((uptr)Verbosity() >= (1)) Report("Can not handle: symtab %p, strtab %zx\n"
, symtab, strtab); } while (0)
;
223 return 0;
224 }
225
226 for (const ElfW(Sym)Elf64_Sym *p = (const ElfW(Sym)Elf64_Sym *)symtab; (ElfW(Addr)Elf64_Addr)p < strtab;
30
'p' initialized to a null pointer value
31
Assuming 'p' is < 'strtab'
32
Loop condition is true. Entering loop body
227 ++p) {
228 // There is no reliable way to find the end of the symbol table. In
229 // lld-produces files, there are other sections between symtab and strtab.
230 // Stop looking when the symbol name is not inside strtab.
231 if (p->st_name >= strsz) break;
33
Access to field 'st_name' results in a dereference of a null pointer (loaded from variable 'p')
232 char *name = (char*)(strtab + p->st_name);
233 if (strcmp(name, "__cfi_check") == 0) {
234 assert(p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) ||((p->st_info == (((1) << 4) + ((2) & 0xf)) || p->
st_info == (((2) << 4) + ((2) & 0xf))) ? static_cast
<void> (0) : __assert_fail ("p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) || p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC)"
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 235, __PRETTY_FUNCTION__))
235 p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC))((p->st_info == (((1) << 4) + ((2) & 0xf)) || p->
st_info == (((2) << 4) + ((2) & 0xf))) ? static_cast
<void> (0) : __assert_fail ("p->st_info == ELF32_ST_INFO(STB_GLOBAL, STT_FUNC) || p->st_info == ELF32_ST_INFO(STB_WEAK, STT_FUNC)"
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 235, __PRETTY_FUNCTION__))
;
236 uptr addr = info->dlpi_addr + p->st_value;
237 return addr;
238 }
239 }
240 return 0;
241}
242
243int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *data) {
244 uptr cfi_check = find_cfi_check_in_dso(info);
245 if (cfi_check)
246 VReport(1, "Module '%s' __cfi_check %zx\n", info->dlpi_name, cfi_check)do { if ((uptr)Verbosity() >= (1)) Report("Module '%s' __cfi_check %zx\n"
, info->dlpi_name, cfi_check); } while (0)
;
247
248 ShadowBuilder *b = reinterpret_cast<ShadowBuilder *>(data);
249
250 for (int i = 0; i < info->dlpi_phnum; i++) {
251 const Elf_Phdr *phdr = &info->dlpi_phdr[i];
252 if (phdr->p_type == PT_LOAD1) {
253 // Jump tables are in the executable segment.
254 // VTables are in the non-executable one.
255 // Need to fill shadow for both.
256 // FIXME: reject writable if vtables are in the r/o segment. Depend on
257 // PT_RELRO?
258 uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
259 uptr cur_end = cur_beg + phdr->p_memsz;
260 if (cfi_check) {
261 VReport(1, " %zx .. %zx\n", cur_beg, cur_end)do { if ((uptr)Verbosity() >= (1)) Report(" %zx .. %zx\n"
, cur_beg, cur_end); } while (0)
;
262 b->Add(cur_beg, cur_end, cfi_check);
263 } else {
264 b->AddUnchecked(cur_beg, cur_end);
265 }
266 }
267 }
268 return 0;
269}
270
271// Init or update shadow for the current set of loaded libraries.
272void UpdateShadow() {
273 ShadowBuilder b;
274 b.Start();
275 dl_iterate_phdr(dl_iterate_phdr_cb, &b);
276 b.Install();
277}
278
279void InitShadow() {
280 CHECK_EQ(0, GetShadow())do { __sanitizer::u64 v1 = (u64)((0)); __sanitizer::u64 v2 = (
u64)((GetShadow())); if (__builtin_expect(!!(!(v1 == v2)), 0)
) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 280, "(" "(0)" ") " "==" " (" "(GetShadow())" ")", v1, v2);
} while (false)
;
281 CHECK_EQ(0, GetShadowSize())do { __sanitizer::u64 v1 = (u64)((0)); __sanitizer::u64 v2 = (
u64)((GetShadowSize())); if (__builtin_expect(!!(!(v1 == v2))
, 0)) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 281, "(" "(0)" ") " "==" " (" "(GetShadowSize())" ")", v1, v2
); } while (false)
;
282
283 uptr vma = GetMaxVirtualAddress();
284 // Shadow is 2 -> 2**kShadowGranularity.
285 SetShadowSize((vma >> (kShadowGranularity - 1)) + 1);
286 VReport(1, "CFI: VMA size %zx, shadow size %zx\n", vma, GetShadowSize())do { if ((uptr)Verbosity() >= (1)) Report("CFI: VMA size %zx, shadow size %zx\n"
, vma, GetShadowSize()); } while (0)
;
287
288 UpdateShadow();
289}
290
291THREADLOCAL__thread int in_loader;
292BlockingMutex shadow_update_lock(LINKER_INITIALIZED);
293
294void EnterLoader() {
295 if (in_loader == 0) {
296 shadow_update_lock.Lock();
297 }
298 ++in_loader;
299}
300
301void ExitLoader() {
302 CHECK(in_loader > 0)do { __sanitizer::u64 v1 = (u64)((in_loader > 0)); __sanitizer
::u64 v2 = (u64)(0); if (__builtin_expect(!!(!(v1 != v2)), 0)
) __sanitizer::CheckFailed("/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/projects/compiler-rt/lib/cfi/cfi.cc"
, 302, "(" "(in_loader > 0)" ") " "!=" " (" "0" ")", v1, v2
); } while (false)
;
303 --in_loader;
304 UpdateShadow();
305 if (in_loader == 0) {
306 shadow_update_lock.Unlock();
307 }
308}
309
310ALWAYS_INLINEinline __attribute__((always_inline)) void CfiSlowPathCommon(u64 CallSiteTypeId, void *Ptr,
311 void *DiagData) {
312 uptr Addr = (uptr)Ptr;
313 VReport(3, "__cfi_slowpath: %llx, %p\n", CallSiteTypeId, Ptr)do { if ((uptr)Verbosity() >= (3)) Report("__cfi_slowpath: %llx, %p\n"
, CallSiteTypeId, Ptr); } while (0)
;
314 ShadowValue sv = ShadowValue::load(Addr);
315 if (sv.is_invalid()) {
316 VReport(1, "CFI: invalid memory region for a check target: %p\n", Ptr)do { if ((uptr)Verbosity() >= (1)) Report("CFI: invalid memory region for a check target: %p\n"
, Ptr); } while (0)
;
317#ifdef CFI_ENABLE_DIAG1
318 if (DiagData) {
319 __ubsan_handle_cfi_check_fail(
320 reinterpret_cast<__ubsan::CFICheckFailData *>(DiagData), Addr, false);
321 return;
322 }
323#endif
324 Trap();
325 }
326 if (sv.is_unchecked()) {
327 VReport(2, "CFI: unchecked call (shadow=FFFF): %p\n", Ptr)do { if ((uptr)Verbosity() >= (2)) Report("CFI: unchecked call (shadow=FFFF): %p\n"
, Ptr); } while (0)
;
328 return;
329 }
330 CFICheckFn cfi_check = sv.get_cfi_check();
331 VReport(2, "__cfi_check at %p\n", cfi_check)do { if ((uptr)Verbosity() >= (2)) Report("__cfi_check at %p\n"
, cfi_check); } while (0)
;
332 cfi_check(CallSiteTypeId, Ptr, DiagData);
333}
334
335void InitializeFlags() {
336 SetCommonFlagsDefaults();
337#ifdef CFI_ENABLE_DIAG1
338 __ubsan::Flags *uf = __ubsan::flags();
339 uf->SetDefaults();
340#endif
341
342 FlagParser cfi_parser;
343 RegisterCommonFlags(&cfi_parser);
344 cfi_parser.ParseString(GetEnv("CFI_OPTIONS"));
345
346#ifdef CFI_ENABLE_DIAG1
347 FlagParser ubsan_parser;
348 __ubsan::RegisterUbsanFlags(&ubsan_parser, uf);
349 RegisterCommonFlags(&ubsan_parser);
350
351 const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
352 ubsan_parser.ParseString(ubsan_default_options);
353 ubsan_parser.ParseString(GetEnv("UBSAN_OPTIONS"));
354#endif
355
356 InitializeCommonFlags();
357
358 if (Verbosity())
359 ReportUnrecognizedFlags();
360
361 if (common_flags()->help) {
362 cfi_parser.PrintFlagDescriptions();
363 }
364}
365
366} // namespace __cfi
367
368using namespace __cfi;
369
370extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) void
371__cfi_slowpath(u64 CallSiteTypeId, void *Ptr) {
372 CfiSlowPathCommon(CallSiteTypeId, Ptr, nullptr);
373}
374
375#ifdef CFI_ENABLE_DIAG1
376extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default"))) void
377__cfi_slowpath_diag(u64 CallSiteTypeId, void *Ptr, void *DiagData) {
378 CfiSlowPathCommon(CallSiteTypeId, Ptr, DiagData);
379}
380#endif
381
382// Setup shadow for dlopen()ed libraries.
383// The actual shadow setup happens after dlopen() returns, which means that
384// a library can not be a target of any CFI checks while its constructors are
385// running. It's unclear how to fix this without some extra help from libc.
386// In glibc, mmap inside dlopen is not interceptable.
387// Maybe a seccomp-bpf filter?
388// We could insert a high-priority constructor into the library, but that would
389// not help with the uninstrumented libraries.
390INTERCEPTOR(void*, dlopen, const char *filename, int flag)typedef void* (*dlopen_f)(const char *filename, int flag); namespace
__interception { dlopen_f real_dlopen; } extern "C" void* dlopen
(const char *filename, int flag) __attribute__((weak, alias("__interceptor_"
"dlopen"), visibility("default"))); extern "C" __attribute__
((visibility("default"))) void* __interceptor_dlopen(const char
*filename, int flag)
{
391 EnterLoader();
392 void *handle = REAL(dlopen)__interception::real_dlopen(filename, flag);
393 ExitLoader();
394 return handle;
395}
396
397INTERCEPTOR(int, dlclose, void *handle)typedef int (*dlclose_f)(void *handle); namespace __interception
{ dlclose_f real_dlclose; } extern "C" int dlclose(void *handle
) __attribute__((weak, alias("__interceptor_" "dlclose"), visibility
("default"))); extern "C" __attribute__((visibility("default"
))) int __interceptor_dlclose(void *handle)
{
398 EnterLoader();
399 int res = REAL(dlclose)__interception::real_dlclose(handle);
400 ExitLoader();
401 return res;
402}
403
404extern "C" SANITIZER_INTERFACE_ATTRIBUTE__attribute__((visibility("default")))
405#if !SANITIZER_CAN_USE_PREINIT_ARRAY1
406// On ELF platforms, the constructor is invoked using .preinit_array (see below)
407__attribute__((constructor(0)))
408#endif
409void __cfi_init() {
410 SanitizerToolName = "CFI";
411 InitializeFlags();
412 InitShadow();
413
414 INTERCEPT_FUNCTION(dlopen)::__interception::GetRealFunctionAddress( "dlopen", (::__interception
::uptr *)&__interception::real_dlopen, (::__interception::
uptr) & (dlopen), (::__interception::uptr) & __interceptor_dlopen
)
;
415 INTERCEPT_FUNCTION(dlclose)::__interception::GetRealFunctionAddress( "dlclose", (::__interception
::uptr *)&__interception::real_dlclose, (::__interception
::uptr) & (dlclose), (::__interception::uptr) & __interceptor_dlclose
)
;
416
417#ifdef CFI_ENABLE_DIAG1
418 __ubsan::InitAsPlugin();
419#endif
420}
421
422#if SANITIZER_CAN_USE_PREINIT_ARRAY1
423// On ELF platforms, run cfi initialization before any other constructors.
424// On other platforms we use the constructor attribute to arrange to run our
425// initialization early.
426extern "C" {
427__attribute__((section(".preinit_array"),
428 used)) void (*__cfi_preinit)(void) = __cfi_init;
429}
430#endif