[llvm] 04e79cf - [dfsan] Add a flag to ignore personality routines.

Taewook Oh via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 8 14:48:43 PST 2021


Author: Taewook Oh
Date: 2021-12-08T14:48:38-08:00
New Revision: 04e79cf70b42ad477bb4eaf0483a599797c600f4

URL: https://github.com/llvm/llvm-project/commit/04e79cf70b42ad477bb4eaf0483a599797c600f4
DIFF: https://github.com/llvm/llvm-project/commit/04e79cf70b42ad477bb4eaf0483a599797c600f4.diff

LOG: [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

Added: 
    llvm/test/Instrumentation/DataFlowSanitizer/Inputs/personality-routine-abilist.txt
    llvm/test/Instrumentation/DataFlowSanitizer/ignore_persnality_routine.ll

Modified: 
    llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
index 38c219ce34654..9eedd9fd151e5 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -232,6 +232,12 @@ static cl::opt<int> ClTrackOrigins("dfsan-track-origins",
                                    cl::desc("Track origins of labels"),
                                    cl::Hidden, cl::init(0));
 
+static cl::opt<bool> ClIgnorePersonalityRoutine(
+    "dfsan-ignore-personality-routine",
+    cl::desc("If a personality routine is marked uninstrumented from the ABI "
+             "list, do not create a wrapper for it."),
+    cl::Hidden, cl::init(false));
+
 static StringRef getGlobalTypeString(const GlobalValue &G) {
   // Types of GlobalVariables are always pointer types.
   Type *GType = G.getValueType();
@@ -1357,9 +1363,24 @@ bool DataFlowSanitizer::runImpl(Module &M) {
   std::vector<Function *> FnsToInstrument;
   SmallPtrSet<Function *, 2> FnsWithNativeABI;
   SmallPtrSet<Function *, 2> FnsWithForceZeroLabel;
+  SmallPtrSet<Constant *, 1> PersonalityFns;
   for (Function &F : M)
-    if (!F.isIntrinsic() && !DFSanRuntimeFunctions.contains(&F))
+    if (!F.isIntrinsic() && !DFSanRuntimeFunctions.contains(&F)) {
       FnsToInstrument.push_back(&F);
+      if (F.hasPersonalityFn())
+        PersonalityFns.insert(F.getPersonalityFn()->stripPointerCasts());
+    }
+
+  if (ClIgnorePersonalityRoutine) {
+    for (auto *C : PersonalityFns) {
+      assert(isa<Function>(C) && "Personality routine is not a function!");
+      Function *F = cast<Function>(C);
+      if (!isInstrumented(F))
+        FnsToInstrument.erase(
+            std::remove(FnsToInstrument.begin(), FnsToInstrument.end(), F),
+            FnsToInstrument.end());
+    }
+  }
 
   // Give function aliases prefixes when necessary, and build wrappers where the
   // instrumentedness is inconsistent.

diff  --git a/llvm/test/Instrumentation/DataFlowSanitizer/Inputs/personality-routine-abilist.txt b/llvm/test/Instrumentation/DataFlowSanitizer/Inputs/personality-routine-abilist.txt
new file mode 100644
index 0000000000000..29a9f58b94355
--- /dev/null
+++ b/llvm/test/Instrumentation/DataFlowSanitizer/Inputs/personality-routine-abilist.txt
@@ -0,0 +1 @@
+fun:__gxx_personality_v0=uninstrumented

diff  --git a/llvm/test/Instrumentation/DataFlowSanitizer/ignore_persnality_routine.ll b/llvm/test/Instrumentation/DataFlowSanitizer/ignore_persnality_routine.ll
new file mode 100644
index 0000000000000..b558793bec9da
--- /dev/null
+++ b/llvm/test/Instrumentation/DataFlowSanitizer/ignore_persnality_routine.ll
@@ -0,0 +1,39 @@
+; RUN: opt < %s -dfsan -S --dfsan-abilist=%S/Inputs/personality-routine-abilist.txt | FileCheck %s
+; RUN: opt < %s -dfsan -S --dfsan-abilist=%S/Inputs/personality-routine-abilist.txt -dfsan-ignore-personality-routine | FileCheck %s --check-prefix=CHECK-IGNORE
+; RUN: opt < %s -passes=dfsan -S --dfsan-abilist=%S/Inputs/personality-routine-abilist.txt | FileCheck %s
+
+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"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare i32 @__gxx_personality_v0(...)
+
+declare i8* @__cxa_begin_catch(i8*)
+
+declare void @__cxa_end_catch()
+
+declare void @g(...)
+
+; CHECK-LABEL: @h.dfsan
+; CHECK-SAME: personality {{.*}}@"dfsw$__gxx_personality_v0"{{.*}}
+; CHECK-IGNORE-LABEL: @h.dfsan
+; CHECK-IGNORE-SAME: personality {{.*}}__gxx_personality_v0{{.*}}
+define i32 @h() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+  invoke void (...) @g(i32 42)
+          to label %try.cont unwind label %lpad
+
+lpad:
+  %1 = landingpad { i8*, i32 }
+          catch i8* null
+  %2 = extractvalue { i8*, i32 } %1, 0
+  %3 = tail call i8* @__cxa_begin_catch(i8* %2)
+  tail call void @__cxa_end_catch()
+  br label %try.cont
+
+try.cont:
+  ret i32 0
+}
+
+; CHECK: @"dfsw$__gxx_personality_v0"
+; CHECK: call void @__dfsan_vararg_wrapper
+; CHECK-IGNORE-NOT: @"dfsw$__gxx_personality_v0"
+; CHECK-IGNORE-NOT: call void @__dfsan_vararg_wrapper


        


More information about the llvm-commits mailing list