//===-- sanitizer_libignore.cc --------------------------------------------===// // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" #if SANITIZER_LINUX #include "sanitizer_libignore.h" #include "sanitizer_flags.h" #include "sanitizer_procmaps.h" namespace __sanitizer { LibIgnore::LibIgnore(LinkerInitialized) { } void LibIgnore::Init(const SuppressionContext &supp) { BlockingMutexLock lock(&mutex_); CHECK_EQ(count_, 0); const uptr n = supp.SuppressionCount(); for (uptr i = 0; i < n; i++) { const Suppression *s = supp.SuppressionAt(i); if (s->type != SuppressionLib) continue; if (count_ >= kMaxLibs) { Report("%s: too many called_from_lib suppressions (max: %d)\n", SanitizerToolName, kMaxLibs); Die(); } Lib *lib = &libs_[count_++]; lib->templ = internal_strdup(s->templ); lib->name = 0; lib->loaded = false; } } void LibIgnore::OnLibraryLoaded(const char *name) { BlockingMutexLock lock(&mutex_); // Try to match suppressions with symlink target. InternalScopedBuffer buf(4096); if (name != 0 && internal_readlink(name, buf.data(), buf.size() - 1) > 0 && buf.data()[0]) { for (uptr i = 0; i < count_; i++) { Lib *lib = &libs_[i]; if (!lib->loaded && lib->real_name == 0 && TemplateMatch(lib->templ, name)) lib->real_name = internal_strdup(buf.data()); } } // Scan suppressions list and find newly loaded and unloaded libraries. MemoryMappingLayout proc_maps(/*cache_enabled*/false); InternalScopedBuffer module(4096); for (uptr i = 0; i < count_; i++) { Lib *lib = &libs_[i]; bool loaded = false; proc_maps.Reset(); uptr b, e, off, prot; while (proc_maps.Next(&b, &e, &off, module.data(), module.size(), &prot)) { if ((prot & MemoryMappingLayout::kProtectionExecute) == 0) continue; if (TemplateMatch(lib->templ, module.data()) || (lib->real_name != 0 && internal_strcmp(lib->real_name, module.data()) == 0)) { if (loaded) { Report("%s: called_from_lib suppression '%s' is matched against" " 2 libraries: '%s' and '%s'\n", SanitizerToolName, lib->templ, lib->name, module.data()); Die(); } loaded = true; if (lib->loaded) continue; if (common_flags()->verbosity) Report("Matched called_from_lib suppression '%s' against library" " '%s'\n", lib->templ, module.data()); lib->loaded = true; lib->name = internal_strdup(module.data()); const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed); code_ranges_[idx].begin = b; code_ranges_[idx].end = e; atomic_store(&loaded_count_, idx + 1, memory_order_release); } } if (lib->loaded && !loaded) { Report("%s: library '%s' that was matched against called_from_lib" " suppression '%s' is unloaded\n", SanitizerToolName, lib->name, lib->templ); Die(); } } } void LibIgnore::OnLibraryUnloaded() { OnLibraryLoaded(0); } } // namespace __sanitizer #endif // #if SANITIZER_LINUX