Skip to content

Commit b9208ce

Browse files
authored
[clang][dataflow] Crash fix for widenDistinctValues(). (#89895)
We used to crash if the previous iteration contained a `BoolValue` and the current iteration contained an `IntegerValue`. The accompanying test sets up this situation -- see comments there for details. While I'm here, clean up the tests for integral casts to use the test helpers we have available now. I was looking at these tests to understand how we handle integral casts, and the test helpers make the tests easier to read.
1 parent 9b0651f commit b9208ce

File tree

2 files changed

+41
-37
lines changed

2 files changed

+41
-37
lines changed

clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,13 @@ static WidenResult widenDistinctValues(QualType Type, Value &Prev,
157157
Value &Current, Environment &CurrentEnv,
158158
Environment::ValueModel &Model) {
159159
// Boolean-model widening.
160-
if (auto *PrevBool = dyn_cast<BoolValue>(&Prev)) {
160+
if (isa<BoolValue>(Prev) && isa<BoolValue>(Current)) {
161+
// FIXME: Checking both values should be unnecessary, but we can currently
162+
// end up with `BoolValue`s in integer-typed variables. See comment in
163+
// `joinDistinctValues()` for details.
164+
auto &PrevBool = cast<BoolValue>(Prev);
165+
auto &CurBool = cast<BoolValue>(Current);
166+
161167
if (isa<TopBoolValue>(Prev))
162168
// Safe to return `Prev` here, because Top is never dependent on the
163169
// environment.
@@ -166,13 +172,12 @@ static WidenResult widenDistinctValues(QualType Type, Value &Prev,
166172
// We may need to widen to Top, but before we do so, check whether both
167173
// values are implied to be either true or false in the current environment.
168174
// In that case, we can simply return a literal instead.
169-
auto &CurBool = cast<BoolValue>(Current);
170-
bool TruePrev = PrevEnv.proves(PrevBool->formula());
175+
bool TruePrev = PrevEnv.proves(PrevBool.formula());
171176
bool TrueCur = CurrentEnv.proves(CurBool.formula());
172177
if (TruePrev && TrueCur)
173178
return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged};
174179
if (!TruePrev && !TrueCur &&
175-
PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool->formula())) &&
180+
PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool.formula())) &&
176181
CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula())))
177182
return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged};
178183

clang/unittests/Analysis/FlowSensitive/TransferTest.cpp

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3370,20 +3370,11 @@ TEST(TransferTest, IntegralCast) {
33703370
Code,
33713371
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
33723372
ASTContext &ASTCtx) {
3373-
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
33743373
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
33753374

3376-
const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3377-
ASSERT_THAT(FooDecl, NotNull());
3378-
3379-
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3380-
ASSERT_THAT(BarDecl, NotNull());
3381-
3382-
const auto *FooVal = Env.getValue(*FooDecl);
3383-
const auto *BarVal = Env.getValue(*BarDecl);
3384-
EXPECT_TRUE(isa<IntegerValue>(FooVal));
3385-
EXPECT_TRUE(isa<IntegerValue>(BarVal));
3386-
EXPECT_EQ(FooVal, BarVal);
3375+
const auto &FooVal = getValueForDecl<IntegerValue>(ASTCtx, Env, "Foo");
3376+
const auto &BarVal = getValueForDecl<IntegerValue>(ASTCtx, Env, "Bar");
3377+
EXPECT_EQ(&FooVal, &BarVal);
33873378
});
33883379
}
33893380

@@ -3398,17 +3389,10 @@ TEST(TransferTest, IntegraltoBooleanCast) {
33983389
Code,
33993390
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
34003391
ASTContext &ASTCtx) {
3401-
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
34023392
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
34033393

3404-
const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3405-
ASSERT_THAT(FooDecl, NotNull());
3406-
3407-
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3408-
ASSERT_THAT(BarDecl, NotNull());
3409-
3410-
const auto *FooVal = Env.getValue(*FooDecl);
3411-
const auto *BarVal = Env.getValue(*BarDecl);
3394+
const auto &FooVal = getValueForDecl(ASTCtx, Env, "Foo");
3395+
const auto &BarVal = getValueForDecl(ASTCtx, Env, "Bar");
34123396
EXPECT_TRUE(isa<IntegerValue>(FooVal));
34133397
EXPECT_TRUE(isa<BoolValue>(BarVal));
34143398
});
@@ -3426,23 +3410,38 @@ TEST(TransferTest, IntegralToBooleanCastFromBool) {
34263410
Code,
34273411
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &Results,
34283412
ASTContext &ASTCtx) {
3429-
ASSERT_THAT(Results.keys(), UnorderedElementsAre("p"));
34303413
const Environment &Env = getEnvironmentAtAnnotation(Results, "p");
34313414

3432-
const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
3433-
ASSERT_THAT(FooDecl, NotNull());
3434-
3435-
const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
3436-
ASSERT_THAT(BarDecl, NotNull());
3437-
3438-
const auto *FooVal = Env.getValue(*FooDecl);
3439-
const auto *BarVal = Env.getValue(*BarDecl);
3440-
EXPECT_TRUE(isa<BoolValue>(FooVal));
3441-
EXPECT_TRUE(isa<BoolValue>(BarVal));
3442-
EXPECT_EQ(FooVal, BarVal);
3415+
const auto &FooVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Foo");
3416+
const auto &BarVal = getValueForDecl<BoolValue>(ASTCtx, Env, "Bar");
3417+
EXPECT_EQ(&FooVal, &BarVal);
34433418
});
34443419
}
34453420

3421+
TEST(TransferTest, WidenBoolValueInIntegerVariable) {
3422+
// This is a crash repro.
3423+
// This test sets up a case where we perform widening on an integer variable
3424+
// that contains a `BoolValue` for the previous iteration and an
3425+
// `IntegerValue` for the current iteration. We used to crash on this because
3426+
// `widenDistinctValues()` assumed that if the previous iteration had a
3427+
// `BoolValue`, the current iteration would too.
3428+
// FIXME: The real fix here is to make sure we never store `BoolValue`s in
3429+
// integer variables; see also the comment in `widenDistinctValues()`.
3430+
std::string Code = R"cc(
3431+
struct S {
3432+
int i;
3433+
S *next;
3434+
};
3435+
void target(S *s) {
3436+
for (; s; s = s->next)
3437+
s->i = false;
3438+
}
3439+
)cc";
3440+
runDataflow(Code,
3441+
[](const llvm::StringMap<DataflowAnalysisState<NoopLattice>> &,
3442+
ASTContext &) {});
3443+
}
3444+
34463445
TEST(TransferTest, NullToPointerCast) {
34473446
std::string Code = R"(
34483447
using my_nullptr_t = decltype(nullptr);

0 commit comments

Comments
 (0)