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
2628using namespace clang ;
@@ -29,11 +31,8 @@ using namespace ento;
2931namespace {
3032
3133class 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
5049public:
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