23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Support/raw_ostream.h"
26 using namespace clang;
35 CheckName CheckName_CallAndMessageUnInitRefArg;
36 CheckName CheckName_CallAndMessageChecker;
39 class CallAndMessageChecker
40 :
public Checker< check::PreStmt<CallExpr>,
41 check::PreStmt<CXXDeleteExpr>,
42 check::PreObjCMessage,
44 mutable std::unique_ptr<BugType> BT_call_null;
45 mutable std::unique_ptr<BugType> BT_call_undef;
46 mutable std::unique_ptr<BugType> BT_cxx_call_null;
47 mutable std::unique_ptr<BugType> BT_cxx_call_undef;
48 mutable std::unique_ptr<BugType> BT_call_arg;
49 mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
50 mutable std::unique_ptr<BugType> BT_msg_undef;
51 mutable std::unique_ptr<BugType> BT_objc_prop_undef;
52 mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
53 mutable std::unique_ptr<BugType> BT_msg_arg;
54 mutable std::unique_ptr<BugType> BT_msg_ret;
55 mutable std::unique_ptr<BugType> BT_call_few_args;
67 const Expr *ArgEx,
bool IsFirstArgument,
68 bool CheckUninitFields,
const CallEvent &Call,
69 std::unique_ptr<BugType> &BT,
80 void LazyInit_BT(
const char *desc, std::unique_ptr<BugType> &BT)
const {
86 const Expr *ArgEx, std::unique_ptr<BugType> &BT,
87 const ParmVarDecl *ParamDecl,
const char *BD)
const;
97 auto R = llvm::make_unique<BugReport>(*BT, BT->
getName(), N);
99 R->addRange(BadE->getSourceRange());
108 bool IsFirstArgument) {
114 return "Argument in message expression is an uninitialized value";
116 assert(Msg.
isSetter() &&
"Getters have no args");
117 return "Argument for property setter is an uninitialized value";
119 if (Msg.
isSetter() && IsFirstArgument)
120 return "Argument for subscript setter is an uninitialized value";
121 return "Subscript index is an uninitialized value";
123 llvm_unreachable(
"Unknown message kind.");
126 return "Block call argument is an uninitialized value";
128 return "Function call argument is an uninitialized value";
136 std::unique_ptr<BugType> &BT,
138 const char *BD)
const {
139 if (!Filter.Check_CallAndMessageUnInitRefArg)
152 Message =
"Function call argument is a pointer to uninitialized value";
154 Message =
"Function call argument is an uninitialized value";
163 const SVal PSV = State->getSVal(SValMemRegion);
167 auto R = llvm::make_unique<BugReport>(*BT, Message, N);
168 R->addRange(ArgRange);
184 bool IsFirstArgument,
185 bool CheckUninitFields,
187 std::unique_ptr<BugType> &BT,
190 const char *BD =
"Uninitialized argument value";
192 if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
202 auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
203 R->addRange(ArgRange);
211 if (!CheckUninitFields)
217 class FindUninitializedField {
227 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
233 assert(RD &&
"Referred record has no definition");
234 for (
const auto *I : RD->
fields()) {
235 const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
236 FieldChain.push_back(I);
247 FieldChain.pop_back();
256 FindUninitializedField F(C.
getState()->getStateManager().getStoreManager(),
264 llvm::raw_svector_ostream os(Str);
265 os <<
"Passed-by-value struct argument contains uninitialized data";
267 if (F.FieldChain.size() == 1)
268 os <<
" (e.g., field: '" << *F.FieldChain[0] <<
"')";
270 os <<
" (e.g., via the field chain: '";
273 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
284 auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
285 R->addRange(ArgRange);
298 void CallAndMessageChecker::checkPreStmt(
const CallExpr *CE,
304 SVal L = State->getSVal(Callee, LCtx);
309 this,
"Called function pointer is an uninitalized pointer value"));
310 emitBadCall(BT_call_undef.get(),
C, Callee);
317 if (StNull && !StNonNull) {
320 this,
"Called function pointer is null (null dereference)"));
321 emitBadCall(BT_call_null.get(),
C, Callee);
328 void CallAndMessageChecker::checkPreStmt(
const CXXDeleteExpr *DE,
337 if (!BT_cxx_delete_undef)
338 BT_cxx_delete_undef.reset(
339 new BuiltinBug(
this,
"Uninitialized argument value"));
341 Desc =
"Argument to 'delete[]' is uninitialized";
343 Desc =
"Argument to 'delete' is uninitialized";
344 BugType *BT = BT_cxx_delete_undef.get();
345 auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
353 void CallAndMessageChecker::checkPreCall(
const CallEvent &Call,
360 SVal V = CC->getCXXThisVal();
362 if (!BT_cxx_call_undef)
363 BT_cxx_call_undef.reset(
364 new BuiltinBug(
this,
"Called C++ object pointer is uninitialized"));
365 emitBadCall(BT_cxx_call_undef.get(),
C, CC->getCXXThisExpr());
370 std::tie(StNonNull, StNull) =
373 if (StNull && !StNonNull) {
374 if (!BT_cxx_call_null)
375 BT_cxx_call_null.reset(
376 new BuiltinBug(
this,
"Called C++ object pointer is null"));
377 emitBadCall(BT_cxx_call_null.get(),
C, CC->getCXXThisExpr());
385 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
395 LazyInit_BT(
"Function call with too few arguments", BT_call_few_args);
398 llvm::raw_svector_ostream os(Str);
399 os <<
"Function taking " << Params <<
" argument"
400 << (Params == 1 ?
"" :
"s") <<
" is called with less ("
404 llvm::make_unique<BugReport>(*BT_call_few_args, os.str(), N));
412 const bool checkUninitFields =
415 std::unique_ptr<BugType> *BT;
416 if (isa<ObjCMethodCall>(Call))
421 for (
unsigned i = 0, e = Call.
getNumArgs(); i != e; ++i) {
423 if(FD && i < FD->getNumParams())
427 checkUninitFields, Call, *BT, ParamDecl))
435 void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
445 "Receiver in message expression "
446 "is an uninitialized value"));
447 BT = BT_msg_undef.get();
450 if (!BT_objc_prop_undef)
452 this,
"Property access on an uninitialized object pointer"));
453 BT = BT_objc_prop_undef.get();
456 if (!BT_objc_subscript_undef)
458 this,
"Subscript access on an uninitialized object pointer"));
459 BT = BT_objc_subscript_undef.get();
462 assert(BT &&
"Unknown message kind.");
464 auto R = llvm::make_unique<BugReport>(*BT, BT->
getName(), N);
466 R->addRange(ME->getReceiverRange());
469 if (
const Expr *ReceiverE = ME->getInstanceReceiver())
480 std::tie(notNilState, nilState) = state->assume(receiverVal);
483 if (nilState && !notNilState) {
484 HandleNilReceiver(C, state, msg);
496 new BuiltinBug(
this,
"Receiver in message expression is 'nil'"));
500 QualType ResTy = msg.getResultType();
503 llvm::raw_svector_ostream os(buf);
504 os <<
"The receiver of message '";
508 os <<
", which results in forming a null reference";
510 os <<
" and returns a value of type '";
512 os <<
"' that will be garbage";
515 auto report = llvm::make_unique<BugReport>(*BT_msg_ret, os.str(), N);
525 return (triple.getVendor() == llvm::Triple::Apple &&
526 (triple.isiOS() || !triple.isMacOSXVersionLT(10,5)));
537 QualType RetTy = Msg.getResultType();
541 if (CanRetTy->isStructureOrClassType()) {
553 const uint64_t returnTypeSize = Ctx.
getTypeSize(CanRetTy);
556 (voidPtrSize < returnTypeSize &&
564 emitNilReceiverBug(C, Msg, N);
589 #define REGISTER_CHECKER(name) \
590 void ento::register##name(CheckerManager &mgr) { \
591 CallAndMessageChecker *Checker = \
592 mgr.registerChecker<CallAndMessageChecker>(); \
593 Checker->Filter.Check_##name = true; \
594 Checker->Filter.CheckName_##name = mgr.getCurrentCheckName(); \
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
TypedValueRegion - An abstract class representing regions having a typed value.
const Expr * getDerefExpr(const Stmt *S)
MemRegion - The root abstract class for all memory regions.
A helper class which wraps a boolean value set to false by default.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph). Uses the default CheckerContex...
virtual QualType getValueType() const =0
AnalysisManager & getAnalysisManager()
static StringRef describeUninitializedArgumentInCall(const CallEvent &Call, bool IsFirstArgument)
const Expr * getCallee() const
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
const void * getStore() const
ParmVarDecl - Represents a parameter to a function.
MemRegionManager & getRegionManager()
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool isReferenceType() const
Represents any expression that calls an Objective-C method.
bool shouldInlineCall() const
const TargetInfo & getTargetInfo() const
virtual Kind getKind() const =0
Returns the kind of call this is.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
field_range fields() const
Selector getSelector() const
const TypedValueRegion * getRegion() const
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
#define REGISTER_CHECKER(name)
StringRef getName() const
ExplodedNode * generateSink(ProgramStateRef State=nullptr, ExplodedNode *Pred=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a sink node. Generating a sink stops exploration of the given path.
Represents a non-static C++ member function call, no matter how it is written.
QualType getPointeeType() const
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument. May be null if this expression does not appe...
const ProgramStateRef & getState() const
SourceRange getReceiverRange() const
Source range of the receiver.
ParentMap & getParentMap() const
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
const ParmVarDecl * getParamDecl(unsigned i) const
An expression that sends a message to the given Objective-C object or class.
RecordDecl * getDefinition() const
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
bool isConsumedExpr(Expr *E) const
unsigned getNumParams() const
virtual Stmt * getBody() const
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called. May be null.
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
ASTContext & getASTContext()
Represents a delete expression for memory deallocation and destructor calls, e.g. "delete[] pArray"...
CanQualType UnsignedLongLongTy
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
const MemRegion * getAsRegion() const
for(auto typeArg:T->getTypeArgsAsWritten())
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
Represents an abstract call to a function or method along a particular path.
ObjCMessageKind getMessageKind() const
const RecordType * getAsStructureType() const
static bool supportsNilWithFloatRet(const llvm::Triple &triple)
const LangOptions & getLangOpts() const
bool isArrayFormAsWritten() const
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, bool IsArg=false, bool EnableNullFPSuppression=true)
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
SValBuilder & getSValBuilder()
Defines the clang::TargetInfo interface.
A trivial tuple used to represent a source range.
bool isConstQualified() const
Determine whether this type is const-qualified.
virtual const ObjCMessageExpr * getOriginExpr() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
Expr * IgnoreParens() LLVM_READONLY
const LocationContext * getLocationContext() const
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
bool isPointerType() const