Skip to content

[UBSAN] Preserve ubsan code with ubsan-unique-traps #83470

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

Closed
wants to merge 1 commit into from

Conversation

vitalybuka
Copy link
Collaborator

Removing TrapBB->getParent()->size() added with #65972. Counter as-is
is not very unique after inlining https://godbolt.org/z/4KfEKq7zb (see
m()).

Removing `TrapBB->getParent()->size()` added with llvm#65972. Counter as-is
is not very unique after inlining https://godbolt.org/z/4KfEKq7zb (see
m()).
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:codegen IR generation bugs: mangling, exceptions, etc. labels Feb 29, 2024
@llvmbot
Copy link
Member

llvmbot commented Feb 29, 2024

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Vitaly Buka (vitalybuka)

Changes

Removing TrapBB->getParent()->size() added with #65972. Counter as-is
is not very unique after inlining https://godbolt.org/z/4KfEKq7zb (see
m()).


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

2 Files Affected:

  • (modified) clang/lib/CodeGen/CGExpr.cpp (+3-5)
  • (modified) clang/test/CodeGen/bounds-checking.c (+2-2)
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 59a7fe8925001c..ee5f3a2786a627 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -3826,11 +3826,9 @@ void CodeGenFunction::EmitTrapCheck(llvm::Value *Checked,
     Builder.CreateCondBr(Checked, Cont, TrapBB);
     EmitBlock(TrapBB);
 
-    llvm::CallInst *TrapCall = Builder.CreateCall(
-        CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
-        llvm::ConstantInt::get(CGM.Int8Ty, ClSanitizeDebugDeoptimization
-                                               ? TrapBB->getParent()->size()
-                                               : CheckHandlerID));
+    llvm::CallInst *TrapCall =
+        Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::ubsantrap),
+                           llvm::ConstantInt::get(CGM.Int8Ty, CheckHandlerID));
 
     if (!CGM.getCodeGenOpts().TrapFuncName.empty()) {
       auto A = llvm::Attribute::get(getLLVMContext(), "trap-func-name",
diff --git a/clang/test/CodeGen/bounds-checking.c b/clang/test/CodeGen/bounds-checking.c
index 8100e30d0650ad..f6c4880e70a150 100644
--- a/clang/test/CodeGen/bounds-checking.c
+++ b/clang/test/CodeGen/bounds-checking.c
@@ -74,11 +74,11 @@ char B2[10];
 // CHECK-LABEL: @f8
 void f8(int i, int k) {
   // NOOPTLOCAL: call void @llvm.ubsantrap(i8 3)
-  // NOOPTARRAY: call void @llvm.ubsantrap(i8 2)
+  // NOOPTARRAY: call void @llvm.ubsantrap(i8 18)
   B[i] = '\0';
 
   // NOOPTLOCAL: call void @llvm.ubsantrap(i8 5)
-  // NOOPTARRAY: call void @llvm.ubsantrap(i8 4)
+  // NOOPTARRAY: call void @llvm.ubsantrap(i8 18)
   B2[k] = '\0';
 }
 

@oskarwirga
Copy link
Contributor

It happens later, in LLVM backend, it needs to be fixed.

From #65972 (comment)

Is this something you have planned to fix? If not would replacing the .size() counter with perhaps a seeded random uint8 be acceptable?

My use case prevents me from shipping the minimal runtime alongside the instrumentation so my goal was to create an improvement (definitely imperfect!) to the debugability of a production deployment of BoundsSan. This PR as is would revert that behavior entirely.

@vitalybuka
Copy link
Collaborator Author

It happens later, in LLVM backend, it needs to be fixed.

From #65972 (comment)

Is this something you have planned to fix? If not would replacing the .size() counter with perhaps a seeded random uint8 be acceptable?

My use case prevents me from shipping the minimal runtime alongside the instrumentation so my goal was to create an improvement (definitely imperfect!) to the debugability of a production deployment of BoundsSan. This PR as is would revert that behavior entirely.

I don't plan to do anything about it.
My point that it does not work even on trivial example as in description.
Unless you/someone else is willing to work on real fix, this behavior is not worse of preserving.

Copy link
Contributor

@oskarwirga oskarwirga left a comment

Choose a reason for hiding this comment

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

If you are going to remove this feature, I would rather you simply revert the old commit. There is no point leaving the flag in at this point.

I had explored earlier dealing with the optimization at a later time in the compilation pipeline, but got nowhere and this solution was ideal for my use case, binary size constraints limited any inlining so I never ran into the issue. I appreciate you cleaning this up! :)

@vitalybuka
Copy link
Collaborator Author

If you are going to remove this feature, I would rather you simply revert the old commit. There is no point leaving the flag in at this point.

I had explored earlier dealing with the optimization at a later time in the compilation pipeline, but got nowhere and this solution was ideal for my use case, binary size constraints limited any inlining so I never ran into the issue. I appreciate you cleaning this up! :)

Actually I am here because I want to use the flag to avoid merging basic blocks.
We are going to opt-out ubsan checks based on PGO, per basic block hotness #83471

However I am considering introducing a special intrinsic for that, the this patch will not be needed.

@vitalybuka vitalybuka requested a review from oskarwirga April 5, 2024 16:07
@vitalybuka
Copy link
Collaborator Author

vitalybuka commented Apr 5, 2024

I changed my design, so I don't need this patch.
Given https://godbolt.org/z/4KfEKq7zb, I can revert your patch, or just leave it as is. I have no preference.

@oskarwirga
Copy link
Contributor

I changed my design, so I don't need this patch. Given https://godbolt.org/z/4KfEKq7zb, I can revert your patch, or just leave it as is. I have no preference.

I would prefer leaving it as is, I will make a note to revisit this pending further testing on my end to see how useful it really is. Thank you :)

@vitalybuka
Copy link
Collaborator Author

abandoning

@vitalybuka vitalybuka closed this Apr 5, 2024
@vitalybuka vitalybuka deleted the nocount branch April 5, 2024 19:47
thurstond added a commit to thurstond/llvm-project that referenced this pull request Nov 26, 2024
llvm#65972 (continuation of https://reviews.llvm.org/D148654) had considered adding nomerge to ubsantrap, but did not proceed with that because of llvm#53011. Instead, it added a counter (based on TrapBB->getParent()->size()) to each ubsantrap call. However, this counter is not guaranteed to be unique after inlining, as shown by llvm#83470, which can result in ubsantraps being merged by the backend.

llvm#101549 fixed has since fixed the nomerge limitation ("It sets nomerge flag for the node if the instruction has nomerge arrtibute."). This patch therefore takes advantage of nomerge instead of using the counter, guaranteeing that the ubsantraps are not merged.

This patch is equivalent to llvm#83470 but also adds nomerge and updates the test that was precommitted in llvm#117649.
thurstond added a commit to thurstond/llvm-project that referenced this pull request Nov 26, 2024
…considered harmful

This testcase demonstrates that when nomerge is missing from ubsantrap
intrinsics, they may be merged when inlining.

This is based on the observation and testcase by Vitaly Buka in llvm#83470
thurstond added a commit that referenced this pull request Nov 26, 2024
…117649)

This test (copied from #83470)
demonstrates that UBSan does not add the nomerge annotation. This is
significant because it can result in them being merged by the backend,
even when -ubsan-unique-traps is enabled.

N.B. #65972 (continuation of
https://reviews.llvm.org/D148654) had considered adding nomerge to
ubsantrap, but did not proceed with that because of
#53011.
#101549 fixed that limitation
("It sets nomerge flag for the node if the instruction has nomerge
arrtibute."); planned upcoming work
(#117651) will add nomerge for
ubsan.
thurstond added a commit that referenced this pull request Nov 26, 2024
…considered harmful (#117657)

These testcases demonstrate that ubsan intrinsics are merged in the
backend iff nomerge is missing from ubsantrap intrinsics.

This is based on the observation and testcase by Vitaly Buka in
#83470.
thurstond added a commit to thurstond/llvm-project that referenced this pull request Nov 26, 2024
llvm#65972 (continuation of https://reviews.llvm.org/D148654) had considered adding nomerge to ubsantrap, but did not proceed with that because of llvm#53011. Instead, it added a counter (based on TrapBB->getParent()->size()) to each ubsantrap call. However, this counter is not guaranteed to be unique after inlining, as shown by llvm#83470, which can result in ubsantraps being merged by the backend.

llvm#101549 fixed has since fixed the nomerge limitation ("It sets nomerge flag for the node if the instruction has nomerge arrtibute."). This patch therefore takes advantage of nomerge instead of using the counter, guaranteeing that the ubsantraps are not merged.

This patch is equivalent to llvm#83470 but also adds nomerge and updates the test that was precommitted in llvm#117649.
thurstond added a commit to thurstond/llvm-project that referenced this pull request Nov 26, 2024
…nomerge" (llvm#117804)

This reverts commit c8bdb31.

It was reverted because I forgot to update the auto-generated assertions after adding the target triple.

Original commit message:

This test (copied from llvm#83470) demonstrates that UBSan does not add the nomerge annotation. This is significant because it can result in them being merged by the backend, even when -ubsan-unique-traps is enabled.

N.B. llvm#65972 (continuation of https://reviews.llvm.org/D148654) had considered adding nomerge to ubsantrap, but did not proceed with that because of llvm#53011. llvm#101549 fixed that limitation ("It sets nomerge flag for the node if the instruction has nomerge arrtibute."); planned upcoming work (llvm#117651) will add nomerge for ubsan.
thurstond added a commit that referenced this pull request Nov 26, 2024
…nomerge" (#117804) (#117805)

This reverts commit c8bdb31.

It was reverted because I forgot to update the auto-generated assertions
after adding the target triple.

Original commit message:

This test (copied from #83470)
demonstrates that UBSan does not add the nomerge annotation. This is
significant because it can result in them being merged by the backend,
even when -ubsan-unique-traps is enabled.

N.B. #65972 (continuation of
https://reviews.llvm.org/D148654) had considered adding nomerge to
ubsantrap, but did not proceed with that because of
#53011.
#101549 fixed that limitation
("It sets nomerge flag for the node if the instruction has nomerge
arrtibute."); planned upcoming work
(#117651) will add nomerge for
ubsan.
thurstond added a commit to thurstond/llvm-project that referenced this pull request Nov 26, 2024
llvm#65972 (continuation of https://reviews.llvm.org/D148654) had considered adding nomerge to ubsantrap, but did not proceed with that because of llvm#53011. Instead, it added a counter (based on TrapBB->getParent()->size()) to each ubsantrap call. However, this counter is not guaranteed to be unique after inlining, as shown by llvm#83470, which can result in ubsantraps being merged by the backend.

llvm#101549 fixed has since fixed the nomerge limitation ("It sets nomerge flag for the node if the instruction has nomerge arrtibute."). This patch therefore takes advantage of nomerge instead of using the counter, guaranteeing that the ubsantraps are not merged.

This patch is equivalent to llvm#83470 but also adds nomerge and updates the test that was precommitted in llvm#117649.
thurstond added a commit that referenced this pull request Nov 27, 2024
…117651)

#65972 (continuation of
https://reviews.llvm.org/D148654) had considered adding nomerge to
ubsantrap, but did not proceed with that because of
#53011. Instead, it added a
counter (based on TrapBB->getParent()->size()) to each ubsantrap call.
However, this counter is not guaranteed to be unique after inlining, as
shown by #83470, which can
result in ubsantraps being merged by the backend.

#101549 has since fixed the
nomerge limitation ("It sets nomerge flag for the node if the
instruction has nomerge arrtibute."). This patch therefore takes
advantage of nomerge instead of using the counter, guaranteeing that the
ubsantraps are not merged.

This patch is equivalent to
#83470 but also adds nomerge
and updates tests (#117649:
ubsan-trap-merge.c; #117657:
ubsan-trap-merge.ll, ubsan-trap-nomerge.ll; catch-undef-behavior.c).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants