Skip to content

Conversation

@tahonermann
Copy link
Contributor

Bit shift operations with a shift operand greater than or equal to the bit width of the (promoted) value type result in undefined behavior according to C++ [expr.shift]p1. This change adds checking for this situation and avoids attempts to constant fold DIExpressions that would otherwise provoke such behavior. An existing test that presumably intended to exercise shifts at the UB boundary has been updated; it now checks for shifts of 64 bits instead of 65. This issue was reported by a static analysis tool; no actual cases of shift operations that would result in undefined behavior in practice have been identified.

…f DIExpressions.

Bit shift operations with a shift operand greater than or equal to the bit width
of the (promoted) value type result in undefined behavior according to C++
[expr.shift]p1. This change adds checking for this situation and avoids attempts
to constant fold DIExpressions that would otherwise provoke such behavior.
An existing test that presumably intended to exercise shifts at the UB boundary
has been updated; it now checks for shifts of 64 bits instead of 65. This issue
was reported by a static analysis tool; no actual cases of shift operations that
would result in undefined behavior in practice have been identified.
@tahonermann tahonermann self-assigned this Nov 16, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 16, 2024

@llvm/pr-subscribers-llvm-ir

Author: Tom Honermann (tahonermann)

Changes

Bit shift operations with a shift operand greater than or equal to the bit width of the (promoted) value type result in undefined behavior according to C++ [[expr.shift]p1](https://eel.is/c++draft/expr.shift#1). This change adds checking for this situation and avoids attempts to constant fold DIExpressions that would otherwise provoke such behavior. An existing test that presumably intended to exercise shifts at the UB boundary has been updated; it now checks for shifts of 64 bits instead of 65. This issue was reported by a static analysis tool; no actual cases of shift operations that would result in undefined behavior in practice have been identified.


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

2 Files Affected:

  • (modified) llvm/lib/IR/DIExpressionOptimizer.cpp (+4-2)
  • (modified) llvm/unittests/IR/MetadataTest.cpp (+6-6)
diff --git a/llvm/lib/IR/DIExpressionOptimizer.cpp b/llvm/lib/IR/DIExpressionOptimizer.cpp
index 2bb8eac348c8e9..5bd18dcf049060 100644
--- a/llvm/lib/IR/DIExpressionOptimizer.cpp
+++ b/llvm/lib/IR/DIExpressionOptimizer.cpp
@@ -59,12 +59,14 @@ foldOperationIfPossible(uint64_t Const1, uint64_t Const2,
     return Const1 - Const2;
   }
   case dwarf::DW_OP_shl: {
-    if ((uint64_t)countl_zero(Const1) < Const2)
+    if (Const2 >= std::numeric_limits<uint64_t>::digits ||
+        (uint64_t)countl_zero(Const1) < Const2)
       return std::nullopt;
     return Const1 << Const2;
   }
   case dwarf::DW_OP_shr: {
-    if ((uint64_t)countr_zero(Const1) < Const2)
+    if (Const2 >= std::numeric_limits<uint64_t>::digits ||
+        (uint64_t)countr_zero(Const1) < Const2)
       return std::nullopt;
     return Const1 >> Const2;
   }
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index fbdab1975df725..628221339c89bf 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -3541,12 +3541,12 @@ TEST_F(DIExpressionTest, Fold) {
   ResExpr = DIExpression::get(Context, ResOps);
   EXPECT_EQ(E, ResExpr);
 
-  // Test a left shift greater than 64.
+  // Test a left shift greater than 63.
   Ops.clear();
   Ops.push_back(dwarf::DW_OP_constu);
   Ops.push_back(1);
   Ops.push_back(dwarf::DW_OP_constu);
-  Ops.push_back(65);
+  Ops.push_back(64);
   Ops.push_back(dwarf::DW_OP_shl);
   Expr = DIExpression::get(Context, Ops);
   E = Expr->foldConstantMath();
@@ -3554,17 +3554,17 @@ TEST_F(DIExpressionTest, Fold) {
   ResOps.push_back(dwarf::DW_OP_constu);
   ResOps.push_back(1);
   ResOps.push_back(dwarf::DW_OP_constu);
-  ResOps.push_back(65);
+  ResOps.push_back(64);
   ResOps.push_back(dwarf::DW_OP_shl);
   ResExpr = DIExpression::get(Context, ResOps);
   EXPECT_EQ(E, ResExpr);
 
-  // Test a right shift greater than 64.
+  // Test a right shift greater than 63.
   Ops.clear();
   Ops.push_back(dwarf::DW_OP_constu);
   Ops.push_back(1);
   Ops.push_back(dwarf::DW_OP_constu);
-  Ops.push_back(65);
+  Ops.push_back(64);
   Ops.push_back(dwarf::DW_OP_shr);
   Expr = DIExpression::get(Context, Ops);
   E = Expr->foldConstantMath();
@@ -3572,7 +3572,7 @@ TEST_F(DIExpressionTest, Fold) {
   ResOps.push_back(dwarf::DW_OP_constu);
   ResOps.push_back(1);
   ResOps.push_back(dwarf::DW_OP_constu);
-  ResOps.push_back(65);
+  ResOps.push_back(64);
   ResOps.push_back(dwarf::DW_OP_shr);
   ResExpr = DIExpression::get(Context, ResOps);
   EXPECT_EQ(E, ResExpr);

Copy link
Contributor

@rastogishubham rastogishubham left a comment

Choose a reason for hiding this comment

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

LGTM thanks for catching the bug!

@tahonermann tahonermann merged commit dc087d1 into llvm:main Nov 18, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants