From 1a9d1b52047cd8dc91fbb5087c2fdcaf19bb4535 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Mon, 14 Jul 2025 16:54:19 +0000 Subject: [PATCH 1/3] [msan] Re-fix disjoint OR instrumentation from #145990 When disjoint OR was specified and a bit position contained a 1 in both operands, #145990 would set the corresponding shadow bit to uninitialized. However, the output of the operation is (LLVM) 'poison' for the entire result, hence the entire shadow ought to be uninitialized. This patch corrects the issue. --- .../Transforms/Instrumentation/MemorySanitizer.cpp | 10 ++++++---- llvm/test/Instrumentation/MemorySanitizer/or.ll | 14 ++++++++------ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp index 5f5200b2c9e62..fecec845f8d58 100644 --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -2509,9 +2509,9 @@ struct MemorySanitizerVisitor : public InstVisitor { // // S = (S1 & S2) | (~V1 & S2) | (S1 & ~V2) // - // Addendum if the "Or" is "disjoint": - // 1|1 => p; - // S = S | (V1 & V2) + // If the "disjoint OR" property is violated, the result is poison, and + // hence the entire shadow is uninitialized: + // S = S | SignExt(V1 & V2 != 0) Value *S1 = getShadow(&I, 0); Value *S2 = getShadow(&I, 1); Value *V1 = I.getOperand(0); @@ -2532,7 +2532,9 @@ struct MemorySanitizerVisitor : public InstVisitor { if (ClPreciseDisjointOr && cast(&I)->isDisjoint()) { Value *V1V2 = IRB.CreateAnd(V1, V2); - S = IRB.CreateOr(S, V1V2, "_ms_disjoint"); + Value *DisjointOrShadow = IRB.CreateSExt( + IRB.CreateICmpNE(V1V2, getCleanShadow(V1V2)), V1V2->getType()); + S = IRB.CreateOr(S, DisjointOrShadow, "_ms_disjoint"); } setShadow(&I, S); diff --git a/llvm/test/Instrumentation/MemorySanitizer/or.ll b/llvm/test/Instrumentation/MemorySanitizer/or.ll index 27a1800aa495b..650c70b6a4d94 100644 --- a/llvm/test/Instrumentation/MemorySanitizer/or.ll +++ b/llvm/test/Instrumentation/MemorySanitizer/or.ll @@ -1,4 +1,4 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; NOTE: Assertions have mostly been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -S -passes=msan -msan-precise-disjoint-or=false 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-IMPRECISE ; RUN: opt < %s -S -passes=msan -msan-precise-disjoint-or=true 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PRECISE ; @@ -40,15 +40,17 @@ define i8 @test_disjoint_or(i8 %a, i8 %b) sanitize_memory { ; CHECK-NEXT: [[TMP6:%.*]] = and i8 [[TMP3]], [[TMP2]] ; CHECK-NEXT: [[TMP7:%.*]] = and i8 [[TMP1]], [[TMP4]] ; CHECK-NEXT: [[TMP8:%.*]] = or i8 [[TMP5]], [[TMP6]] -; CHECK-NEXT: [[TMP11:%.*]] = or i8 [[TMP8]], [[TMP7]] +; CHECK-NEXT: [[TMP9:%.*]] = or i8 [[TMP8]], [[TMP7]] ; ; CHECK-IMPRECISE: [[C:%.*]] = or disjoint i8 [[A]], [[B]] -; CHECK-IMPRECISE-NEXT: store i8 [[TMP11]], ptr @__msan_retval_tls, align 8 +; CHECK-IMPRECISE-NEXT: store i8 [[TMP9]], ptr @__msan_retval_tls, align 8 ; -; CHECK-PRECISE: [[TMP10:%.*]] = and i8 [[A]], [[B]] -; CHECK-PRECISE-NEXT: [[TMP12:%.*]] = or i8 [[TMP11]], [[TMP10]] +; CHECK-PRECISE-NEXT: [[TMP10:%.*]] = and i8 [[A]], [[B]] +; CHECK-PRECISE-NEXT: [[TMP11:%.*]] = icmp ne i8 [[TMP10]], 0 +; CHECK-PRECISE-NEXT: [[TMP12:%.*]] = sext i1 [[TMP11]] to i8 +; CHECK-PRECISE-NEXT: [[_MS_DISJOINT:%.*]] = or i8 [[TMP9]], [[TMP12]] ; CHECK-PRECISE-NEXT: [[C:%.*]] = or disjoint i8 [[A]], [[B]] -; CHECK-PRECISE-NEXT: store i8 [[TMP12]], ptr @__msan_retval_tls, align 8 +; CHECK-PRECISE-NEXT: store i8 [[_MS_DISJOINT]], ptr @__msan_retval_tls, align 8 ; ; CHECK-NEXT: ret i8 [[C]] ; From a8bfd6bca8474a264e166a2fe09887bcaf7c0762 Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 15 Jul 2025 17:38:46 +0000 Subject: [PATCH 2/3] Fully auto-gen --- .../Instrumentation/MemorySanitizer/or.ll | 46 ++++++++++++------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/llvm/test/Instrumentation/MemorySanitizer/or.ll b/llvm/test/Instrumentation/MemorySanitizer/or.ll index 650c70b6a4d94..33e0de7b637f2 100644 --- a/llvm/test/Instrumentation/MemorySanitizer/or.ll +++ b/llvm/test/Instrumentation/MemorySanitizer/or.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; NOTE: Assertions have mostly been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -S -passes=msan -msan-precise-disjoint-or=false 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-IMPRECISE ; RUN: opt < %s -S -passes=msan -msan-precise-disjoint-or=true 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PRECISE @@ -29,30 +30,41 @@ define i8 @test_or(i8 %a, i8 %b) sanitize_memory { } define i8 @test_disjoint_or(i8 %a, i8 %b) sanitize_memory { -; CHECK-LABEL: define i8 @test_disjoint_or( -; CHECK-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) #[[ATTR0]] { -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr @__msan_param_tls, align 8 -; CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8 -; CHECK-NEXT: call void @llvm.donothing() -; CHECK-NEXT: [[TMP3:%.*]] = xor i8 [[A]], -1 -; CHECK-NEXT: [[TMP4:%.*]] = xor i8 [[B]], -1 -; CHECK-NEXT: [[TMP5:%.*]] = and i8 [[TMP1]], [[TMP2]] -; CHECK-NEXT: [[TMP6:%.*]] = and i8 [[TMP3]], [[TMP2]] -; CHECK-NEXT: [[TMP7:%.*]] = and i8 [[TMP1]], [[TMP4]] -; CHECK-NEXT: [[TMP8:%.*]] = or i8 [[TMP5]], [[TMP6]] -; CHECK-NEXT: [[TMP9:%.*]] = or i8 [[TMP8]], [[TMP7]] -; -; CHECK-IMPRECISE: [[C:%.*]] = or disjoint i8 [[A]], [[B]] -; CHECK-IMPRECISE-NEXT: store i8 [[TMP9]], ptr @__msan_retval_tls, align 8 +; CHECK-IMPRECISE-LABEL: define i8 @test_disjoint_or( +; CHECK-IMPRECISE-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) #[[ATTR0]] { +; CHECK-IMPRECISE-NEXT: [[TMP1:%.*]] = load i8, ptr @__msan_param_tls, align 8 +; CHECK-IMPRECISE-NEXT: [[TMP2:%.*]] = load i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8 +; CHECK-IMPRECISE-NEXT: call void @llvm.donothing() +; CHECK-IMPRECISE-NEXT: [[TMP3:%.*]] = xor i8 [[A]], -1 +; CHECK-IMPRECISE-NEXT: [[TMP4:%.*]] = xor i8 [[B]], -1 +; CHECK-IMPRECISE-NEXT: [[TMP5:%.*]] = and i8 [[TMP1]], [[TMP2]] +; CHECK-IMPRECISE-NEXT: [[TMP6:%.*]] = and i8 [[TMP3]], [[TMP2]] +; CHECK-IMPRECISE-NEXT: [[TMP7:%.*]] = and i8 [[TMP1]], [[TMP4]] +; CHECK-IMPRECISE-NEXT: [[TMP8:%.*]] = or i8 [[TMP5]], [[TMP6]] +; CHECK-IMPRECISE-NEXT: [[TMP9:%.*]] = or i8 [[TMP8]], [[TMP7]] +; CHECK-IMPRECISE-NEXT: [[C:%.*]] = or disjoint i8 [[A]], [[B]] +; CHECK-IMPRECISE-NEXT: store i8 [[TMP9]], ptr @__msan_retval_tls, align 8 +; CHECK-IMPRECISE-NEXT: ret i8 [[C]] ; +; CHECK-PRECISE-LABEL: define i8 @test_disjoint_or( +; CHECK-PRECISE-SAME: i8 [[A:%.*]], i8 [[B:%.*]]) #[[ATTR0]] { +; CHECK-PRECISE-NEXT: [[TMP1:%.*]] = load i8, ptr @__msan_param_tls, align 8 +; CHECK-PRECISE-NEXT: [[TMP2:%.*]] = load i8, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8 +; CHECK-PRECISE-NEXT: call void @llvm.donothing() +; CHECK-PRECISE-NEXT: [[TMP3:%.*]] = xor i8 [[A]], -1 +; CHECK-PRECISE-NEXT: [[TMP4:%.*]] = xor i8 [[B]], -1 +; CHECK-PRECISE-NEXT: [[TMP5:%.*]] = and i8 [[TMP1]], [[TMP2]] +; CHECK-PRECISE-NEXT: [[TMP6:%.*]] = and i8 [[TMP3]], [[TMP2]] +; CHECK-PRECISE-NEXT: [[TMP7:%.*]] = and i8 [[TMP1]], [[TMP4]] +; CHECK-PRECISE-NEXT: [[TMP8:%.*]] = or i8 [[TMP5]], [[TMP6]] +; CHECK-PRECISE-NEXT: [[TMP9:%.*]] = or i8 [[TMP8]], [[TMP7]] ; CHECK-PRECISE-NEXT: [[TMP10:%.*]] = and i8 [[A]], [[B]] ; CHECK-PRECISE-NEXT: [[TMP11:%.*]] = icmp ne i8 [[TMP10]], 0 ; CHECK-PRECISE-NEXT: [[TMP12:%.*]] = sext i1 [[TMP11]] to i8 ; CHECK-PRECISE-NEXT: [[_MS_DISJOINT:%.*]] = or i8 [[TMP9]], [[TMP12]] ; CHECK-PRECISE-NEXT: [[C:%.*]] = or disjoint i8 [[A]], [[B]] ; CHECK-PRECISE-NEXT: store i8 [[_MS_DISJOINT]], ptr @__msan_retval_tls, align 8 -; -; CHECK-NEXT: ret i8 [[C]] +; CHECK-PRECISE-NEXT: ret i8 [[C]] ; %c = or disjoint i8 %a, %b ret i8 %c From 7eccd15a19bdaa9464f602828ceeae5566d20ded Mon Sep 17 00:00:00 2001 From: Thurston Dang Date: Tue, 15 Jul 2025 17:41:14 +0000 Subject: [PATCH 3/3] Remove stray comment --- llvm/test/Instrumentation/MemorySanitizer/or.ll | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/test/Instrumentation/MemorySanitizer/or.ll b/llvm/test/Instrumentation/MemorySanitizer/or.ll index 33e0de7b637f2..20993a54187ac 100644 --- a/llvm/test/Instrumentation/MemorySanitizer/or.ll +++ b/llvm/test/Instrumentation/MemorySanitizer/or.ll @@ -1,5 +1,4 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 -; NOTE: Assertions have mostly been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt < %s -S -passes=msan -msan-precise-disjoint-or=false 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-IMPRECISE ; RUN: opt < %s -S -passes=msan -msan-precise-disjoint-or=true 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-PRECISE ;