summaryrefslogtreecommitdiff
path: root/lib/sanitizer_common/sanitizer_libignore.cc
blob: 49c4ba4294922ba3734d293ff07bb30779de373a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//===-- sanitizer_libignore.cc --------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "sanitizer_platform.h"

#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \
    SANITIZER_NETBSD || SANITIZER_OPENBSD

#include "sanitizer_libignore.h"
#include "sanitizer_flags.h"
#include "sanitizer_posix.h"
#include "sanitizer_procmaps.h"

namespace __sanitizer {

LibIgnore::LibIgnore(LinkerInitialized) {
}

void LibIgnore::AddIgnoredLibrary(const char *name_templ) {
  BlockingMutexLock lock(&mutex_);
  if (count_ >= kMaxLibs) {
    Report("%s: too many ignored libraries (max: %d)\n", SanitizerToolName,
           kMaxLibs);
    Die();
  }
  Lib *lib = &libs_[count_++];
  lib->templ = internal_strdup(name_templ);
  lib->name = nullptr;
  lib->real_name = nullptr;
  lib->loaded = false;
}

void LibIgnore::OnLibraryLoaded(const char *name) {
  BlockingMutexLock lock(&mutex_);
  // Try to match suppressions with symlink target.
  InternalScopedString buf(kMaxPathLength);
  if (name && internal_readlink(name, buf.data(), buf.size() - 1) > 0 &&
      buf[0]) {
    for (uptr i = 0; i < count_; i++) {
      Lib *lib = &libs_[i];
      if (!lib->loaded && (!lib->real_name) &&
          TemplateMatch(lib->templ, name))
        lib->real_name = internal_strdup(buf.data());
    }
  }

  // Scan suppressions list and find newly loaded and unloaded libraries.
  ListOfModules modules;
  modules.init();
  for (uptr i = 0; i < count_; i++) {
    Lib *lib = &libs_[i];
    bool loaded = false;
    for (const auto &mod : modules) {
      for (const auto &range : mod.ranges()) {
        if (!range.executable)
          continue;
        if (!TemplateMatch(lib->templ, mod.full_name()) &&
            !(lib->real_name &&
            internal_strcmp(lib->real_name, mod.full_name()) == 0))
          continue;
        if (loaded) {
          Report("%s: called_from_lib suppression '%s' is matched against"
                 " 2 libraries: '%s' and '%s'\n",
                 SanitizerToolName, lib->templ, lib->name, mod.full_name());
          Die();
        }
        loaded = true;
        if (lib->loaded)
          continue;
        VReport(1,
                "Matched called_from_lib suppression '%s' against library"
                " '%s'\n",
                lib->templ, mod.full_name());
        lib->loaded = true;
        lib->name = internal_strdup(mod.full_name());
        const uptr idx =
            atomic_load(&ignored_ranges_count_, memory_order_relaxed);
        CHECK_LT(idx, ARRAY_SIZE(ignored_code_ranges_));
        ignored_code_ranges_[idx].begin = range.beg;
        ignored_code_ranges_[idx].end = range.end;
        atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release);
        break;
      }
    }
    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();
    }
  }

  // Track instrumented ranges.
  if (track_instrumented_libs_) {
    for (const auto &mod : modules) {
      if (!mod.instrumented())
        continue;
      for (const auto &range : mod.ranges()) {
        if (!range.executable)
          continue;
        if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1))
          continue;
        VReport(1, "Adding instrumented range %p-%p from library '%s'\n",
                range.beg, range.end, mod.full_name());
        const uptr idx =
            atomic_load(&instrumented_ranges_count_, memory_order_relaxed);
        CHECK_LT(idx, ARRAY_SIZE(instrumented_code_ranges_));
        instrumented_code_ranges_[idx].begin = range.beg;
        instrumented_code_ranges_[idx].end = range.end;
        atomic_store(&instrumented_ranges_count_, idx + 1,
                     memory_order_release);
      }
    }
  }
}

void LibIgnore::OnLibraryUnloaded() {
  OnLibraryLoaded(nullptr);
}

} // namespace __sanitizer

#endif  // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC ||
        // SANITIZER_NETBSD