Skip to content

Commit 1c93b73

Browse files
committed
Add support for function calls that take a pointer-of-pointer argument
1 parent 268e913 commit 1c93b73

File tree

2 files changed

+70
-22
lines changed

2 files changed

+70
-22
lines changed

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

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -168,24 +168,21 @@ int fncall_reassignment(int *fncall_reassigned) {
168168
// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the pointer's value cannot be null
169169
*fncall_reassigned = 42;
170170
}
171-
172-
ptr_fn(&fncall_reassigned);
171+
172+
ref_fn(fncall_reassigned);
173173

174174
if (fncall_reassigned) {
175175
// FIXME: References of a pointer passed to external functions do not invalidate its value
176176
// CHECK-MESSAGES: :[[@LINE-2]]:7: warning: pointer value is checked even though it cannot be null at this point
177-
// CHECK-MESSAGES: :[[@LINE-8]]:5: note: one of the locations where the pointer's value cannot be null
178177
*fncall_reassigned = 42;
179178
}
180179

181180
*fncall_reassigned = 42;
182-
183-
ref_fn(fncall_reassigned);
181+
182+
ptr_fn(&fncall_reassigned);
184183

185184
if (fncall_reassigned) {
186-
// FIXME: References of a pointer passed to external functions do not invalidate its value
187-
// CHECK-MESSAGES: :[[@LINE-2]]:7: warning: pointer value is checked even though it cannot be null at this point
188-
// CHECK-MESSAGES: :[[@LINE-19]]:5: note: one of the locations where the pointer's value cannot be null
185+
// no-warning
189186
*fncall_reassigned = 42;
190187
}
191188

@@ -194,8 +191,7 @@ int fncall_reassignment(int *fncall_reassigned) {
194191

195192
if (fncall_reassigned) {
196193
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer value is checked even though it cannot be null at this point
197-
// FIXME: Better note tag support, preferably after the reassignment/refresh
198-
// CHECK-MESSAGES: :[[@LINE-29]]:5: note: one of the locations where the pointer's value cannot be null
194+
// CHECK-MESSAGES: :[[@LINE-4]]:3: note: one of the locations where the pointer's value cannot be null
199195
*fncall_reassigned = 42;
200196
return *fncall_reassigned;
201197
} else {

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

Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,9 @@ auto addressofMatcher() {
9999
}
100100

101101
auto functionCallMatcher() {
102-
return callExpr(hasDeclaration(functionDecl(returns(isAnyPointer()))))
103-
.bind(kVar);
102+
return callExpr(
103+
callee(functionDecl(hasAnyParameter(anyOf(hasType(pointerType()),
104+
hasType(referenceType()))))));
104105
}
105106

106107
auto assignMatcher() {
@@ -362,6 +363,49 @@ void matchAddressofExpr(const Expr *expr,
362363
RootValue->setProperty(kIsNonnull, Env.getBoolLiteralValue(true));
363364
}
364365

366+
void matchPtrArgFunctionExpr(const CallExpr *fncall,
367+
const MatchFinder::MatchResult &Result,
368+
Environment &Env) {
369+
// Inner storageloc, inner type
370+
fncall->dump();
371+
372+
for (const auto *Arg : fncall->arguments()) {
373+
// WrappedArg->dump();
374+
// const auto *Arg = WrappedArg->IgnoreCasts();
375+
Arg->dump();
376+
377+
// FIXME: Add handling for reference types as arguments
378+
if (Arg->getType()->isPointerType()) {
379+
llvm::errs() << (int)Env.getValue(*Arg)->getKind();
380+
PointerValue *OuterValue = cast_or_null<PointerValue>(
381+
Env.getValue(*Arg));
382+
383+
if (!OuterValue)
384+
continue;
385+
386+
QualType InnerType = Arg->getType()->getPointeeType();
387+
if (!InnerType->isPointerType())
388+
continue;
389+
390+
StorageLocation &InnerLoc = OuterValue->getPointeeLoc();
391+
392+
PointerValue *InnerValue =
393+
cast_or_null<PointerValue>(Env.getValue(InnerLoc));
394+
395+
if (!InnerValue)
396+
continue;
397+
398+
Value *NewValue = Env.createValue(InnerType);
399+
assert(NewValue && "Failed to re-initialize a pointer's value");
400+
401+
Env.setValue(InnerLoc, *NewValue);
402+
403+
// FIXME: Recursively invalidate all member pointers of eg. a struct
404+
// Should be part of the framework, most likely.
405+
}
406+
}
407+
}
408+
365409
void matchAnyPointerExpr(const Expr *fncall,
366410
const MatchFinder::MatchResult &Result,
367411
Environment &Env) {
@@ -502,7 +546,7 @@ auto buildTransferMatchSwitch() {
502546
.CaseOfCFGStmt<Stmt>(arrowMatcher(), matchDereferenceExpr)
503547
.CaseOfCFGStmt<Expr>(nullptrMatcher(), matchNullptrExpr)
504548
.CaseOfCFGStmt<Expr>(addressofMatcher(), matchAddressofExpr)
505-
.CaseOfCFGStmt<Expr>(functionCallMatcher(), matchAnyPointerExpr)
549+
.CaseOfCFGStmt<CallExpr>(functionCallMatcher(), matchPtrArgFunctionExpr)
506550
.CaseOfCFGStmt<Expr>(anyPointerMatcher(), matchAnyPointerExpr)
507551
.CaseOfCFGStmt<Expr>(castExprMatcher(), matchNullCheckExpr)
508552
.CaseOfCFGStmt<Expr>(nullCheckExprMatcher(), matchNullCheckExpr)
@@ -586,24 +630,32 @@ void NullPointerAnalysisModel::join(QualType Type, const Value &Val1,
586630
case SR::False:
587631
return MergedEnv.getBoolLiteralValue(false);
588632
case SR::Unknown:
589-
if (MergedEnv.proves(MergedEnv.arena().makeEquals(LHSVar->formula(),
590-
RHSVar->formula())))
591-
return *LHSVar;
592-
593-
return MergedEnv.makeTopBoolValue();
633+
break;
594634
}
595635
}
596636

637+
if (LHSVar && RHSVar &&
638+
MergedEnv.proves(MergedEnv.arena().makeEquals(LHSVar->formula(),
639+
RHSVar->formula()))) {
640+
return *LHSVar;
641+
}
642+
597643
return MergedEnv.makeTopBoolValue();
598644
};
599645

600646
BoolValue &NonnullValue = MergeValues(kIsNonnull);
601647
BoolValue &NullValue = MergeValues(kIsNull);
602648

603-
MergedVal.setProperty(kIsNonnull, NonnullValue);
604-
MergedVal.setProperty(kIsNull, NullValue);
605-
606-
MergedEnv.assume(MergedEnv.makeOr(NonnullValue, NullValue).formula());
649+
if (&NonnullValue == &MergedEnv.makeTopBoolValue() ||
650+
&NullValue == &MergedEnv.makeTopBoolValue()) {
651+
MergedVal.setProperty(kIsNonnull, MergedEnv.makeTopBoolValue());
652+
MergedVal.setProperty(kIsNull, MergedEnv.makeTopBoolValue());
653+
} else {
654+
MergedVal.setProperty(kIsNonnull, NonnullValue);
655+
MergedVal.setProperty(kIsNull, NullValue);
656+
657+
MergedEnv.assume(MergedEnv.makeOr(NonnullValue, NullValue).formula());
658+
}
607659
}
608660

609661
ComparisonResult NullPointerAnalysisModel::compare(QualType Type,

0 commit comments

Comments
 (0)