23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/ADT/StringExtras.h"
25 #include "llvm/Support/raw_ostream.h"
27 using namespace clang;
36 CheckName CheckName_CallAndMessageUnInitRefArg;
37 CheckName CheckName_CallAndMessageChecker;
40 class CallAndMessageChecker
41 :
public Checker< check::PreStmt<CallExpr>,
42 check::PreStmt<CXXDeleteExpr>,
43 check::PreObjCMessage,
44 check::ObjCMessageNil,
46 mutable std::unique_ptr<BugType> BT_call_null;
47 mutable std::unique_ptr<BugType> BT_call_undef;
48 mutable std::unique_ptr<BugType> BT_cxx_call_null;
49 mutable std::unique_ptr<BugType> BT_cxx_call_undef;
50 mutable std::unique_ptr<BugType> BT_call_arg;
51 mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
52 mutable std::unique_ptr<BugType> BT_msg_undef;
53 mutable std::unique_ptr<BugType> BT_objc_prop_undef;
54 mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
55 mutable std::unique_ptr<BugType> BT_msg_arg;
56 mutable std::unique_ptr<BugType> BT_msg_ret;
57 mutable std::unique_ptr<BugType> BT_call_few_args;
75 const Expr *ArgEx,
int ArgumentNumber,
76 bool CheckUninitFields,
const CallEvent &Call,
77 std::unique_ptr<BugType> &BT,
88 void LazyInit_BT(
const char *desc, std::unique_ptr<BugType> &BT)
const {
94 std::unique_ptr<BugType> &BT,
96 int ArgumentNumber)
const;
106 auto R = llvm::make_unique<BugReport>(*BT, BT->
getName(), N);
118 llvm::raw_svector_ostream &Os) {
124 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
125 <<
" argument in message expression is an uninitialized value";
128 assert(Msg.
isSetter() &&
"Getters have no args");
129 Os <<
"Argument for property setter is an uninitialized value";
132 if (Msg.
isSetter() && (ArgumentNumber == 0))
133 Os <<
"Argument for subscript setter is an uninitialized value";
135 Os <<
"Subscript index is an uninitialized value";
138 llvm_unreachable(
"Unknown message kind.");
141 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
142 <<
" block call argument is an uninitialized value";
145 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
146 <<
" function call argument is an uninitialized value";
151 bool CallAndMessageChecker::uninitRefOrPointer(
153 std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl,
const char *BD,
154 int ArgumentNumber)
const {
155 if (!Filter.Check_CallAndMessageUnInitRefArg)
166 llvm::raw_svector_ostream Os(Buf);
169 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
170 <<
" function call argument is a pointer to uninitialized value";
172 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
173 <<
" function call argument is an uninitialized value";
182 const SVal PSV = State->getSVal(SValMemRegion);
186 auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
187 R->addRange(ArgRange);
204 bool CheckUninitFields,
206 std::unique_ptr<BugType> &BT,
209 const char *BD =
"Uninitialized argument value";
211 if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
220 llvm::raw_svector_ostream Os(Buf);
222 auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
224 R->addRange(ArgRange);
232 if (!CheckUninitFields)
238 class FindUninitializedField {
248 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
254 assert(RD &&
"Referred record has no definition");
255 for (
const auto *
I : RD->
fields()) {
257 FieldChain.push_back(
I);
268 FieldChain.pop_back();
277 FindUninitializedField F(C.
getState()->getStateManager().getStoreManager(),
285 llvm::raw_svector_ostream os(Str);
286 os <<
"Passed-by-value struct argument contains uninitialized data";
288 if (F.FieldChain.size() == 1)
289 os <<
" (e.g., field: '" << *F.FieldChain[0] <<
"')";
291 os <<
" (e.g., via the field chain: '";
294 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
305 auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
306 R->addRange(ArgRange);
319 void CallAndMessageChecker::checkPreStmt(
const CallExpr *CE,
325 SVal L = State->getSVal(Callee, LCtx);
330 this,
"Called function pointer is an uninitialized pointer value"));
331 emitBadCall(BT_call_undef.get(), C, Callee);
338 if (StNull && !StNonNull) {
341 this,
"Called function pointer is null (null dereference)"));
342 emitBadCall(BT_call_null.get(), C, Callee);
349 void CallAndMessageChecker::checkPreStmt(
const CXXDeleteExpr *DE,
358 if (!BT_cxx_delete_undef)
359 BT_cxx_delete_undef.reset(
360 new BuiltinBug(
this,
"Uninitialized argument value"));
362 Desc =
"Argument to 'delete[]' is uninitialized";
364 Desc =
"Argument to 'delete' is uninitialized";
365 BugType *BT = BT_cxx_delete_undef.get();
366 auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
373 void CallAndMessageChecker::checkPreCall(
const CallEvent &Call,
380 SVal V = CC->getCXXThisVal();
382 if (!BT_cxx_call_undef)
383 BT_cxx_call_undef.reset(
384 new BuiltinBug(
this,
"Called C++ object pointer is uninitialized"));
385 emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
390 std::tie(StNonNull, StNull) =
393 if (StNull && !StNonNull) {
394 if (!BT_cxx_call_null)
395 BT_cxx_call_null.reset(
396 new BuiltinBug(
this,
"Called C++ object pointer is null"));
397 emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
405 if (D && (isa<FunctionDecl>(D) || isa<BlockDecl>(D))) {
414 LazyInit_BT(
"Function call with too few arguments", BT_call_few_args);
417 llvm::raw_svector_ostream os(Str);
418 if (isa<FunctionDecl>(D)) {
421 assert(isa<BlockDecl>(D));
424 os <<
"taking " << Params <<
" argument"
425 << (Params == 1 ?
"" :
"s") <<
" is called with fewer ("
429 llvm::make_unique<BugReport>(*BT_call_few_args, os.str(), N));
437 const bool checkUninitFields =
440 std::unique_ptr<BugType> *BT;
441 if (isa<ObjCMethodCall>(Call))
446 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
447 for (
unsigned i = 0, e = Call.
getNumArgs(); i != e; ++i) {
449 if(FD && i < FD->getNumParams())
453 checkUninitFields, Call, *BT, ParamDecl))
461 void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
471 "Receiver in message expression "
472 "is an uninitialized value"));
473 BT = BT_msg_undef.get();
476 if (!BT_objc_prop_undef)
478 this,
"Property access on an uninitialized object pointer"));
479 BT = BT_objc_prop_undef.get();
482 if (!BT_objc_subscript_undef)
484 this,
"Subscript access on an uninitialized object pointer"));
485 BT = BT_objc_subscript_undef.get();
488 assert(BT &&
"Unknown message kind.");
490 auto R = llvm::make_unique<BugReport>(*BT, BT->
getName(), N);
492 R->addRange(ME->getReceiverRange());
495 if (
const Expr *ReceiverE = ME->getInstanceReceiver())
503 void CallAndMessageChecker::checkObjCMessageNil(
const ObjCMethodCall &msg,
505 HandleNilReceiver(C, C.
getState(), msg);
514 new BuiltinBug(
this,
"Receiver in message expression is 'nil'"));
518 QualType ResTy = msg.getResultType();
521 llvm::raw_svector_ostream os(buf);
522 os <<
"The receiver of message '";
526 os <<
", which results in forming a null reference";
528 os <<
" and returns a value of type '";
530 os <<
"' that will be garbage";
533 auto report = llvm::make_unique<BugReport>(*BT_msg_ret, os.str(), N);
543 return (triple.getVendor() == llvm::Triple::Apple &&
544 (triple.isiOS() || triple.isWatchOS() ||
545 !triple.isMacOSXVersionLT(10,5)));
556 QualType RetTy = Msg.getResultType();
560 if (CanRetTy->isStructureOrClassType()) {
572 const uint64_t returnTypeSize = Ctx.
getTypeSize(CanRetTy);
575 (voidPtrSize < returnTypeSize &&
583 emitNilReceiverBug(C, Msg, N);
608 #define REGISTER_CHECKER(name) \
609 void ento::register##name(CheckerManager &mgr) { \
610 CallAndMessageChecker *Checker = \
611 mgr.registerChecker<CallAndMessageChecker>(); \
612 Checker->Filter.Check_##name = true; \
613 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.
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
TypedValueRegion - An abstract class representing regions having a typed value.
const Expr * getDerefExpr(const Stmt *S)
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
A helper class which wraps a boolean value set to false by default.
for(unsigned I=0, E=TL.getNumArgs();I!=E;++I)
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
Decl - This represents one declaration (or definition), e.g.
virtual QualType getValueType() const =0
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
AnalysisManager & getAnalysisManager()
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.
RecordDecl - Represents a struct/union/class.
MemRegionManager & getRegionManager()
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool isReferenceType() const
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
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
bool isSetter() const
Returns true if this property access or subscript is a setter (has the form of an assignment)...
const TypedValueRegion * getRegion() const
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
detail::InMemoryDirectory::const_iterator I
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
#define REGISTER_CHECKER(name)
StringRef getName() const
Represents a non-static C++ member function call, no matter how it is written.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
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.
Expr - This represents one expression.
virtual ArrayRef< ParmVarDecl * > parameters() const =0
Return call's formal parameters.
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
getDefinition - Returns the RecordDecl that actually defines this struct/union/class.
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
bool isConsumedExpr(Expr *E) const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
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. ...
CanQualType UnsignedLongLongTy
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
const MemRegion * getAsRegion() const
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
Returns how the message was written in the source (property access, subscript, or explicit message se...
const RecordType * getAsStructureType() const
static bool supportsNilWithFloatRet(const llvm::Triple &triple)
const LangOptions & getLangOpts() const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
bool isArrayFormAsWritten() const
bool trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, BugReport &R, bool IsArg=false, bool EnableNullFPSuppression=true)
Attempts to add visitors to trace a null or undefined value back to its point of origin, whether it is a symbol constrained to null or an explicit assignment.
virtual unsigned getNumArgs() const =0
Returns the number of arguments (explicit and implicit).
static void describeUninitializedArgumentInCall(const CallEvent &Call, int ArgumentNumber, llvm::raw_svector_ostream &Os)
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SValBuilder & getSValBuilder()
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
A trivial tuple used to represent a source range.
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
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
IgnoreParens - Ignore parentheses.
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