Skip to content

Commit b5a09ac

Browse files
committed
Better top-bool- and generic-value handling
1 parent 911e659 commit b5a09ac

File tree

2 files changed

+37
-24
lines changed

2 files changed

+37
-24
lines changed

clang-tools-extra/test/clang-tidy/checkers/bugprone/null-check-after-dereference.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ int fncall_reassignment(int *fncall_reassigned) {
156156
fncall_reassigned = external_fn();
157157

158158
if (fncall_reassigned) {
159+
// no-warning
159160
*fncall_reassigned = 42;
160161
}
161162

clang/lib/Analysis/FlowSensitive/Models/NullPointerAnalysisModel.cpp

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,8 @@ void setUnknownValue(const Expr &E, Value &Val, Environment &Env) {
211211
Env.setValue(E, Val);
212212
}
213213

214+
// Gets a pointer's value, and initializes it to (Unknown, Unknown) if it hasn't
215+
// been initialized already.
214216
Value *getValue(const Expr &Var, Environment &Env) {
215217
if (Value *EnvVal = Env.getValue(Var)) {
216218
// FIXME: The framework usually creates the values for us, but without the
@@ -220,13 +222,20 @@ Value *getValue(const Expr &Var, Environment &Env) {
220222
return EnvVal;
221223
}
222224

223-
Value *RootValue = Env.createValue(Var.getType());
225+
return nullptr;
224226

225-
initializeRootValue(*RootValue, Env);
226-
227-
setUnknownValue(Var, *RootValue, Env);
227+
// Value *RootValue = Env.createValue(Var.getType());
228+
//
229+
// initializeRootValue(*RootValue, Env);
230+
//
231+
// setUnknownValue(Var, *RootValue, Env);
232+
//
233+
// return RootValue;
234+
}
228235

229-
return RootValue;
236+
bool hasTopOrNullValue(const Value *Val, const Environment &Env) {
237+
return !Val || isa_and_present<TopBoolValue>(Val->getProperty(kIsNull)) ||
238+
isa_and_present<TopBoolValue>(Val->getProperty(kIsNonnull));
230239
}
231240

232241
void matchDereferenceExpr(const Stmt *stmt,
@@ -236,12 +245,11 @@ void matchDereferenceExpr(const Stmt *stmt,
236245
assert(Var != nullptr);
237246

238247
Value *RootValue = getValue(*Var, Env);
248+
if (hasTopOrNullValue(RootValue, Env))
249+
return;
239250

240251
BoolValue &IsNull = getVal(kIsNull, *RootValue);
241252

242-
if (&IsNull == &Env.makeTopBoolValue())
243-
return;
244-
245253
Env.assume(Env.arena().makeNot(IsNull.formula()));
246254
}
247255

@@ -259,15 +267,13 @@ void matchNullCheckExpr(const Expr *NullCheck,
259267
}
260268

261269
Value *RootValue = getValue(*Var, Env);
270+
if (hasTopOrNullValue(RootValue, Env))
271+
return;
262272

263273
Arena &A = Env.arena();
264274
BoolValue &IsNonnull = getVal(kIsNonnull, *RootValue);
265275
BoolValue &IsNull = getVal(kIsNull, *RootValue);
266276

267-
if (&IsNonnull == &Env.makeTopBoolValue() ||
268-
&IsNull == &Env.makeTopBoolValue())
269-
return;
270-
271277
BoolValue *CondValue = cast_or_null<BoolValue>(Env.getValue(*NullCheck));
272278
if (!CondValue) {
273279
CondValue = &A.makeAtomValue();
@@ -296,17 +302,14 @@ void matchEqualExpr(const BinaryOperator *EqualExpr,
296302
Value *LHSValue = getValue(*LHSVar, Env);
297303
Value *RHSValue = getValue(*RHSVar, Env);
298304

305+
if (hasTopOrNullValue(LHSValue, Env) || hasTopOrNullValue(RHSValue, Env))
306+
return;
307+
299308
BoolValue &LHSNonnull = getVal(kIsNonnull, *LHSValue);
300309
BoolValue &LHSNull = getVal(kIsNull, *LHSValue);
301310
BoolValue &RHSNonnull = getVal(kIsNonnull, *RHSValue);
302311
BoolValue &RHSNull = getVal(kIsNull, *RHSValue);
303312

304-
if (&LHSNonnull == &Env.makeTopBoolValue() ||
305-
&RHSNonnull == &Env.makeTopBoolValue() ||
306-
&LHSNull == &Env.makeTopBoolValue() ||
307-
&RHSNull == &Env.makeTopBoolValue())
308-
return;
309-
310313
BoolValue *CondValue = cast_or_null<BoolValue>(Env.getValue(*EqualExpr));
311314
if (!CondValue) {
312315
CondValue = &A.makeAtomValue();
@@ -349,6 +352,7 @@ void matchAddressofExpr(const Expr *expr,
349352
const auto *Var = Result.Nodes.getNodeAs<Expr>(kVar);
350353
assert(Var != nullptr);
351354

355+
// FIXME: Use atoms or export to separate function
352356
Value *RootValue = Env.getValue(*Var);
353357
if (!RootValue) {
354358
RootValue = Env.createValue(Var->getType());
@@ -397,7 +401,8 @@ void matchPtrArgFunctionExpr(const CallExpr *fncall,
397401
}
398402
}
399403

400-
if (fncall->getCallReturnType(*Result.Context)->isPointerType()) {
404+
if (fncall->getCallReturnType(*Result.Context)->isPointerType() &&
405+
!Env.getValue(*fncall)) {
401406
Value *RootValue = Env.createValue(
402407
fncall->getCallReturnType(*Result.Context));
403408
if (!RootValue)
@@ -415,13 +420,15 @@ void matchAnyPointerExpr(const Expr *fncall,
415420
const auto *Var = Result.Nodes.getNodeAs<Expr>(kVar);
416421
assert(Var != nullptr);
417422

418-
// Initialize to (Unknown, Unknown)
423+
// In some cases, prvalues are not automatically initialized
424+
// Initialize these values, but don't set null-ness values for performance
419425
if (Env.getValue(*Var))
420426
return;
421427

422428
Value *RootValue = Env.createValue(Var->getType());
429+
if (!RootValue)
430+
return;
423431

424-
// initializeRootValue(*RootValue, Env);
425432
setUnknownValue(*Var, *RootValue, Env);
426433
}
427434

@@ -527,12 +534,14 @@ diagnoseEqualExpr(const Expr *PtrCheck, const MatchFinder::MatchResult &Result,
527534
std::vector<SourceLocation> NullVarLocations;
528535

529536
if (Value *LHSValue = Env.getValue(*LHSVar);
537+
LHSValue->getProperty(kIsNonnull) &&
530538
Env.proves(A.makeNot(getVal(kIsNonnull, *LHSValue).formula()))) {
531539
WarningLocToVal.try_emplace(LHSVar->getBeginLoc(), LHSValue);
532540
NullVarLocations.push_back(LHSVar->getBeginLoc());
533541
}
534542

535543
if (Value *RHSValue = Env.getValue(*RHSVar);
544+
RHSValue->getProperty(kIsNonnull) &&
536545
Env.proves(A.makeNot(getVal(kIsNonnull, *RHSValue).formula()))) {
537546
WarningLocToVal.try_emplace(RHSVar->getBeginLoc(), RHSValue);
538547
NullVarLocations.push_back(RHSVar->getBeginLoc());
@@ -647,8 +656,7 @@ void NullPointerAnalysisModel::join(QualType Type, const Value &Val1,
647656
BoolValue &NonnullValue = MergeValues(kIsNonnull);
648657
BoolValue &NullValue = MergeValues(kIsNull);
649658

650-
if (&NonnullValue == &MergedEnv.makeTopBoolValue() ||
651-
&NullValue == &MergedEnv.makeTopBoolValue()) {
659+
if (isa<TopBoolValue>(NonnullValue) || isa<TopBoolValue>(NullValue)) {
652660
MergedVal.setProperty(kIsNonnull, MergedEnv.makeTopBoolValue());
653661
MergedVal.setProperty(kIsNull, MergedEnv.makeTopBoolValue());
654662
} else {
@@ -673,8 +681,12 @@ ComparisonResult NullPointerAnalysisModel::compare(QualType Type,
673681
auto *LHSVar = cast_or_null<BoolValue>(Val1.getProperty(Name));
674682
auto *RHSVar = cast_or_null<BoolValue>(Val2.getProperty(Name));
675683

684+
if (isa_and_present<TopBoolValue>(LHSVar) ||
685+
isa_and_present<TopBoolValue>(RHSVar))
686+
return CR::Top;
687+
676688
if (LHSVar == RHSVar)
677-
return (LHSVar == &Env1.makeTopBoolValue()) ? CR::Top : CR::Same;
689+
return CR::Same;
678690

679691
SatisfiabilityResult LHSResult = computeSatisfiability(LHSVar, Env1);
680692
SatisfiabilityResult RHSResult = computeSatisfiability(RHSVar, Env2);

0 commit comments

Comments
 (0)