Skip to content

[msan] Fix "Add optional flag to improve instrumentation of disjoint OR (#145990)" #146799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 3, 2025

Conversation

thurstond
Copy link
Contributor

@thurstond thurstond commented Jul 2, 2025

The "V1" and "V2" values were already NOT'ed, hence the calculation of disjoint OR in #145990 was incorrect. This patch fixes the issue by using DeMorgan's law.

…OR (llvm#145990)"

The "V1" and "V2" values were already NOT'ed, hence the calculation of
disjoint OR was incorrect. This patch fixes the issue by using the
instruction operands directly.
@llvmbot
Copy link
Member

llvmbot commented Jul 2, 2025

@llvm/pr-subscribers-compiler-rt-sanitizer

@llvm/pr-subscribers-llvm-transforms

Author: Thurston Dang (thurstond)

Changes

The "V1" and "V2" values were already NOT'ed, hence the calculation of disjoint OR was incorrect. This patch fixes the issue by using the instruction operands directly.


Full diff: https://github.com/llvm/llvm-project/pull/146799.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp (+6-1)
  • (modified) llvm/test/Instrumentation/MemorySanitizer/or.ll (+3-2)
diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index 6511c197fcb5a..4a0eee177667e 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -2512,6 +2512,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
     //    S = S | (V1 & V2)
     Value *S1 = getShadow(&I, 0);
     Value *S2 = getShadow(&I, 1);
+    // Gotcha: V1 and V2 are NOT'ed here
     Value *V1 = IRB.CreateNot(I.getOperand(0));
     Value *V2 = IRB.CreateNot(I.getOperand(1));
     if (V1->getType() != S1->getType()) {
@@ -2524,7 +2525,11 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
 
     Value *S = IRB.CreateOr({S1S2, V1S2, S1V2});
     if (ClPreciseDisjointOr && cast<PossiblyDisjointInst>(&I)->isDisjoint()) {
-      Value *V1V2 = IRB.CreateAnd(V1, V2);
+      // "V1" and "V2" were NOT'ed above, but we still want to reuse them
+      // because they were IntCast'ed to the same type as the shadows.
+      //
+      // (V1 & V2) == ~(~V1 | ~V2) (de Morgan)
+      Value *V1V2 = IRB.CreateNot(IRB.CreateOr(V1, V2));
       S = IRB.CreateOr({S, V1V2});
     }
 
diff --git a/llvm/test/Instrumentation/MemorySanitizer/or.ll b/llvm/test/Instrumentation/MemorySanitizer/or.ll
index 2d51de13a8ebb..71beb38b466e4 100644
--- a/llvm/test/Instrumentation/MemorySanitizer/or.ll
+++ b/llvm/test/Instrumentation/MemorySanitizer/or.ll
@@ -45,8 +45,9 @@ define i8 @test_disjoint_or(i8 %a, i8 %b) sanitize_memory {
 ; CHECK-IMPRECISE:      [[C:%.*]] = or disjoint i8 [[A]], [[B]]
 ; CHECK-IMPRECISE-NEXT: store i8 [[TMP11]], ptr @__msan_retval_tls, align 8
 ;
-; CHECK-PRECISE:         [[TMP10:%.*]] = and i8 [[TMP3]], [[TMP4]]
-; CHECK-PRECISE-NEXT:    [[TMP12:%.*]] = or i8 [[TMP11]], [[TMP10]]
+; CHECK-PRECISE:         [[TMP10:%.*]] = or i8 [[TMP3]], [[TMP4]]
+; CHECK-PRECISE-NEXT:    [[TMP11:%.*]] = xor i8 [[TMP10]], -1
+; CHECK-PRECISE-NEXT:    [[TMP12:%.*]] = or i8 [[TMP9]], [[TMP11]]
 ; CHECK-PRECISE-NEXT:    [[C:%.*]] = or disjoint i8 [[A]], [[B]]
 ; CHECK-PRECISE-NEXT:    store i8 [[TMP12]], ptr @__msan_retval_tls, align 8
 ;

@@ -2512,6 +2512,7 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
// S = S | (V1 & V2)
Value *S1 = getShadow(&I, 0);
Value *S2 = getShadow(&I, 1);
// Gotcha: V1 and V2 are NOT'ed here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change the names instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The composite names would get clunky and possibly ambiguous:

    // Name is ambiguous: it's ((NotV1) & S2), as opposed to (Not (V1 & S2))
    Value *NotV1S2 = IRB.CreateAnd(NotV1, S2);
    Value *S1NotV2 = IRB.CreateAnd(S1, NotV2);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe give them more meaningless names then, so people have to look up the definition? idk tho

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the order to make it unambiguous

@@ -2524,7 +2525,11 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {

Value *S = IRB.CreateOr({S1S2, V1S2, S1V2});
if (ClPreciseDisjointOr && cast<PossiblyDisjointInst>(&I)->isDisjoint()) {
Value *V1V2 = IRB.CreateAnd(V1, V2);
// "V1" and "V2" were NOT'ed above, but we still want to reuse them
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that really better than just int casting them again?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do that

@thurstond thurstond requested a review from fmayer July 2, 2025 23:41
// (V1 & V2) == ~(~V1 | ~V2) (de Morgan)
Value *V1V2 = IRB.CreateNot(IRB.CreateOr(V1, V2));
// "V1" and "V2" were NOT'ed above
V1 = IRB.CreateIntCast(I.getOperand(0), S1->getType(), false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't reuse the variable name :(

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed the earlier variables NotV1 / NotV2

@thurstond thurstond requested a review from fmayer July 3, 2025 00:00
@thurstond
Copy link
Contributor Author

Failing test is flang, so YOLO

@thurstond thurstond merged commit 4cf53cd into llvm:main Jul 3, 2025
10 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants