File indexing completed on 2024-05-05 05:44:15
0001 /* 0002 SPDX-FileCopyrightText: 2021 Milian Wolff <mail@milianw.de> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "suppressions.h" 0008 0009 #include <cstring> 0010 #include <fstream> 0011 #include <iostream> 0012 0013 #include <boost/algorithm/string/trim.hpp> 0014 0015 namespace { 0016 std::vector<std::string> parseSuppressionsFile(std::istream& input) 0017 { 0018 std::vector<std::string> ret; 0019 std::string line; 0020 while (std::getline(input, line)) { 0021 auto suppression = parseSuppression(line); 0022 if (!suppression.empty()) { 0023 ret.push_back(std::move(suppression)); 0024 } 0025 } 0026 return ret; 0027 } 0028 0029 /** 0030 * This function is based on the TemplateMatch function found in 0031 * llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp 0032 * The code was licensed under Apache License v2.0 with LLVM Exceptions 0033 */ 0034 bool TemplateMatch(const char* templ, const char* str) 0035 { 0036 if ((!str) || str[0] == 0) 0037 return false; 0038 bool start = false; 0039 if (templ && templ[0] == '^') { 0040 start = true; 0041 templ++; 0042 } 0043 bool asterisk = false; 0044 while (templ && templ[0]) { 0045 if (templ[0] == '*') { 0046 templ++; 0047 start = false; 0048 asterisk = true; 0049 continue; 0050 } 0051 if (templ[0] == '$') 0052 return str[0] == 0 || asterisk; 0053 if (str[0] == 0) 0054 return false; 0055 char* tpos = (char*)strchr(templ, '*'); 0056 char* tpos1 = (char*)strchr(templ, '$'); 0057 if ((!tpos) || (tpos1 && tpos1 < tpos)) 0058 tpos = tpos1; 0059 if (tpos) 0060 tpos[0] = 0; 0061 const char* str0 = str; 0062 const char* spos = strstr(str, templ); 0063 str = spos + strlen(templ); 0064 templ = tpos; 0065 if (tpos) 0066 tpos[0] = tpos == tpos1 ? '$' : '*'; 0067 if (!spos) 0068 return false; 0069 if (start && spos != str0) 0070 return false; 0071 start = false; 0072 asterisk = false; 0073 } 0074 return true; 0075 } 0076 } 0077 0078 std::string parseSuppression(std::string line) 0079 { 0080 boost::trim(line, std::locale::classic()); 0081 if (line.empty() || line[0] == '#') { 0082 // comment 0083 return {}; 0084 } else if (line.compare(0, 5, "leak:") == 0) { 0085 return line.substr(5); 0086 } 0087 std::cerr << "invalid suppression line: " << line << '\n'; 0088 return {}; 0089 } 0090 0091 std::vector<std::string> parseSuppressions(const std::string& suppressionFile, bool* ok) 0092 { 0093 if (ok) { 0094 *ok = true; 0095 } 0096 0097 if (suppressionFile.empty()) { 0098 return {}; 0099 } 0100 0101 auto stream = std::ifstream(suppressionFile); 0102 if (!stream.is_open()) { 0103 std::cerr << "failed to open suppression file: " << suppressionFile << '\n'; 0104 if (ok) { 0105 *ok = false; 0106 } 0107 return {}; 0108 } 0109 0110 return parseSuppressionsFile(stream); 0111 } 0112 0113 bool matchesSuppression(const std::string& suppression, const std::string& haystack) 0114 { 0115 return suppression == haystack || TemplateMatch(suppression.c_str(), haystack.c_str()); 0116 } 0117 0118 std::vector<Suppression> builtinSuppressions() 0119 { 0120 return { 0121 // libc 0122 {"__nss_module_allocate", 0, 0}, 0123 {"__gconv_read_conf", 0, 0}, 0124 {"__new_exitfn", 0, 0}, 0125 {"tzset_internal", 0, 0}, 0126 // dynamic linker 0127 {"dl_open_worker", 0, 0}, 0128 // glib event loop 0129 {"g_main_context_new", 0, 0}, 0130 {"g_main_context_new", 0, 0}, 0131 {"g_thread_self", 0, 0}, 0132 }; 0133 }