sanitizer_suppressions.cc 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. //===-- sanitizer_suppressions.cc -----------------------------------------===//
  2. //
  3. // This file is distributed under the University of Illinois Open Source
  4. // License. See LICENSE.TXT for details.
  5. //
  6. //===----------------------------------------------------------------------===//
  7. //
  8. // Suppression parsing/matching code shared between TSan and LSan.
  9. //
  10. //===----------------------------------------------------------------------===//
  11. #include "sanitizer_suppressions.h"
  12. #include "sanitizer_allocator_internal.h"
  13. #include "sanitizer_common.h"
  14. #include "sanitizer_flags.h"
  15. #include "sanitizer_libc.h"
  16. #include "sanitizer_placement_new.h"
  17. namespace __sanitizer {
  18. static const char *const kTypeStrings[SuppressionTypeCount] = {
  19. "none", "race", "mutex", "thread", "signal",
  20. "leak", "called_from_lib", "deadlock", "vptr_check"};
  21. bool TemplateMatch(char *templ, const char *str) {
  22. if (str == 0 || str[0] == 0)
  23. return false;
  24. bool start = false;
  25. if (templ && templ[0] == '^') {
  26. start = true;
  27. templ++;
  28. }
  29. bool asterisk = false;
  30. while (templ && templ[0]) {
  31. if (templ[0] == '*') {
  32. templ++;
  33. start = false;
  34. asterisk = true;
  35. continue;
  36. }
  37. if (templ[0] == '$')
  38. return str[0] == 0 || asterisk;
  39. if (str[0] == 0)
  40. return false;
  41. char *tpos = (char*)internal_strchr(templ, '*');
  42. char *tpos1 = (char*)internal_strchr(templ, '$');
  43. if (tpos == 0 || (tpos1 && tpos1 < tpos))
  44. tpos = tpos1;
  45. if (tpos != 0)
  46. tpos[0] = 0;
  47. const char *str0 = str;
  48. const char *spos = internal_strstr(str, templ);
  49. str = spos + internal_strlen(templ);
  50. templ = tpos;
  51. if (tpos)
  52. tpos[0] = tpos == tpos1 ? '$' : '*';
  53. if (spos == 0)
  54. return false;
  55. if (start && spos != str0)
  56. return false;
  57. start = false;
  58. asterisk = false;
  59. }
  60. return true;
  61. }
  62. ALIGNED(64) static char placeholder[sizeof(SuppressionContext)];
  63. static SuppressionContext *suppression_ctx = 0;
  64. SuppressionContext *SuppressionContext::Get() {
  65. CHECK(suppression_ctx);
  66. return suppression_ctx;
  67. }
  68. void SuppressionContext::InitIfNecessary() {
  69. if (suppression_ctx)
  70. return;
  71. suppression_ctx = new(placeholder) SuppressionContext;
  72. if (common_flags()->suppressions[0] == '\0')
  73. return;
  74. char *suppressions_from_file;
  75. uptr buffer_size;
  76. uptr contents_size =
  77. ReadFileToBuffer(common_flags()->suppressions, &suppressions_from_file,
  78. &buffer_size, 1 << 26 /* max_len */);
  79. if (contents_size == 0) {
  80. Printf("%s: failed to read suppressions file '%s'\n", SanitizerToolName,
  81. common_flags()->suppressions);
  82. Die();
  83. }
  84. suppression_ctx->Parse(suppressions_from_file);
  85. }
  86. bool SuppressionContext::Match(const char *str, SuppressionType type,
  87. Suppression **s) {
  88. can_parse_ = false;
  89. uptr i;
  90. for (i = 0; i < suppressions_.size(); i++)
  91. if (type == suppressions_[i].type &&
  92. TemplateMatch(suppressions_[i].templ, str))
  93. break;
  94. if (i == suppressions_.size()) return false;
  95. *s = &suppressions_[i];
  96. return true;
  97. }
  98. static const char *StripPrefix(const char *str, const char *prefix) {
  99. while (str && *str == *prefix) {
  100. str++;
  101. prefix++;
  102. }
  103. if (!*prefix)
  104. return str;
  105. return 0;
  106. }
  107. void SuppressionContext::Parse(const char *str) {
  108. // Context must not mutate once Match has been called.
  109. CHECK(can_parse_);
  110. const char *line = str;
  111. while (line) {
  112. while (line[0] == ' ' || line[0] == '\t')
  113. line++;
  114. const char *end = internal_strchr(line, '\n');
  115. if (end == 0)
  116. end = line + internal_strlen(line);
  117. if (line != end && line[0] != '#') {
  118. const char *end2 = end;
  119. while (line != end2 && (end2[-1] == ' ' || end2[-1] == '\t'))
  120. end2--;
  121. int type;
  122. for (type = 0; type < SuppressionTypeCount; type++) {
  123. const char *next_char = StripPrefix(line, kTypeStrings[type]);
  124. if (next_char && *next_char == ':') {
  125. line = ++next_char;
  126. break;
  127. }
  128. }
  129. if (type == SuppressionTypeCount) {
  130. Printf("%s: failed to parse suppressions\n", SanitizerToolName);
  131. Die();
  132. }
  133. Suppression s;
  134. s.type = static_cast<SuppressionType>(type);
  135. s.templ = (char*)InternalAlloc(end2 - line + 1);
  136. internal_memcpy(s.templ, line, end2 - line);
  137. s.templ[end2 - line] = 0;
  138. s.hit_count = 0;
  139. s.weight = 0;
  140. suppressions_.push_back(s);
  141. }
  142. if (end[0] == 0)
  143. break;
  144. line = end + 1;
  145. }
  146. }
  147. uptr SuppressionContext::SuppressionCount() const {
  148. return suppressions_.size();
  149. }
  150. const Suppression *SuppressionContext::SuppressionAt(uptr i) const {
  151. CHECK_LT(i, suppressions_.size());
  152. return &suppressions_[i];
  153. }
  154. void SuppressionContext::GetMatched(
  155. InternalMmapVector<Suppression *> *matched) {
  156. for (uptr i = 0; i < suppressions_.size(); i++)
  157. if (suppressions_[i].hit_count)
  158. matched->push_back(&suppressions_[i]);
  159. }
  160. const char *SuppressionTypeString(SuppressionType t) {
  161. CHECK(t < SuppressionTypeCount);
  162. return kTypeStrings[t];
  163. }
  164. } // namespace __sanitizer