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);
110 BadE = bugreporter::getDerefExpr(BadE);
111 bugreporter::trackNullOrUndefValue(N, BadE, *R);
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";
186 auto R = llvm::make_unique<BugReport>(*BT, Os.str(), N);
187 R->addRange(ArgRange);
189 bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
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);
226 bugreporter::trackNullOrUndefValue(N, ArgEx, *R);
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);
367 bugreporter::trackNullOrUndefValue(N, DE, *R);
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())
496 bugreporter::trackNullOrUndefValue(N, ReceiverE, *R);
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);
537 bugreporter::trackNullOrUndefValue(N, receiver, *report);
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(); \
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
Represents a function declaration or definition.
TypedValueRegion - An abstract class representing regions having a typed value.
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.
Selector getSelector() const
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
bool isArrayFormAsWritten() const
A helper class which wraps a boolean value set to false by default.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
const void * getStore() const
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 RecordType * getAsStructureType() const
const TargetInfo & getTargetInfo() const
AnalysisManager & getAnalysisManager()
bool isConsumedExpr(Expr *E) const
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
virtual SVal getBinding(Store store, Loc loc, QualType T=QualType())=0
Return the value bound to specified location in a given state.
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
Represents a parameter to a function.
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 ...
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
field_range fields() const
StringRef getName() const
bool isReferenceType() const
virtual const Expr * getArgExpr(unsigned Index) const
Returns the expression associated with a given argument.
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.
virtual Kind getKind() const =0
Returns the kind of call this is.
bool isSetter() const
Returns true if this property access or subscript is a setter (has the form of an assignment)...
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
virtual ArrayRef< ParmVarDecl * > parameters() const =0
Return call's formal parameters.
#define REGISTER_CHECKER(name)
Represents a non-static C++ member function call, no matter how it is written.
for(unsigned I=0, E=TL.getNumArgs();I !=E;++I)
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
Expr - This represents one expression.
const Expr * getCallee() const
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
virtual const Decl * getDecl() const
Returns the declaration of the function or method that will be called.
An expression that sends a message to the given Objective-C object or class.
const TypedValueRegion * getRegion() const
ParentMap & getParentMap() const
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
bool isConstQualified() const
Determine whether this type is const-qualified.
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
const MemRegion * getAsRegion() const
const ParmVarDecl * getParamDecl(unsigned i) const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
virtual const ObjCMessageExpr * getOriginExpr() const
Dataflow Directional Tag Classes.
ASTContext & getASTContext()
virtual SourceRange getArgSourceRange(unsigned Index) const
Returns the source range for errors associated with this argument.
Represents a delete expression for memory deallocation and destructor calls, e.g. ...
CanQualType UnsignedLongLongTy
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...
SourceRange getReceiverRange() const
Source range of the receiver.
static bool supportsNilWithFloatRet(const llvm::Triple &triple)
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
const ProgramStateRef & getState() const
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
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)
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]).
bool isPointerType() const
virtual SVal getArgSVal(unsigned Index) const
Returns the value of a given argument at the time of the call.
A trivial tuple used to represent a source range.
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
const LocationContext * getLocationContext() const
const LangOptions & getLangOpts() const
const FieldRegion * getFieldRegion(const FieldDecl *fd, const SubRegion *superRegion)
getFieldRegion - Retrieve or create the memory region associated with a specified FieldDecl...
Expr * IgnoreParens() LLVM_READONLY
IgnoreParens - Ignore parentheses.
bool shouldInlineCall() const