Skip to content

Commit 04e79cf

Browse files
committed
[dfsan] Add a flag to ignore personality routines.
This diff adds "dfsan-ignore-personality-routine" flag, which makes the dfsan pass to not to generate wrappers for the personality functions if the function is marked uninstrumented. This flag is to support dfsan with the cases where the exception handling routines cannot be instrumented (e.g. use the prebuilt version of c++ standard library). When the personality function cannot be instrumented it is supposed to be marked "uninstrumented" from the abi list file. While DFSan generates a wrapper function for uninstrumented functions, it cannot cannot generate a valid wrapper for vararg functions, and indirect invocation of vararg function wrapper terminates the execution of dfsan-instrumented programs. This makes invocation of personality routine to crash the program, because 1) clang adds a declaration of personality functions as a vararg function with no fixed argument, and 2) personality routines are always called indirectly. To address this issue, the flag introduced in this diff makes dfsan to not to instrument the personality function. This is not the "correct" solution in the sense that return value label from the personality function will be undefined. However, in practice, if the exception handling routines are uninstrumented we wouldn't expect precise label propagation around them, and it would be more beneficial to make the rest of the program run without termination. Reviewed By: browneee Differential Revision: https://reviews.llvm.org/D115317
1 parent 23149d5 commit 04e79cf

File tree

3 files changed

+62
-1
lines changed

3 files changed

+62
-1
lines changed

llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,12 @@ static cl::opt<int> ClTrackOrigins("dfsan-track-origins",
232232
cl::desc("Track origins of labels"),
233233
cl::Hidden, cl::init(0));
234234

235+
static cl::opt<bool> ClIgnorePersonalityRoutine(
236+
"dfsan-ignore-personality-routine",
237+
cl::desc("If a personality routine is marked uninstrumented from the ABI "
238+
"list, do not create a wrapper for it."),
239+
cl::Hidden, cl::init(false));
240+
235241
static StringRef getGlobalTypeString(const GlobalValue &G) {
236242
// Types of GlobalVariables are always pointer types.
237243
Type *GType = G.getValueType();
@@ -1357,9 +1363,24 @@ bool DataFlowSanitizer::runImpl(Module &M) {
13571363
std::vector<Function *> FnsToInstrument;
13581364
SmallPtrSet<Function *, 2> FnsWithNativeABI;
13591365
SmallPtrSet<Function *, 2> FnsWithForceZeroLabel;
1366+
SmallPtrSet<Constant *, 1> PersonalityFns;
13601367
for (Function &F : M)
1361-
if (!F.isIntrinsic() && !DFSanRuntimeFunctions.contains(&F))
1368+
if (!F.isIntrinsic() && !DFSanRuntimeFunctions.contains(&F)) {
13621369
FnsToInstrument.push_back(&F);
1370+
if (F.hasPersonalityFn())
1371+
PersonalityFns.insert(F.getPersonalityFn()->stripPointerCasts());
1372+
}
1373+
1374+
if (ClIgnorePersonalityRoutine) {
1375+
for (auto *C : PersonalityFns) {
1376+
assert(isa<Function>(C) && "Personality routine is not a function!");
1377+
Function *F = cast<Function>(C);
1378+
if (!isInstrumented(F))
1379+
FnsToInstrument.erase(
1380+
std::remove(FnsToInstrument.begin(), FnsToInstrument.end(), F),
1381+
FnsToInstrument.end());
1382+
}
1383+
}
13631384

13641385
// Give function aliases prefixes when necessary, and build wrappers where the
13651386
// instrumentedness is inconsistent.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fun:__gxx_personality_v0=uninstrumented
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
; RUN: opt < %s -dfsan -S --dfsan-abilist=%S/Inputs/personality-routine-abilist.txt | FileCheck %s
2+
; RUN: opt < %s -dfsan -S --dfsan-abilist=%S/Inputs/personality-routine-abilist.txt -dfsan-ignore-personality-routine | FileCheck %s --check-prefix=CHECK-IGNORE
3+
; RUN: opt < %s -passes=dfsan -S --dfsan-abilist=%S/Inputs/personality-routine-abilist.txt | FileCheck %s
4+
5+
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
6+
target triple = "x86_64-unknown-linux-gnu"
7+
8+
declare i32 @__gxx_personality_v0(...)
9+
10+
declare i8* @__cxa_begin_catch(i8*)
11+
12+
declare void @__cxa_end_catch()
13+
14+
declare void @g(...)
15+
16+
; CHECK-LABEL: @h.dfsan
17+
; CHECK-SAME: personality {{.*}}@"dfsw$__gxx_personality_v0"{{.*}}
18+
; CHECK-IGNORE-LABEL: @h.dfsan
19+
; CHECK-IGNORE-SAME: personality {{.*}}__gxx_personality_v0{{.*}}
20+
define i32 @h() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
21+
invoke void (...) @g(i32 42)
22+
to label %try.cont unwind label %lpad
23+
24+
lpad:
25+
%1 = landingpad { i8*, i32 }
26+
catch i8* null
27+
%2 = extractvalue { i8*, i32 } %1, 0
28+
%3 = tail call i8* @__cxa_begin_catch(i8* %2)
29+
tail call void @__cxa_end_catch()
30+
br label %try.cont
31+
32+
try.cont:
33+
ret i32 0
34+
}
35+
36+
; CHECK: @"dfsw$__gxx_personality_v0"
37+
; CHECK: call void @__dfsan_vararg_wrapper
38+
; CHECK-IGNORE-NOT: @"dfsw$__gxx_personality_v0"
39+
; CHECK-IGNORE-NOT: call void @__dfsan_vararg_wrapper

0 commit comments

Comments
 (0)