Skip to content

Commit 3d0d2fe

Browse files
committed
analyzer][CallAndMessage][NFC] Change old callbacks to rely on CallEvent
The following series of patches has something similar in mind with D77474, with the same goal to finally end incorrect checker names for good. Despite CallAndMessage not suffering from this particular issue, it is a dependency for many other checkers, which is problematic, because we don't really want dependencies to also emit diagnostics (reasoning for this is also more detailed in D77474). CallAndMessage also has another problem, namely that it is responsible for a lot of reports. You'll soon learn that this isn't really easy to solve for compatibility reasons, but that is the topic of followup patches. Differential Revision: https://reviews.llvm.org/D77845
1 parent e89a08a commit 3d0d2fe

File tree

1 file changed

+69
-73
lines changed

1 file changed

+69
-73
lines changed

clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp

Lines changed: 69 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,18 @@
1111
//
1212
//===----------------------------------------------------------------------===//
1313

14-
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14+
#include "clang/AST/ExprCXX.h"
1515
#include "clang/AST/ParentMap.h"
1616
#include "clang/Basic/TargetInfo.h"
17+
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
1718
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1819
#include "clang/StaticAnalyzer/Core/Checker.h"
1920
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
2021
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
2122
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2223
#include "llvm/ADT/SmallString.h"
2324
#include "llvm/ADT/StringExtras.h"
25+
#include "llvm/Support/Casting.h"
2426
#include "llvm/Support/raw_ostream.h"
2527

2628
using namespace clang;
@@ -29,11 +31,8 @@ using namespace ento;
2931
namespace {
3032

3133
class CallAndMessageChecker
32-
: public Checker< check::PreStmt<CallExpr>,
33-
check::PreStmt<CXXDeleteExpr>,
34-
check::PreObjCMessage,
35-
check::ObjCMessageNil,
36-
check::PreCall > {
34+
: public Checker<check::PreObjCMessage, check::ObjCMessageNil,
35+
check::PreCall> {
3736
mutable std::unique_ptr<BugType> BT_call_null;
3837
mutable std::unique_ptr<BugType> BT_call_undef;
3938
mutable std::unique_ptr<BugType> BT_cxx_call_null;
@@ -48,11 +47,10 @@ class CallAndMessageChecker
4847
mutable std::unique_ptr<BugType> BT_call_few_args;
4948

5049
public:
51-
DefaultBool Check_CallAndMessageUnInitRefArg;
52-
CheckerNameRef CheckName_CallAndMessageUnInitRefArg;
50+
enum CheckKind { CK_CallAndMessageUnInitRefArg, CK_NumCheckKinds };
51+
52+
DefaultBool ChecksEnabled[CK_NumCheckKinds];
5353

54-
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
55-
void checkPreStmt(const CXXDeleteExpr *DE, CheckerContext &C) const;
5654
void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
5755

5856
/// Fill in the return value that results from messaging nil based on the
@@ -144,7 +142,7 @@ bool CallAndMessageChecker::uninitRefOrPointer(
144142
CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
145143
std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
146144
int ArgumentNumber) const {
147-
if (!Check_CallAndMessageUnInitRefArg)
145+
if (!ChecksEnabled[CK_CallAndMessageUnInitRefArg])
148146
return false;
149147

150148
// No parameter declaration available, i.e. variadic function argument.
@@ -311,63 +309,36 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
311309
return false;
312310
}
313311

314-
void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
315-
CheckerContext &C) const{
316-
317-
const Expr *Callee = CE->getCallee()->IgnoreParens();
312+
void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
313+
CheckerContext &C) const {
318314
ProgramStateRef State = C.getState();
319-
const LocationContext *LCtx = C.getLocationContext();
320-
SVal L = State->getSVal(Callee, LCtx);
321-
322-
if (L.isUndef()) {
323-
if (!BT_call_undef)
324-
BT_call_undef.reset(new BuiltinBug(
325-
this, "Called function pointer is an uninitialized pointer value"));
326-
emitBadCall(BT_call_undef.get(), C, Callee);
327-
return;
328-
}
329-
330-
ProgramStateRef StNonNull, StNull;
331-
std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
332-
333-
if (StNull && !StNonNull) {
334-
if (!BT_call_null)
335-
BT_call_null.reset(new BuiltinBug(
336-
this, "Called function pointer is null (null dereference)"));
337-
emitBadCall(BT_call_null.get(), C, Callee);
338-
return;
339-
}
340-
341-
C.addTransition(StNonNull);
342-
}
315+
if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr())) {
316+
const Expr *Callee = CE->getCallee()->IgnoreParens();
317+
const LocationContext *LCtx = C.getLocationContext();
318+
SVal L = State->getSVal(Callee, LCtx);
319+
320+
if (L.isUndef()) {
321+
if (!BT_call_undef)
322+
BT_call_undef.reset(new BuiltinBug(
323+
this, "Called function pointer is an uninitialized pointer value"));
324+
emitBadCall(BT_call_undef.get(), C, Callee);
325+
return;
326+
}
343327

344-
void CallAndMessageChecker::checkPreStmt(const CXXDeleteExpr *DE,
345-
CheckerContext &C) const {
328+
ProgramStateRef StNonNull, StNull;
329+
std::tie(StNonNull, StNull) =
330+
State->assume(L.castAs<DefinedOrUnknownSVal>());
346331

347-
SVal Arg = C.getSVal(DE->getArgument());
348-
if (Arg.isUndef()) {
349-
StringRef Desc;
350-
ExplodedNode *N = C.generateErrorNode();
351-
if (!N)
332+
if (StNull && !StNonNull) {
333+
if (!BT_call_null)
334+
BT_call_null.reset(new BuiltinBug(
335+
this, "Called function pointer is null (null dereference)"));
336+
emitBadCall(BT_call_null.get(), C, Callee);
352337
return;
353-
if (!BT_cxx_delete_undef)
354-
BT_cxx_delete_undef.reset(
355-
new BuiltinBug(this, "Uninitialized argument value"));
356-
if (DE->isArrayFormAsWritten())
357-
Desc = "Argument to 'delete[]' is uninitialized";
358-
else
359-
Desc = "Argument to 'delete' is uninitialized";
360-
BugType *BT = BT_cxx_delete_undef.get();
361-
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Desc, N);
362-
bugreporter::trackExpressionValue(N, DE, *R);
363-
C.emitReport(std::move(R));
364-
return;
365-
}
366-
}
338+
}
367339

368-
void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
369-
CheckerContext &C) const {
370-
ProgramStateRef State = C.getState();
340+
State = StNonNull;
341+
}
371342

372343
// If this is a call to a C++ method, check if the callee is null or
373344
// undefined.
@@ -425,6 +396,30 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
425396
}
426397
}
427398

399+
if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call)) {
400+
const CXXDeleteExpr *DE = DC->getOriginExpr();
401+
assert(DE);
402+
SVal Arg = C.getSVal(DE->getArgument());
403+
if (Arg.isUndef()) {
404+
StringRef Desc;
405+
ExplodedNode *N = C.generateErrorNode();
406+
if (!N)
407+
return;
408+
if (!BT_cxx_delete_undef)
409+
BT_cxx_delete_undef.reset(
410+
new BuiltinBug(this, "Uninitialized argument value"));
411+
if (DE->isArrayFormAsWritten())
412+
Desc = "Argument to 'delete[]' is uninitialized";
413+
else
414+
Desc = "Argument to 'delete' is uninitialized";
415+
BugType *BT = BT_cxx_delete_undef.get();
416+
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Desc, N);
417+
bugreporter::trackExpressionValue(N, DE, *R);
418+
C.emitReport(std::move(R));
419+
return;
420+
}
421+
}
422+
428423
// Don't check for uninitialized field values in arguments if the
429424
// caller has a body that is available and we have the chance to inline it.
430425
// This is a hack, but is a reasonable compromise betweens sometimes warning
@@ -444,8 +439,8 @@ void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
444439
if(FD && i < FD->getNumParams())
445440
ParamDecl = FD->getParamDecl(i);
446441
if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
447-
Call.getArgExpr(i), i,
448-
checkUninitFields, Call, *BT, ParamDecl))
442+
Call.getArgExpr(i), i, checkUninitFields, Call, *BT,
443+
ParamDecl))
449444
return;
450445
}
451446

@@ -609,12 +604,13 @@ bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
609604
return true;
610605
}
611606

612-
void ento::registerCallAndMessageUnInitRefArg(CheckerManager &mgr) {
613-
CallAndMessageChecker *Checker = mgr.getChecker<CallAndMessageChecker>();
614-
Checker->Check_CallAndMessageUnInitRefArg = true;
615-
Checker->CheckName_CallAndMessageUnInitRefArg = mgr.getCurrentCheckerName();
616-
}
607+
#define REGISTER_CHECKER(name) \
608+
void ento::register##name(CheckerManager &mgr) { \
609+
CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>(); \
610+
checker->ChecksEnabled[CallAndMessageChecker::CK_##name] = true; \
611+
\
612+
} \
613+
\
614+
bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
617615

618-
bool ento::shouldRegisterCallAndMessageUnInitRefArg(const CheckerManager &mgr) {
619-
return true;
620-
}
616+
REGISTER_CHECKER(CallAndMessageUnInitRefArg)

0 commit comments

Comments
 (0)