Skip to content

Commit dc087d1

Browse files
authored
Avoid undefined behavior in shift operators during constant folding of DIExpressions. (#116466)
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.
1 parent 9c3665c commit dc087d1

File tree

2 files changed

+10
-8
lines changed

2 files changed

+10
-8
lines changed

llvm/lib/IR/DIExpressionOptimizer.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,14 @@ foldOperationIfPossible(uint64_t Const1, uint64_t Const2,
5959
return Const1 - Const2;
6060
}
6161
case dwarf::DW_OP_shl: {
62-
if ((uint64_t)countl_zero(Const1) < Const2)
62+
if (Const2 >= std::numeric_limits<uint64_t>::digits ||
63+
static_cast<uint64_t>(countl_zero(Const1)) < Const2)
6364
return std::nullopt;
6465
return Const1 << Const2;
6566
}
6667
case dwarf::DW_OP_shr: {
67-
if ((uint64_t)countr_zero(Const1) < Const2)
68+
if (Const2 >= std::numeric_limits<uint64_t>::digits ||
69+
static_cast<uint64_t>(countr_zero(Const1)) < Const2)
6870
return std::nullopt;
6971
return Const1 >> Const2;
7072
}

llvm/unittests/IR/MetadataTest.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3541,38 +3541,38 @@ TEST_F(DIExpressionTest, Fold) {
35413541
ResExpr = DIExpression::get(Context, ResOps);
35423542
EXPECT_EQ(E, ResExpr);
35433543

3544-
// Test a left shift greater than 64.
3544+
// Test a left shift greater than 63.
35453545
Ops.clear();
35463546
Ops.push_back(dwarf::DW_OP_constu);
35473547
Ops.push_back(1);
35483548
Ops.push_back(dwarf::DW_OP_constu);
3549-
Ops.push_back(65);
3549+
Ops.push_back(64);
35503550
Ops.push_back(dwarf::DW_OP_shl);
35513551
Expr = DIExpression::get(Context, Ops);
35523552
E = Expr->foldConstantMath();
35533553
ResOps.clear();
35543554
ResOps.push_back(dwarf::DW_OP_constu);
35553555
ResOps.push_back(1);
35563556
ResOps.push_back(dwarf::DW_OP_constu);
3557-
ResOps.push_back(65);
3557+
ResOps.push_back(64);
35583558
ResOps.push_back(dwarf::DW_OP_shl);
35593559
ResExpr = DIExpression::get(Context, ResOps);
35603560
EXPECT_EQ(E, ResExpr);
35613561

3562-
// Test a right shift greater than 64.
3562+
// Test a right shift greater than 63.
35633563
Ops.clear();
35643564
Ops.push_back(dwarf::DW_OP_constu);
35653565
Ops.push_back(1);
35663566
Ops.push_back(dwarf::DW_OP_constu);
3567-
Ops.push_back(65);
3567+
Ops.push_back(64);
35683568
Ops.push_back(dwarf::DW_OP_shr);
35693569
Expr = DIExpression::get(Context, Ops);
35703570
E = Expr->foldConstantMath();
35713571
ResOps.clear();
35723572
ResOps.push_back(dwarf::DW_OP_constu);
35733573
ResOps.push_back(1);
35743574
ResOps.push_back(dwarf::DW_OP_constu);
3575-
ResOps.push_back(65);
3575+
ResOps.push_back(64);
35763576
ResOps.push_back(dwarf::DW_OP_shr);
35773577
ResExpr = DIExpression::get(Context, ResOps);
35783578
EXPECT_EQ(E, ResExpr);

0 commit comments

Comments
 (0)