[compiler-rt] [llvm] [ASan] Do not instrument catch block parameters on Windows (PR #159618)
David Justo via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 22 20:22:41 PDT 2025
https://github.com/davidmrdavid updated https://github.com/llvm/llvm-project/pull/159618
>From ece2a2ba47d043f5225fd408c66749d8bd67c80c Mon Sep 17 00:00:00 2001
From: David Justo <dajusto at microsoft.com>
Date: Thu, 18 Sep 2025 10:17:12 -0700
Subject: [PATCH 1/4] do not asan-instrument catch parameters on windows
---
.../Instrumentation/AddressSanitizer.cpp | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index 42c3d4a4f4c46..986d3c2861af0 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -1397,6 +1397,16 @@ void AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI,
MI->eraseFromParent();
}
+// Check if an alloca is a catch block parameter
+static bool isCatchParameter(const AllocaInst &AI) {
+ for (const Use &U : AI.uses()) {
+ if (isa<CatchPadInst>(U.getUser())) {
+ return true;
+ }
+ }
+ return false;
+}
+
/// Check if we want (and can) handle this alloca.
bool AddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
auto [It, Inserted] = ProcessedAllocas.try_emplace(&AI);
@@ -1417,7 +1427,11 @@ bool AddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
// swifterror allocas are register promoted by ISel
!AI.isSwiftError() &&
// safe allocas are not interesting
- !(SSGI && SSGI->isSafe(AI)));
+ !(SSGI && SSGI->isSafe(AI)) &&
+ // Mitigation for https://github.com/google/sanitizers/issues/749
+ // We don't instrument Windows catch-block parameters to avoid
+ // interfering with exception handling assumptions.
+ !(TargetTriple.isOSWindows() && isCatchParameter(AI)));
It->second = IsInteresting;
return IsInteresting;
>From bff409da82c600d5b07915b81f7ec51f99e7c276 Mon Sep 17 00:00:00 2001
From: David Justo <dajusto at microsoft.com>
Date: Thu, 18 Sep 2025 10:25:18 -0700
Subject: [PATCH 2/4] add basic unit test: catches exception 'inline' and in
another frame
---
.../Windows/basic_exception_handling.cpp | 36 +++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp
diff --git a/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp b/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp
new file mode 100644
index 0000000000000..94ca4b9bf2df0
--- /dev/null
+++ b/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp
@@ -0,0 +1,36 @@
+// RUN: %clangxx_asan %s -o %t
+// RUN: %run %t | FileCheck %s
+
+// This test tests that declaring a parameter in a catch-block does not produce a false positive
+// ASan error on Windows.
+
+// This code is based on the repro in https://github.com/google/sanitizers/issues/749
+#include <cstdio>
+#include <exception>
+
+void throwInFunction(){
+ throw std::exception("test2");
+}
+
+int main()
+{
+ // case 1: direct throw
+ try {
+ throw std::exception("test1");
+ } catch (const std::exception& ex){
+ puts(ex.what());
+ // CHECK: test1
+ }
+
+ // case 2: throw in function
+ try {
+ throwInFunction();
+ } catch (const std::exception& ex){
+ puts(ex.what());
+ // CHECK: test2
+ }
+
+ printf("Success!\n");
+ // CHECK: Success!
+ return 0;
+}
\ No newline at end of file
>From 043848d2fecc459b5d250298c20cb115d2f1c4ef Mon Sep 17 00:00:00 2001
From: David Justo <dajusto at microsoft.com>
Date: Thu, 18 Sep 2025 11:08:07 -0700
Subject: [PATCH 3/4] apply clang-format on
`compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp`
---
.../Windows/basic_exception_handling.cpp | 41 +++++++++----------
1 file changed, 19 insertions(+), 22 deletions(-)
diff --git a/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp b/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp
index 94ca4b9bf2df0..f8dd49e64c760 100644
--- a/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp
+++ b/compiler-rt/test/asan/TestCases/Windows/basic_exception_handling.cpp
@@ -8,29 +8,26 @@
#include <cstdio>
#include <exception>
-void throwInFunction(){
- throw std::exception("test2");
-}
+void throwInFunction() { throw std::exception("test2"); }
-int main()
-{
- // case 1: direct throw
- try {
- throw std::exception("test1");
- } catch (const std::exception& ex){
- puts(ex.what());
- // CHECK: test1
- }
+int main() {
+ // case 1: direct throw
+ try {
+ throw std::exception("test1");
+ } catch (const std::exception &ex) {
+ puts(ex.what());
+ // CHECK: test1
+ }
- // case 2: throw in function
- try {
- throwInFunction();
- } catch (const std::exception& ex){
- puts(ex.what());
- // CHECK: test2
- }
+ // case 2: throw in function
+ try {
+ throwInFunction();
+ } catch (const std::exception &ex) {
+ puts(ex.what());
+ // CHECK: test2
+ }
- printf("Success!\n");
- // CHECK: Success!
- return 0;
+ printf("Success!\n");
+ // CHECK: Success!
+ return 0;
}
\ No newline at end of file
>From 2326be0809f140351ae1f740a18d9214ca878019 Mon Sep 17 00:00:00 2001
From: David Justo <dajusto at microsoft.com>
Date: Mon, 22 Sep 2025 20:22:14 -0700
Subject: [PATCH 4/4] optimization: disable catch-parameter instrumentation via
a linear pass over function basic blocks
---
.../Instrumentation/AddressSanitizer.cpp | 38 +++++++++++--------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
index 986d3c2861af0..598fa8e9421c9 100644
--- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp
@@ -847,6 +847,7 @@ struct AddressSanitizer {
bool maybeInsertAsanInitAtFunctionEntry(Function &F);
bool maybeInsertDynamicShadowAtFunctionEntry(Function &F);
void markEscapedLocalAllocas(Function &F);
+ void markCatchParametersAsUninteresting(Function &F);
private:
friend struct FunctionStackPoisoner;
@@ -1397,16 +1398,6 @@ void AddressSanitizer::instrumentMemIntrinsic(MemIntrinsic *MI,
MI->eraseFromParent();
}
-// Check if an alloca is a catch block parameter
-static bool isCatchParameter(const AllocaInst &AI) {
- for (const Use &U : AI.uses()) {
- if (isa<CatchPadInst>(U.getUser())) {
- return true;
- }
- }
- return false;
-}
-
/// Check if we want (and can) handle this alloca.
bool AddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
auto [It, Inserted] = ProcessedAllocas.try_emplace(&AI);
@@ -1427,11 +1418,7 @@ bool AddressSanitizer::isInterestingAlloca(const AllocaInst &AI) {
// swifterror allocas are register promoted by ISel
!AI.isSwiftError() &&
// safe allocas are not interesting
- !(SSGI && SSGI->isSafe(AI)) &&
- // Mitigation for https://github.com/google/sanitizers/issues/749
- // We don't instrument Windows catch-block parameters to avoid
- // interfering with exception handling assumptions.
- !(TargetTriple.isOSWindows() && isCatchParameter(AI)));
+ !(SSGI && SSGI->isSafe(AI)));
It->second = IsInteresting;
return IsInteresting;
@@ -2989,6 +2976,24 @@ void AddressSanitizer::markEscapedLocalAllocas(Function &F) {
}
}
}
+// Mitigation for https://github.com/google/sanitizers/issues/749
+// We don't instrument Windows catch-block parameters to avoid
+// interfering with exception handling assumptions.
+void AddressSanitizer::markCatchParametersAsUninteresting(Function &F) {
+ for (BasicBlock &BB : F) {
+ for (Instruction &I : BB) {
+ if (auto *CatchPad = dyn_cast<CatchPadInst>(&I)) {
+ // Mark the parameters to a catch-block as uninteresting to avoid
+ // instrumenting them
+ for (Value *Operand : CatchPad->arg_operands()) {
+ if (auto *AI = dyn_cast<AllocaInst>(Operand)) {
+ ProcessedAllocas[AI] = false;
+ }
+ }
+ }
+ }
+ }
+}
bool AddressSanitizer::suppressInstrumentationSiteForDebug(int &Instrumented) {
bool ShouldInstrument =
@@ -3032,6 +3037,9 @@ bool AddressSanitizer::instrumentFunction(Function &F,
// can be passed to that intrinsic.
markEscapedLocalAllocas(F);
+ if (TargetTriple.isOSWindows())
+ markCatchParametersAsUninteresting(F);
+
// We want to instrument every address only once per basic block (unless there
// are calls between uses).
SmallPtrSet<Value *, 16> TempsToInstrument;
More information about the llvm-commits
mailing list