Skip to content

Commit a2c6841

Browse files
authored
Improve sanitizer handling (#178)
1 parent 5c0c1da commit a2c6841

File tree

6 files changed

+163
-71
lines changed

6 files changed

+163
-71
lines changed

lib/passes/TypeARTPass.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050

5151
#include <cassert>
5252
#include <cstddef>
53+
#include <llvm/ADT/DenseSet.h>
5354
#include <llvm/Config/llvm-config.h>
55+
#include <llvm/IR/Constant.h>
5456
#include <llvm/Support/Error.h>
5557
#include <memory>
5658
#include <optional>
@@ -283,14 +285,33 @@ class TypeArtPass : public llvm::PassInfoMixin<TypeArtPass> {
283285
}
284286
}
285287

286-
const auto instrumented_function = llvm::count_if(m.functions(), [&](auto& f) { return runOnFunc(f); }) > 0;
288+
llvm::DenseSet<const llvm::Constant*> tor_funcs;
289+
{
290+
const auto collect_funcs = [&tor_funcs](const auto* constant) -> bool {
291+
if (llvm::isa<llvm::Function>(constant)) {
292+
tor_funcs.insert(constant);
293+
}
294+
return false;
295+
};
296+
297+
util::for_each_cdtor("llvm.global_ctors", m, collect_funcs);
298+
util::for_each_cdtor("llvm.global_dtors", m, collect_funcs);
299+
}
300+
301+
const auto instrumented_function = llvm::count_if(m.functions(), [&](auto& f) {
302+
if (tor_funcs.contains(&f)) {
303+
LOG_DEBUG("Function is in LLVM global ctor or dtor " << f.getName())
304+
return false;
305+
}
306+
return runOnFunc(f);
307+
}) > 0;
287308
return instrumented_function || globals_were_instrumented;
288309
}
289310

290311
bool runOnFunc(llvm::Function& f) {
291312
using namespace typeart;
292313

293-
if (f.isDeclaration() || util::starts_with_any_of(f.getName(), "__typeart", "typeart")) {
314+
if (f.isDeclaration() || util::starts_with_any_of(f.getName(), "__typeart", "typeart", "__sanitizer", "__tysan")) {
294315
return false;
295316
}
296317

lib/passes/analysis/MemInstFinder.cpp

Lines changed: 69 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -180,74 +180,75 @@ bool MemInstFinderPass::runOnModule(Module& module) {
180180
auto& globals = mOpsCollector.globals;
181181
NumDetectedGlobals += globals.size();
182182
if (config[config::ConfigStdArgs::analysis_filter_global]) {
183-
globals.erase(llvm::remove_if(
184-
globals,
185-
[&](const auto gdata) { // NOLINT
186-
GlobalVariable* global = gdata.global;
187-
const auto name = global->getName();
188-
189-
LOG_DEBUG("Analyzing global: " << name);
190-
191-
if (name.empty()) {
192-
return true;
193-
}
194-
195-
if (util::starts_with_any_of(name, "llvm.", "__llvm_gcov", "__llvm_gcda", "__profn", "___asan",
196-
"__msan", "__tsan", "__typeart", "_typeart")) {
197-
LOG_DEBUG("Prefixed matched on " << name)
198-
return true;
199-
}
200-
201-
if (global->hasInitializer()) {
202-
auto* ini = global->getInitializer();
203-
std::string ini_name = util::dump(*ini);
204-
205-
if (llvm::StringRef(ini_name).contains("std::ios_base::Init")) {
206-
LOG_DEBUG("std::ios");
207-
return true;
208-
}
209-
}
210-
211-
if (global->hasSection()) {
212-
// for instance, filters:
213-
// a) (Coverage) -fprofile-instr-generate -fcoverage-mapping
214-
// b) (PGO) -fprofile-instr-generate
215-
StringRef Section = global->getSection();
216-
// Globals from llvm.metadata aren't emitted, do not instrument them.
217-
if (Section == "llvm.metadata") {
218-
LOG_DEBUG("metadata");
219-
return true;
220-
}
221-
// Do not instrument globals from special LLVM sections.
222-
if (Section.find("__llvm") != StringRef::npos || Section.find("__LLVM") != StringRef::npos) {
223-
LOG_DEBUG("llvm section");
224-
return true;
225-
}
226-
}
227-
228-
if ((global->getLinkage() == GlobalValue::ExternalLinkage && global->isDeclaration())) {
229-
LOG_DEBUG("Linkage: External");
230-
return true;
231-
}
232-
233-
Type* global_type = global->getValueType();
234-
if (!global_type->isSized()) {
235-
LOG_DEBUG("not sized");
236-
return true;
237-
}
238-
239-
if (global_type->isArrayTy()) {
240-
global_type = global_type->getArrayElementType();
241-
}
242-
if (auto structType = dyn_cast<StructType>(global_type)) {
243-
if (structType->isOpaque()) {
244-
LOG_DEBUG("Encountered opaque struct " << global_type->getStructName() << " - skipping...");
245-
return true;
246-
}
247-
}
248-
return false;
249-
}),
250-
globals.end());
183+
globals.erase(
184+
llvm::remove_if(
185+
globals,
186+
[&](const auto gdata) { // NOLINT
187+
GlobalVariable* global = gdata.global;
188+
const auto name = global->getName();
189+
190+
LOG_DEBUG("Analyzing global: " << name);
191+
192+
if (name.empty()) {
193+
return true;
194+
}
195+
196+
if (util::starts_with_any_of(name, "llvm.", "__llvm_gcov", "__llvm_gcda", "__profn", "___asan", "__msan",
197+
"__tsan", "__typeart", "_typeart", "__tysan", "__dfsan", "__profc")) {
198+
LOG_DEBUG("Prefixed matched on " << name)
199+
return true;
200+
}
201+
202+
if (global->hasInitializer()) {
203+
auto* ini = global->getInitializer();
204+
std::string ini_name = util::dump(*ini);
205+
206+
if (llvm::StringRef(ini_name).contains("std::ios_base::Init")) {
207+
LOG_DEBUG("std::ios");
208+
return true;
209+
}
210+
}
211+
212+
if (global->hasSection()) {
213+
// for instance, filters:
214+
// a) (Coverage) -fprofile-instr-generate -fcoverage-mapping
215+
// b) (PGO) -fprofile-instr-generate
216+
StringRef Section = global->getSection();
217+
// Globals from llvm.metadata aren't emitted, do not instrument them.
218+
if (Section == "llvm.metadata") {
219+
LOG_DEBUG("metadata");
220+
return true;
221+
}
222+
// Do not instrument globals from special LLVM sections.
223+
if (Section.find("__llvm") != StringRef::npos || Section.find("__LLVM") != StringRef::npos) {
224+
LOG_DEBUG("llvm section");
225+
return true;
226+
}
227+
}
228+
229+
if ((global->getLinkage() == GlobalValue::ExternalLinkage && global->isDeclaration())) {
230+
LOG_DEBUG("Linkage: External");
231+
return true;
232+
}
233+
234+
Type* global_type = global->getValueType();
235+
if (!global_type->isSized()) {
236+
LOG_DEBUG("not sized");
237+
return true;
238+
}
239+
240+
if (global_type->isArrayTy()) {
241+
global_type = global_type->getArrayElementType();
242+
}
243+
if (auto structType = dyn_cast<StructType>(global_type)) {
244+
if (structType->isOpaque()) {
245+
LOG_DEBUG("Encountered opaque struct " << global_type->getStructName() << " - skipping...");
246+
return true;
247+
}
248+
}
249+
return false;
250+
}),
251+
globals.end());
251252

252253
const auto beforeCallFilter = globals.size();
253254
NumFilteredGlobals = NumDetectedGlobals - beforeCallFilter;

lib/passes/filter/Matcher.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class FunctionOracleMatcher final : public Matcher {
8888
if (mem_operations.kind(f_name)) {
8989
return MatchResult::ShouldSkip;
9090
}
91-
if (util::starts_with_any_of(f_name_ref, "__ubsan", "__asan", "__msan")) {
91+
if (util::starts_with_any_of(f_name_ref, "__ubsan", "__asan", "__msan", "__tysan", "__dfsan", "__tsan")) {
9292
return MatchResult::ShouldContinue;
9393
}
9494
}

lib/passes/support/Util.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919

2020
#include "llvm/Demangle/Demangle.h"
2121
#include "llvm/IR/Function.h"
22+
#include "llvm/IR/Module.h"
2223
#include "llvm/Support/Regex.h"
2324
#include "llvm/Support/raw_ostream.h"
2425

2526
#include <algorithm>
2627
#include <llvm/ADT/StringRef.h>
28+
#include <llvm/IR/Constants.h>
29+
#include <llvm/IR/Value.h>
2730
#include <string>
2831

2932
namespace typeart::util {
@@ -202,6 +205,27 @@ inline bool ends_with_any_of(llvm::StringRef lhs, StringTy... rhs) {
202205
#endif
203206
}
204207

208+
template <typename Matcher>
209+
void for_each_cdtor(llvm::StringRef name, llvm::Module& module, Matcher&& matching_fn) {
210+
using namespace llvm;
211+
auto* GVCtor = module.getNamedGlobal(name);
212+
if (!GVCtor) {
213+
return;
214+
}
215+
if (Constant* Init = GVCtor->getInitializer()) {
216+
for (Value* OP : Init->operands()) {
217+
auto* const_struct = dyn_cast<ConstantStruct>(OP);
218+
if (!const_struct || const_struct->getNumOperands() < 3) {
219+
continue;
220+
}
221+
222+
if (matching_fn(const_struct->getOperand(1))) {
223+
return;
224+
}
225+
}
226+
}
227+
}
228+
205229
} // namespace typeart::util
206230

207231
#endif /* LIB_UTIL_H_ */
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// clang-format off
2+
// RUN: %clang-cpp -O0 -g -fsanitize=type -emit-llvm -o - -c %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s
3+
// clang-format on
4+
5+
// REQUIRES: llvm-20 || llvm-21
6+
7+
#include <cmath>
8+
9+
int square(float in) {
10+
float num = in * in;
11+
float b = fabs(num);
12+
return 1;
13+
}
14+
15+
// CHECK: TypeArtPass [Heap & Stack]
16+
// CHECK-NEXT: Malloc : 0
17+
// CHECK-NEXT: Free : 0
18+
// CHECK-NEXT: Alloca : 0
19+
// CHECK-NEXT: Global : 0
20+
21+
// CHECK: call void @__tysan_init
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// clang-format off
2+
// RUN: %clang-cpp -O0 -g -fsanitize=type -emit-llvm -o - -c %s | %apply-typeart --typeart-stack=true --typeart-filter=true -S 2>&1 | %filecheck %s
3+
// clang-format on
4+
5+
// REQUIRES: llvm-20 || llvm-21
6+
7+
#include <cmath>
8+
9+
extern void MPI_mock(void*);
10+
11+
int square(float in) {
12+
float num = in * in;
13+
float calc = fabs(in) * num;
14+
MPI_mock((void*)&calc);
15+
return 1;
16+
}
17+
18+
// CHECK: TypeArtPass [Heap & Stack]
19+
// CHECK-NEXT: Malloc : 0
20+
// CHECK-NEXT: Free : 0
21+
// CHECK-NEXT: Alloca : 1
22+
// CHECK-NEXT: Global : 0
23+
24+
// CHECK: @__typeart_alloc_stack(ptr %{{[a-zA-Z0-9]+}},
25+
// CHECK: call void @__tysan_init

0 commit comments

Comments
 (0)