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,
43 check::ObjCMessageNil,
45 mutable std::unique_ptr<BugType> BT_call_null;
46 mutable std::unique_ptr<BugType> BT_call_undef;
47 mutable std::unique_ptr<BugType> BT_cxx_call_null;
48 mutable std::unique_ptr<BugType> BT_cxx_call_undef;
49 mutable std::unique_ptr<BugType> BT_call_arg;
50 mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
51 mutable std::unique_ptr<BugType> BT_msg_undef;
52 mutable std::unique_ptr<BugType> BT_objc_prop_undef;
53 mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
54 mutable std::unique_ptr<BugType> BT_msg_arg;
55 mutable std::unique_ptr<BugType> BT_msg_ret;
56 mutable std::unique_ptr<BugType> BT_call_few_args;
74 const Expr *ArgEx,
bool IsFirstArgument,
75 bool CheckUninitFields,
const CallEvent &Call,
76 std::unique_ptr<BugType> &BT,
87 void LazyInit_BT(
const char *desc, std::unique_ptr<BugType> &BT)
const {
93 const Expr *ArgEx, std::unique_ptr<BugType> &BT,
94 const ParmVarDecl *ParamDecl,
const char *BD)
const;
104 auto R = llvm::make_unique<BugReport>(*BT, BT->
getName(), N);
106 R->addRange(BadE->getSourceRange());
115 bool IsFirstArgument) {
121 return "Argument in message expression is an uninitialized value";
123 assert(Msg.
isSetter() &&
"Getters have no args");
124 return "Argument for property setter is an uninitialized value";
126 if (Msg.
isSetter() && IsFirstArgument)
127 return "Argument for subscript setter is an uninitialized value";
128 return "Subscript index is an uninitialized value";
130 llvm_unreachable(
"Unknown message kind.");
133 return "Block call argument is an uninitialized value";
135 return "Function call argument is an uninitialized value";
143 std::unique_ptr<BugType> &BT,
145 const char *BD)
const {
146 if (!Filter.Check_CallAndMessageUnInitRefArg)
159 Message =
"Function call argument is a pointer to uninitialized value";
161 Message =
"Function call argument is an uninitialized value";
170 const SVal PSV = State->getSVal(SValMemRegion);
174 auto R = llvm::make_unique<BugReport>(*BT, Message, N);
175 R->addRange(ArgRange);
191 bool IsFirstArgument,
192 bool CheckUninitFields,
194 std::unique_ptr<BugType> &BT,
197 const char *BD =
"Uninitialized argument value";
199 if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD))
209 auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
210 R->addRange(ArgRange);
218 if (!CheckUninitFields)
224 class FindUninitializedField {
234 : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
240 assert(RD &&
"Referred record has no definition");
241 for (
const auto *
I : RD->
fields()) {
243 FieldChain.push_back(
I);
254 FieldChain.pop_back();
263 FindUninitializedField F(C.
getState()->getStateManager().getStoreManager(),
271 llvm::raw_svector_ostream os(Str);
272 os <<
"Passed-by-value struct argument contains uninitialized data";
274 if (F.FieldChain.size() == 1)
275 os <<
" (e.g., field: '" << *F.FieldChain[0] <<
"')";
277 os <<
" (e.g., via the field chain: '";
280 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
291 auto R = llvm::make_unique<BugReport>(*BT, os.str(), N);
292 R->addRange(ArgRange);
305 void CallAndMessageChecker::checkPreStmt(
const CallExpr *CE,
311 SVal L = State->getSVal(Callee, LCtx);
316 this,
"Called function pointer is an uninitialized pointer value"));
317 emitBadCall(BT_call_undef.get(), C, Callee);
324 if (StNull && !StNonNull) {
327 this,
"Called function pointer is null (null dereference)"));
328 emitBadCall(BT_call_null.get(), C, Callee);
335 void CallAndMessageChecker::checkPreStmt(
const CXXDeleteExpr *DE,
344 if (!BT_cxx_delete_undef)
345 BT_cxx_delete_undef.reset(
346 new BuiltinBug(
this,
"Uninitialized argument value"));
348 Desc =
"Argument to 'delete[]' is uninitialized";
350 Desc =
"Argument to 'delete' is uninitialized";
351 BugType *BT = BT_cxx_delete_undef.get();
352 auto R = llvm::make_unique<BugReport>(*BT, Desc, N);
360 void CallAndMessageChecker::checkPreCall(
const CallEvent &Call,
367 SVal V = CC->getCXXThisVal();
369 if (!BT_cxx_call_undef)
370 BT_cxx_call_undef.reset(
371 new BuiltinBug(
this,
"Called C++ object pointer is uninitialized"));
372 emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
377 std::tie(StNonNull, StNull) =
380 if (StNull && !StNonNull) {
381 if (!BT_cxx_call_null)
382 BT_cxx_call_null.reset(
383 new BuiltinBug(
this,
"Called C++ object pointer is null"));
384 emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
392 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
402 LazyInit_BT(
"Function call with too few arguments", BT_call_few_args);
405 llvm::raw_svector_ostream os(Str);
406 os <<
"Function taking " << Params <<
" argument"
407 << (Params == 1 ?
"" :
"s") <<
" is called with less ("
411 llvm::make_unique<BugReport>(*BT_call_few_args, os.str(), N));
419 const bool checkUninitFields =
422 std::unique_ptr<BugType> *BT;
423 if (isa<ObjCMethodCall>(Call))
428 for (
unsigned i = 0, e = Call.
getNumArgs(); i != e; ++i) {
430 if(FD && i < FD->getNumParams())
434 checkUninitFields, Call, *BT, ParamDecl))
442 void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
452 "Receiver in message expression "
453 "is an uninitialized value"));
454 BT = BT_msg_undef.get();
457 if (!BT_objc_prop_undef)
459 this,
"Property access on an uninitialized object pointer"));
460 BT = BT_objc_prop_undef.get();
463 if (!BT_objc_subscript_undef)
465 this,
"Subscript access on an uninitialized object pointer"));
466 BT = BT_objc_subscript_undef.get();
469 assert(BT &&
"Unknown message kind.");
471 auto R = llvm::make_unique<BugReport>(*BT, BT->
getName(), N);
473 R->addRange(ME->getReceiverRange());
476 if (
const Expr *ReceiverE = ME->getInstanceReceiver())
484 void CallAndMessageChecker::checkObjCMessageNil(
const ObjCMethodCall &msg,
486 HandleNilReceiver(C, C.
getState(), msg);
495 new BuiltinBug(
this,
"Receiver in message expression is 'nil'"));
499 QualType ResTy = msg.getResultType();
502 llvm::raw_svector_ostream os(buf);
503 os <<
"The receiver of message '";
507 os <<
", which results in forming a null reference";
509 os <<
" and returns a value of type '";
511 os <<
"' that will be garbage";
514 auto report = llvm::make_unique<BugReport>(*BT_msg_ret, os.str(), N);
524 return (triple.getVendor() == llvm::Triple::Apple &&
525 (triple.isiOS() || triple.isWatchOS() ||
526 !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.
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.
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
virtual QualType getValueType() const =0
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
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.
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.
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
unsigned getNumParams() const
getNumParams - Return the number of parameters this function must have based on its FunctionType...
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
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
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
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).
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
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