23#include "llvm/ADT/STLExtras.h"
24#include "llvm/ADT/StringExtras.h"
25#include "llvm/Support/FormatVariadic.h"
26#include "llvm/Support/raw_ostream.h"
33class CallAndMessageChecker
34 :
public Checker<check::PreObjCMessage, check::ObjCMessageNil,
36 const BugType CallNullBug{
37 this,
"Called function pointer is null (null dereference)"};
38 const BugType CallUndefBug{
39 this,
"Called function pointer is an uninitialized pointer value"};
40 const BugType CXXCallNullBug{
this,
"Called C++ object pointer is null"};
41 const BugType CXXCallUndefBug{
this,
42 "Called C++ object pointer is uninitialized"};
43 const BugType CallArgBug{
this,
"Uninitialized argument value"};
44 const BugType CXXDeleteUndefBug{
this,
"Uninitialized argument value"};
45 const BugType MsgUndefBug{
46 this,
"Receiver in message expression is an uninitialized value"};
47 const BugType ObjCPropUndefBug{
48 this,
"Property access on an uninitialized object pointer"};
49 const BugType ObjCSubscriptUndefBug{
50 this,
"Subscript access on an uninitialized object pointer"};
51 const BugType MsgArgBug{
this,
"Uninitialized argument value"};
52 const BugType MsgRetBug{
this,
"Receiver in message expression is 'nil'"};
53 const BugType CallFewArgsBug{
this,
"Function call with too few arguments"};
72 CK_CXXDeallocationArg,
73 CK_ArgInitializedness,
74 CK_ArgPointeeInitializedness,
80 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
84 bool StructInitializednessComplete =
true;
86 void checkPreObjCMessage(
const ObjCMethodCall &msg, CheckerContext &
C)
const;
91 void checkObjCMessageNil(
const ObjCMethodCall &msg, CheckerContext &
C)
const;
93 void checkPreCall(
const CallEvent &
Call, CheckerContext &
C)
const;
115 bool PreVisitProcessArg(CheckerContext &
C, SVal
V, SourceRange ArgRange,
116 const Expr *ArgEx,
int ArgumentNumber,
117 bool CheckUninitFields,
const CallEvent &
Call,
119 const ParmVarDecl *ParamDecl)
const;
121 static void emitBadCall(
const BugType &BT, CheckerContext &
C,
123 void emitNilReceiverBug(CheckerContext &
C,
const ObjCMethodCall &msg,
124 ExplodedNode *N)
const;
126 void HandleNilReceiver(CheckerContext &
C,
128 const ObjCMethodCall &msg)
const;
130 bool uninitRefOrPointer(CheckerContext &
C, SVal
V, SourceRange ArgRange,
131 const Expr *ArgEx,
const BugType &BT,
132 const ParmVarDecl *ParamDecl,
133 int ArgumentNumber)
const;
139 ExplodedNode *N =
C.generateErrorNode();
143 auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.
getDescription(), N);
150 C.emitReport(std::move(R));
155 llvm::raw_svector_ostream &Os) {
156 switch (
Call.getKind()) {
161 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
162 <<
" argument in message expression is an uninitialized value";
165 assert(Msg.
isSetter() &&
"Getters have no args");
166 Os <<
"Argument for property setter is an uninitialized value";
169 if (Msg.
isSetter() && (ArgumentNumber == 0))
170 Os <<
"Argument for subscript setter is an uninitialized value";
172 Os <<
"Subscript index is an uninitialized value";
175 llvm_unreachable(
"Unknown message kind.");
178 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
179 <<
" block call argument is an uninitialized value";
182 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
183 <<
" function call argument is an uninitialized value";
189class FindUninitializedField {
191 using FieldChainTy = SmallVector<const FieldDecl *, 10>;
192 FieldChainTy FieldChain;
195 StoreManager &StoreMgr;
196 MemRegionManager &MrMgr;
198 bool FindNotUninitialized;
201 FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
202 Store s,
bool FindNotUninitialized =
false)
203 : StoreMgr(storeMgr), MrMgr(mrMgr), store(
s),
204 FindNotUninitialized(FindNotUninitialized) {}
206 bool Find(
const TypedValueRegion *R) {
209 const RecordDecl *RD = RT->getDecl()->getDefinition();
210 assert(RD &&
"Referred record has no definition");
211 for (
const auto *I : RD->
fields()) {
212 if (I->isUnnamedBitField())
215 FieldChain.push_back(I);
218 if (FindNotUninitialized ? !Find(FR) : Find(FR))
219 return !FindNotUninitialized;
221 SVal
V = StoreMgr.
getBinding(store, loc::MemRegionVal(FR));
222 if (FindNotUninitialized ? !
V.isUndef() :
V.isUndef())
223 return !FindNotUninitialized;
225 FieldChain.pop_back();
229 return FindNotUninitialized;
235template <>
struct format_provider<FindUninitializedField::FieldChainTy> {
236 static void format(
const FindUninitializedField::FieldChainTy &
V,
237 raw_ostream &Stream, StringRef Style) {
240 else if (
V.size() == 1)
241 Stream <<
" (e.g., field: '" << *
V[0] <<
"')";
243 Stream <<
" (e.g., via the field chain: '";
245 V, Stream, [&Stream](
const FieldDecl *FD) { Stream << *FD; },
".");
252bool CallAndMessageChecker::uninitRefOrPointer(
253 CheckerContext &
C, SVal
V, SourceRange ArgRange,
const Expr *ArgEx,
254 const BugType &BT,
const ParmVarDecl *ParamDecl,
int ArgumentNumber)
const {
256 if (!ChecksEnabled[CK_ArgPointeeInitializedness])
263 QualType ParamT = ParamDecl->
getType();
271 const MemRegion *SValMemRegion =
V.getAsRegion();
281 PointeeT =
C.getASTContext().CharTy;
282 const SVal PointeeV = State->getSVal(SValMemRegion, PointeeT);
285 if (ExplodedNode *N =
C.generateErrorNode()) {
286 std::string Msg = llvm::formatv(
287 "{0}{1} function call argument is {2} uninitialized value",
288 ArgumentNumber + 1, llvm::getOrdinalSuffix(ArgumentNumber + 1),
290 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
291 R->addRange(ArgRange);
295 C.emitReport(std::move(R));
300 if (
auto LV = PointeeV.
getAs<nonloc::LazyCompoundVal>()) {
301 const LazyCompoundValData *D = LV->getCVData();
302 FindUninitializedField F(
C.getState()->getStateManager().getStoreManager(),
303 C.getSValBuilder().getRegionManager(),
304 D->
getStore(), StructInitializednessComplete);
307 if (ExplodedNode *N =
C.generateErrorNode()) {
308 std::string Msg = llvm::formatv(
309 "{0}{1} function call argument {2} an uninitialized value{3}",
310 (ArgumentNumber + 1), llvm::getOrdinalSuffix(ArgumentNumber + 1),
311 ParamT->
isPointerType() ?
"points to" :
"references", F.FieldChain);
312 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
313 R->addRange(ArgRange);
317 C.emitReport(std::move(R));
326bool CallAndMessageChecker::PreVisitProcessArg(
327 CheckerContext &
C, SVal
V, SourceRange ArgRange,
const Expr *ArgEx,
328 int ArgumentNumber,
bool CheckUninitFields,
const CallEvent &
Call,
329 const BugType &BT,
const ParmVarDecl *ParamDecl)
const {
330 if (uninitRefOrPointer(
C,
V, ArgRange, ArgEx, BT, ParamDecl, ArgumentNumber))
334 if (!ChecksEnabled[CK_ArgInitializedness]) {
338 if (ExplodedNode *N =
C.generateErrorNode()) {
340 SmallString<200> Buf;
341 llvm::raw_svector_ostream Os(Buf);
343 auto R = std::make_unique<PathSensitiveBugReport>(BT, Os.str(), N);
345 R->addRange(ArgRange);
348 C.emitReport(std::move(R));
353 if (!CheckUninitFields)
356 if (
auto LV =
V.getAs<nonloc::LazyCompoundVal>()) {
357 const LazyCompoundValData *D = LV->getCVData();
358 FindUninitializedField F(
C.getState()->getStateManager().getStoreManager(),
359 C.getSValBuilder().getRegionManager(),
363 if (!ChecksEnabled[CK_ArgInitializedness]) {
367 if (ExplodedNode *N =
C.generateErrorNode()) {
368 std::string Msg = llvm::formatv(
369 "Passed-by-value struct argument contains uninitialized data{0}",
373 auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
374 R->addRange(ArgRange);
380 C.emitReport(std::move(R));
393 const LocationContext *LCtx =
C.getLocationContext();
394 SVal L = State->getSVal(Callee, LCtx);
397 if (!ChecksEnabled[CK_FunctionPointer]) {
401 emitBadCall(CallUndefBug,
C, Callee);
406 std::tie(StNonNull, StNull) = State->assume(L.
castAs<DefinedOrUnknownSVal>());
408 if (StNull && !StNonNull) {
409 if (!ChecksEnabled[CK_FunctionPointer]) {
413 emitBadCall(CallNullBug,
C, Callee);
425 unsigned Params =
Call.parameters().size();
426 if (
Call.getNumArgs() >= Params)
429 if (!ChecksEnabled[CK_ParameterCount]) {
434 ExplodedNode *N =
C.generateErrorNode();
438 SmallString<512> Str;
439 llvm::raw_svector_ostream os(Str);
446 os <<
"taking " << Params <<
" argument" << (Params == 1 ?
"" :
"s")
447 <<
" is called with fewer (" <<
Call.getNumArgs() <<
")";
450 std::make_unique<PathSensitiveBugReport>(CallFewArgsBug, os.str(), N));
455 const CXXInstanceCall *CC, CheckerContext &
C,
ProgramStateRef State)
const {
459 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
468 std::tie(StNonNull, StNull) = State->assume(
V.castAs<DefinedOrUnknownSVal>());
470 if (StNull && !StNonNull) {
471 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
483CallAndMessageChecker::checkCXXDeallocation(
const CXXDeallocatorCall *DC,
492 if (!ChecksEnabled[CK_CXXDeallocationArg]) {
498 ExplodedNode *N =
C.generateErrorNode();
502 Desc =
"Argument to 'delete[]' is uninitialized";
504 Desc =
"Argument to 'delete' is uninitialized";
505 auto R = std::make_unique<PathSensitiveBugReport>(CXXDeleteUndefBug, Desc, N);
507 C.emitReport(std::move(R));
520 const bool checkUninitFields =
521 !(
C.getAnalysisManager().shouldInlineCall() && (D && D->
getBody()));
525 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
526 for (
unsigned i = 0, e =
Call.getNumArgs(); i != e; ++i) {
527 const ParmVarDecl *ParamDecl =
nullptr;
528 if (FD && i < FD->getNumParams())
530 if (PreVisitProcessArg(
C,
Call.getArgSVal(i),
Call.getArgSourceRange(i),
531 Call.getArgExpr(i), i, checkUninitFields,
Call, BT,
538void CallAndMessageChecker::checkPreCall(
const CallEvent &
Call,
539 CheckerContext &
C)
const {
542 if (
const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr()))
543 State = checkFunctionPointerCall(CE,
C, State);
549 State = checkParameterCount(
Call,
C, State);
554 if (
const auto *CC = dyn_cast<CXXInstanceCall>(&
Call))
555 State = checkCXXMethodCall(CC,
C, State);
560 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call))
561 State = checkCXXDeallocation(DC,
C, State);
566 State = checkArgInitializedness(
Call,
C, State);
569 C.addTransition(State);
572void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
573 CheckerContext &
C)
const {
576 if (!ChecksEnabled[CK_UndefReceiver]) {
580 if (ExplodedNode *N =
C.generateErrorNode()) {
581 const BugType *BT =
nullptr;
587 BT = &ObjCPropUndefBug;
590 BT = &ObjCSubscriptUndefBug;
593 assert(BT &&
"Unknown message kind.");
595 auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->
getDescription(), N);
602 C.emitReport(std::move(R));
608void CallAndMessageChecker::checkObjCMessageNil(
const ObjCMethodCall &msg,
609 CheckerContext &
C)
const {
610 HandleNilReceiver(
C,
C.getState(), msg);
613void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &
C,
614 const ObjCMethodCall &msg,
615 ExplodedNode *N)
const {
616 if (!ChecksEnabled[CK_NilReceiver]) {
625 SmallString<200> buf;
626 llvm::raw_svector_ostream os(buf);
627 os <<
"The receiver of message '";
631 os <<
", which results in forming a null reference";
633 os <<
" and returns a value of type '";
635 os <<
"' that will be garbage";
639 std::make_unique<PathSensitiveBugReport>(MsgRetBug, os.str(), N);
645 C.emitReport(std::move(report));
649 return (triple.getVendor() == llvm::Triple::Apple &&
650 (triple.isiOS() || triple.isWatchOS() ||
651 !triple.isMacOSXVersionLT(10,5)));
654void CallAndMessageChecker::HandleNilReceiver(CheckerContext &
C,
656 const ObjCMethodCall &Msg)
const {
657 ASTContext &Ctx =
C.getASTContext();
663 const LocationContext *LCtx =
C.getLocationContext();
665 if (CanRetTy->isStructureOrClassType()) {
667 SVal
V =
C.getSValBuilder().makeZeroVal(RetTy);
673 if (CanRetTy != Ctx.
VoidTy &&
C.getLocationContext()->getParentMap()
680 (voidPtrSize < returnTypeSize &&
687 if (ExplodedNode *N =
C.generateErrorNode(state))
688 emitNilReceiverBug(
C, Msg, N);
705 SVal
V =
C.getSValBuilder().makeZeroVal(RetTy);
710 C.addTransition(state);
713void ento::registerCallAndMessageChecker(CheckerManager &Mgr) {
714 CallAndMessageChecker *Chk = Mgr.
registerChecker<CallAndMessageChecker>();
716#define QUERY_CHECKER_OPTION(OPTION) \
717 Chk->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] = \
718 Mgr.getAnalyzerOptions().getCheckerBooleanOption( \
719 Mgr.getCurrentCheckerName(), #OPTION);
730 Chk->StructInitializednessComplete =
735bool 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.
Represents a member of a struct/union/class.
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
bool isPointerOrReferenceType() 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.
const AnalyzerOptions & getAnalyzerOptions() const
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
CheckerNameRef getCurrentCheckerName() const
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.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
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)