23#include "llvm/ADT/StringExtras.h"
24#include "llvm/Support/raw_ostream.h"
31class CallAndMessageChecker
32 :
public Checker<check::PreObjCMessage, check::ObjCMessageNil,
34 const BugType CallNullBug{
35 this,
"Called function pointer is null (null dereference)"};
36 const BugType CallUndefBug{
37 this,
"Called function pointer is an uninitialized pointer value"};
38 const BugType CXXCallNullBug{
this,
"Called C++ object pointer is null"};
39 const BugType CXXCallUndefBug{
this,
40 "Called C++ object pointer is uninitialized"};
41 const BugType CallArgBug{
this,
"Uninitialized argument value"};
42 const BugType CXXDeleteUndefBug{
this,
"Uninitialized argument value"};
43 const BugType MsgUndefBug{
44 this,
"Receiver in message expression is an uninitialized value"};
45 const BugType ObjCPropUndefBug{
46 this,
"Property access on an uninitialized object pointer"};
47 const BugType ObjCSubscriptUndefBug{
48 this,
"Subscript access on an uninitialized object pointer"};
49 const BugType MsgArgBug{
this,
"Uninitialized argument value"};
50 const BugType MsgRetBug{
this,
"Receiver in message expression is 'nil'"};
51 const BugType CallFewArgsBug{
this,
"Function call with too few arguments"};
70 CK_CXXDeallocationArg,
71 CK_ArgInitializedness,
72 CK_ArgPointeeInitializedness,
78 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
80 void checkPreObjCMessage(
const ObjCMethodCall &msg, CheckerContext &
C)
const;
85 void checkObjCMessageNil(
const ObjCMethodCall &msg, CheckerContext &
C)
const;
87 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
109 bool PreVisitProcessArg(CheckerContext &
C, SVal
V, SourceRange ArgRange,
110 const Expr *ArgEx,
int ArgumentNumber,
111 bool CheckUninitFields,
const CallEvent &
Call,
113 const ParmVarDecl *ParamDecl)
const;
115 static void emitBadCall(
const BugType &BT, CheckerContext &
C,
117 void emitNilReceiverBug(CheckerContext &
C,
const ObjCMethodCall &msg,
118 ExplodedNode *N)
const;
120 void HandleNilReceiver(CheckerContext &
C,
122 const ObjCMethodCall &msg)
const;
124 bool uninitRefOrPointer(CheckerContext &
C, SVal
V, SourceRange ArgRange,
125 const Expr *ArgEx,
const BugType &BT,
126 const ParmVarDecl *ParamDecl,
127 int ArgumentNumber)
const;
133 ExplodedNode *N =
C.generateErrorNode();
137 auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.
getDescription(), N);
144 C.emitReport(std::move(R));
149 llvm::raw_svector_ostream &Os) {
150 switch (
Call.getKind()) {
155 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
156 <<
" argument in message expression is an uninitialized value";
159 assert(Msg.
isSetter() &&
"Getters have no args");
160 Os <<
"Argument for property setter is an uninitialized value";
163 if (Msg.
isSetter() && (ArgumentNumber == 0))
164 Os <<
"Argument for subscript setter is an uninitialized value";
166 Os <<
"Subscript index is an uninitialized value";
169 llvm_unreachable(
"Unknown message kind.");
172 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
173 <<
" block call argument is an uninitialized value";
176 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
177 <<
" function call argument is an uninitialized value";
182bool CallAndMessageChecker::uninitRefOrPointer(
183 CheckerContext &
C, SVal
V, SourceRange ArgRange,
const Expr *ArgEx,
184 const BugType &BT,
const ParmVarDecl *ParamDecl,
int ArgumentNumber)
const {
188 if (!ChecksEnabled[CK_ArgPointeeInitializedness])
198 SmallString<200> Buf;
199 llvm::raw_svector_ostream Os(Buf);
202 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
203 <<
" function call argument is a pointer to uninitialized value";
205 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
206 <<
" function call argument is an uninitialized value";
213 if (
const MemRegion *SValMemRegion =
V.getAsRegion()) {
215 const SVal PSV = State->getSVal(SValMemRegion,
C.getASTContext().CharTy);
217 if (ExplodedNode *N =
C.generateErrorNode()) {
218 auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
219 R->addRange(ArgRange);
223 C.emitReport(std::move(R));
232class FindUninitializedField {
234 SmallVector<const FieldDecl *, 10> FieldChain;
237 StoreManager &StoreMgr;
238 MemRegionManager &MrMgr;
242 FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
244 : StoreMgr(storeMgr), MrMgr(mrMgr), store(
s) {}
246 bool Find(
const TypedValueRegion *R) {
249 const RecordDecl *RD = RT->getDecl()->getDefinition();
250 assert(RD &&
"Referred record has no definition");
251 for (
const auto *I : RD->
fields()) {
252 if (I->isUnnamedBitField())
255 FieldChain.push_back(I);
261 SVal
V = StoreMgr.
getBinding(store, loc::MemRegionVal(FR));
265 FieldChain.pop_back();
274bool CallAndMessageChecker::PreVisitProcessArg(
275 CheckerContext &
C, SVal
V, SourceRange ArgRange,
const Expr *ArgEx,
276 int ArgumentNumber,
bool CheckUninitFields,
const CallEvent &
Call,
277 const BugType &BT,
const ParmVarDecl *ParamDecl)
const {
278 if (uninitRefOrPointer(
C,
V, ArgRange, ArgEx, BT, ParamDecl, ArgumentNumber))
282 if (!ChecksEnabled[CK_ArgInitializedness]) {
286 if (ExplodedNode *N =
C.generateErrorNode()) {
288 SmallString<200> Buf;
289 llvm::raw_svector_ostream Os(Buf);
291 auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
293 R->addRange(ArgRange);
296 C.emitReport(std::move(R));
301 if (!CheckUninitFields)
304 if (
auto LV =
V.getAs<nonloc::LazyCompoundVal>()) {
305 const LazyCompoundValData *D = LV->getCVData();
306 FindUninitializedField F(
C.getState()->getStateManager().getStoreManager(),
307 C.getSValBuilder().getRegionManager(),
311 if (!ChecksEnabled[CK_ArgInitializedness]) {
315 if (ExplodedNode *N =
C.generateErrorNode()) {
316 SmallString<512> Str;
317 llvm::raw_svector_ostream os(Str);
318 os <<
"Passed-by-value struct argument contains uninitialized data";
320 if (F.FieldChain.size() == 1)
321 os <<
" (e.g., field: '" << *F.FieldChain[0] <<
"')";
323 os <<
" (e.g., via the field chain: '";
325 for (
const FieldDecl *FD : F.FieldChain) {
336 auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
337 R->addRange(ArgRange);
343 C.emitReport(std::move(R));
356 const LocationContext *LCtx =
C.getLocationContext();
357 SVal L = State->getSVal(Callee, LCtx);
360 if (!ChecksEnabled[CK_FunctionPointer]) {
364 emitBadCall(CallUndefBug,
C, Callee);
369 std::tie(StNonNull, StNull) = State->assume(L.
castAs<DefinedOrUnknownSVal>());
371 if (StNull && !StNonNull) {
372 if (!ChecksEnabled[CK_FunctionPointer]) {
376 emitBadCall(CallNullBug,
C, Callee);
388 unsigned Params =
Call.parameters().size();
389 if (
Call.getNumArgs() >= Params)
392 if (!ChecksEnabled[CK_ParameterCount]) {
397 ExplodedNode *N =
C.generateErrorNode();
401 SmallString<512> Str;
402 llvm::raw_svector_ostream os(Str);
409 os <<
"taking " << Params <<
" argument" << (Params == 1 ?
"" :
"s")
410 <<
" is called with fewer (" <<
Call.getNumArgs() <<
")";
413 std::make_unique<PathSensitiveBugReport>(CallFewArgsBug, os.str(), N));
418 const CXXInstanceCall *CC, CheckerContext &
C,
ProgramStateRef State)
const {
422 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
431 std::tie(StNonNull, StNull) = State->assume(
V.castAs<DefinedOrUnknownSVal>());
433 if (StNull && !StNonNull) {
434 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
446CallAndMessageChecker::checkCXXDeallocation(
const CXXDeallocatorCall *DC,
455 if (!ChecksEnabled[CK_CXXDeallocationArg]) {
461 ExplodedNode *N =
C.generateErrorNode();
465 Desc =
"Argument to 'delete[]' is uninitialized";
467 Desc =
"Argument to 'delete' is uninitialized";
468 auto R = std::make_unique<PathSensitiveBugReport>(CXXDeleteUndefBug, Desc, N);
470 C.emitReport(std::move(R));
483 const bool checkUninitFields =
484 !(
C.getAnalysisManager().shouldInlineCall() && (D && D->
getBody()));
488 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
489 for (
unsigned i = 0, e =
Call.getNumArgs(); i != e; ++i) {
490 const ParmVarDecl *ParamDecl =
nullptr;
491 if (FD && i < FD->getNumParams())
493 if (PreVisitProcessArg(
C,
Call.getArgSVal(i),
Call.getArgSourceRange(i),
494 Call.getArgExpr(i), i, checkUninitFields,
Call, BT,
501void CallAndMessageChecker::checkPreCall(
const CallEvent &
Call,
502 CheckerContext &
C)
const {
505 if (
const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr()))
506 State = checkFunctionPointerCall(CE,
C, State);
512 State = checkParameterCount(
Call,
C, State);
517 if (
const auto *CC = dyn_cast<CXXInstanceCall>(&
Call))
518 State = checkCXXMethodCall(CC,
C, State);
523 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call))
524 State = checkCXXDeallocation(DC,
C, State);
529 State = checkArgInitializedness(
Call,
C, State);
532 C.addTransition(State);
535void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
536 CheckerContext &
C)
const {
539 if (!ChecksEnabled[CK_UndefReceiver]) {
543 if (ExplodedNode *N =
C.generateErrorNode()) {
544 const BugType *BT =
nullptr;
550 BT = &ObjCPropUndefBug;
553 BT = &ObjCSubscriptUndefBug;
556 assert(BT &&
"Unknown message kind.");
558 auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->
getDescription(), N);
565 C.emitReport(std::move(R));
571void CallAndMessageChecker::checkObjCMessageNil(
const ObjCMethodCall &msg,
572 CheckerContext &
C)
const {
573 HandleNilReceiver(
C,
C.getState(), msg);
576void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &
C,
577 const ObjCMethodCall &msg,
578 ExplodedNode *N)
const {
579 if (!ChecksEnabled[CK_NilReceiver]) {
588 SmallString<200> buf;
589 llvm::raw_svector_ostream os(buf);
590 os <<
"The receiver of message '";
594 os <<
", which results in forming a null reference";
596 os <<
" and returns a value of type '";
598 os <<
"' that will be garbage";
602 std::make_unique<PathSensitiveBugReport>(MsgRetBug, os.str(), N);
608 C.emitReport(std::move(report));
612 return (triple.getVendor() == llvm::Triple::Apple &&
613 (triple.isiOS() || triple.isWatchOS() ||
614 !triple.isMacOSXVersionLT(10,5)));
617void CallAndMessageChecker::HandleNilReceiver(CheckerContext &
C,
619 const ObjCMethodCall &Msg)
const {
620 ASTContext &Ctx =
C.getASTContext();
626 const LocationContext *LCtx =
C.getLocationContext();
628 if (CanRetTy->isStructureOrClassType()) {
630 SVal
V =
C.getSValBuilder().makeZeroVal(RetTy);
636 if (CanRetTy != Ctx.
VoidTy &&
C.getLocationContext()->getParentMap()
643 (voidPtrSize < returnTypeSize &&
650 if (ExplodedNode *N =
C.generateErrorNode(state))
651 emitNilReceiverBug(
C, Msg, N);
668 SVal
V =
C.getSValBuilder().makeZeroVal(RetTy);
673 C.addTransition(state);
676void ento::registerCallAndMessageChecker(CheckerManager &Mgr) {
677 CallAndMessageChecker *Chk = Mgr.
registerChecker<CallAndMessageChecker>();
679#define QUERY_CHECKER_OPTION(OPTION) \
680 Chk->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] = \
681 Mgr.getAnalyzerOptions().getCheckerBooleanOption( \
682 Mgr.getCurrentCheckerName(), #OPTION);
694bool ento::shouldRegisterCallAndMessageChecker(
const CheckerManager &) {
#define QUERY_CHECKER_OPTION(OPTION)
static bool supportsNilWithFloatRet(const llvm::Triple &triple)
static void describeUninitializedArgumentInCall(const CallEvent &Call, int ArgumentNumber, llvm::raw_svector_ostream &Os)
Defines the clang::Expr interface and subclasses for C++ expressions.
__device__ __2f16 float __ockl_bool s
static CanQualType getCanonicalType(QualType T)
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CanQualType UnsignedLongLongTy
const TargetInfo & getTargetInfo() const
bool isArrayFormAsWritten() const
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
This represents one expression.
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
const ParmVarDecl * getParamDecl(unsigned i) const
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Selector getSelector() const
SourceRange getReceiverRange() const
Source range of the receiver.
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
bool isConstQualified() const
Determine whether this type is const-qualified.
field_range fields() const
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
bool isStructureType() const
bool isPointerType() const
bool isReferenceType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const RecordType * getAsStructureType() const
StringRef getDescription() const
const CXXDeleteExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
virtual SVal getCXXThisVal() const
Returns the value of the implicit 'this' object.
virtual const Expr * getCXXThisExpr() const
Returns the expression representing the implicit 'this' object.
Represents an abstract call to a function or method along a particular path.
QualType getResultType() const
Returns the result type, adjusted for references.
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
const void * getStore() const
It might return null.
LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion * getRegion() const
const FieldRegion * getFieldRegion(const FieldDecl *FD, const SubRegion *SuperRegion)
getFieldRegion - Retrieve or create the memory region associated with a specified FieldDecl.
Represents any expression that calls an Objective-C method.
ObjCMessageKind getMessageKind() const
Returns how the message was written in the source (property access, subscript, or explicit message se...
bool isSetter() const
Returns true if this property access or subscript is a setter (has the form of an assignment).
const ObjCMessageExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
SVal getReceiverSVal() const
Returns the value of the receiver at the time of this call.
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
virtual SVal getBinding(Store store, Loc loc, QualType T=QualType())=0
Return the value bound to specified location in a given state.
virtual QualType getValueType() const =0
Defines the clang::TargetInfo interface.
const Expr * getDerefExpr(const Stmt *S)
Given that expression S represents a pointer that would be dereferenced, try to find a sub-expression...
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
const FunctionProtoType * T
U cast(CodeGen::Address addr)