23#include "llvm/ADT/SmallString.h"
24#include "llvm/ADT/StringExtras.h"
25#include "llvm/Support/Casting.h"
26#include "llvm/Support/raw_ostream.h"
33class CallAndMessageChecker
34 :
public Checker<check::PreObjCMessage, check::ObjCMessageNil,
36 mutable std::unique_ptr<BugType> BT_call_null;
37 mutable std::unique_ptr<BugType> BT_call_undef;
38 mutable std::unique_ptr<BugType> BT_cxx_call_null;
39 mutable std::unique_ptr<BugType> BT_cxx_call_undef;
40 mutable std::unique_ptr<BugType> BT_call_arg;
41 mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
42 mutable std::unique_ptr<BugType> BT_msg_undef;
43 mutable std::unique_ptr<BugType> BT_objc_prop_undef;
44 mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
45 mutable std::unique_ptr<BugType> BT_msg_arg;
46 mutable std::unique_ptr<BugType> BT_msg_ret;
47 mutable std::unique_ptr<BugType> BT_call_few_args;
68 CK_CXXDeallocationArg,
69 CK_ArgInitializedness,
70 CK_ArgPointeeInitializedness,
76 bool ChecksEnabled[CK_NumCheckKinds] = {
false};
111 const Expr *ArgEx,
int ArgumentNumber,
113 std::unique_ptr<BugType> &BT,
124 void LazyInit_BT(
const char *desc, std::unique_ptr<BugType> &BT)
const {
126 BT.reset(
new BugType(OriginalName, desc));
129 const Expr *ArgEx, std::unique_ptr<BugType> &BT,
131 int ArgumentNumber)
const;
141 auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->
getDescription(), N);
148 C.emitReport(std::move(R));
153 llvm::raw_svector_ostream &Os) {
154 switch (
Call.getKind()) {
159 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
160 <<
" argument in message expression is an uninitialized value";
163 assert(Msg.
isSetter() &&
"Getters have no args");
164 Os <<
"Argument for property setter is an uninitialized value";
167 if (Msg.
isSetter() && (ArgumentNumber == 0))
168 Os <<
"Argument for subscript setter is an uninitialized value";
170 Os <<
"Subscript index is an uninitialized value";
173 llvm_unreachable(
"Unknown message kind.");
176 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
177 <<
" block call argument is an uninitialized value";
180 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
181 <<
" function call argument is an uninitialized value";
186bool CallAndMessageChecker::uninitRefOrPointer(
188 std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl,
const char *BD,
189 int ArgumentNumber)
const {
193 if (!ChecksEnabled[CK_ArgPointeeInitializedness])
204 llvm::raw_svector_ostream Os(Buf);
207 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
208 <<
" function call argument is a pointer to uninitialized value";
210 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
211 <<
" function call argument is an uninitialized value";
218 if (
const MemRegion *SValMemRegion =
V.getAsRegion()) {
220 const SVal PSV = State->getSVal(SValMemRegion,
C.getASTContext().CharTy);
224 auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
225 R->addRange(ArgRange);
229 C.emitReport(std::move(R));
238class FindUninitializedField {
250 : StoreMgr(storeMgr), MrMgr(mrMgr), store(
s) {}
256 assert(RD &&
"Referred record has no definition");
257 for (
const auto *I : RD->
fields()) {
259 FieldChain.push_back(I);
269 FieldChain.pop_back();
283 bool CheckUninitFields,
285 std::unique_ptr<BugType> &BT,
288 const char *BD =
"Uninitialized argument value";
290 if (uninitRefOrPointer(
C,
V, ArgRange, ArgEx, BT, ParamDecl, BD,
295 if (!ChecksEnabled[CK_ArgInitializedness]) {
303 llvm::raw_svector_ostream Os(Buf);
305 auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
307 R->addRange(ArgRange);
310 C.emitReport(std::move(R));
315 if (!CheckUninitFields)
320 FindUninitializedField F(
C.getState()->getStateManager().getStoreManager(),
321 C.getSValBuilder().getRegionManager(),
324 if (F.Find(
D->getRegion())) {
325 if (!ChecksEnabled[CK_ArgInitializedness]) {
332 llvm::raw_svector_ostream os(Str);
333 os <<
"Passed-by-value struct argument contains uninitialized data";
335 if (F.FieldChain.size() == 1)
336 os <<
" (e.g., field: '" << *F.FieldChain[0] <<
"')";
338 os <<
" (e.g., via the field chain: '";
341 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
352 auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
353 R->addRange(ArgRange);
359 C.emitReport(std::move(R));
373 SVal L = State->getSVal(Callee, LCtx);
376 if (!ChecksEnabled[CK_FunctionPointer]) {
381 BT_call_undef.reset(
new BugType(
383 "Called function pointer is an uninitialized pointer value"));
384 emitBadCall(BT_call_undef.get(),
C, Callee);
391 if (StNull && !StNonNull) {
392 if (!ChecksEnabled[CK_FunctionPointer]) {
397 BT_call_null.reset(
new BugType(
398 OriginalName,
"Called function pointer is null (null dereference)"));
399 emitBadCall(BT_call_null.get(),
C, Callee);
411 unsigned Params =
Call.parameters().size();
412 if (
Call.getNumArgs() >= Params)
415 if (!ChecksEnabled[CK_ParameterCount]) {
424 LazyInit_BT(
"Function call with too few arguments", BT_call_few_args);
427 llvm::raw_svector_ostream os(Str);
428 if (isa<AnyFunctionCall>(
Call)) {
431 assert(isa<BlockCall>(
Call));
434 os <<
"taking " << Params <<
" argument" << (Params == 1 ?
"" :
"s")
435 <<
" is called with fewer (" <<
Call.getNumArgs() <<
")";
438 std::make_unique<PathSensitiveBugReport>(*BT_call_few_args, os.str(), N));
447 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
451 if (!BT_cxx_call_undef)
452 BT_cxx_call_undef.reset(
new BugType(
453 OriginalName,
"Called C++ object pointer is uninitialized"));
461 if (StNull && !StNonNull) {
462 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
466 if (!BT_cxx_call_null)
467 BT_cxx_call_null.reset(
468 new BugType(OriginalName,
"Called C++ object pointer is null"));
486 if (!ChecksEnabled[CK_CXXDeallocationArg]) {
495 if (!BT_cxx_delete_undef)
496 BT_cxx_delete_undef.reset(
497 new BugType(OriginalName,
"Uninitialized argument value"));
499 Desc =
"Argument to 'delete[]' is uninitialized";
501 Desc =
"Argument to 'delete' is uninitialized";
503 std::make_unique<PathSensitiveBugReport>(*BT_cxx_delete_undef, Desc, N);
505 C.emitReport(std::move(R));
518 const bool checkUninitFields =
519 !(
C.getAnalysisManager().shouldInlineCall() && (
D &&
D->
getBody()));
521 std::unique_ptr<BugType> *BT;
522 if (isa<ObjCMethodCall>(
Call))
528 for (
unsigned i = 0, e =
Call.getNumArgs(); i != e; ++i) {
530 if (FD && i < FD->getNumParams())
532 if (PreVisitProcessArg(
C,
Call.getArgSVal(i),
Call.getArgSourceRange(i),
533 Call.getArgExpr(i), i, checkUninitFields,
Call, *BT,
540void CallAndMessageChecker::checkPreCall(
const CallEvent &
Call,
544 if (
const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr()))
545 State = checkFunctionPointerCall(CE,
C, State);
551 State = checkParameterCount(
Call,
C, State);
556 if (
const auto *CC = dyn_cast<CXXInstanceCall>(&
Call))
557 State = checkCXXMethodCall(CC,
C, State);
562 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call))
563 State = checkCXXDeallocation(DC,
C, State);
568 State = checkArgInitializedness(
Call,
C, State);
571 C.addTransition(State);
574void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
578 if (!ChecksEnabled[CK_UndefReceiver]) {
587 BT_msg_undef.reset(
new BugType(OriginalName,
588 "Receiver in message expression "
589 "is an uninitialized value"));
590 BT = BT_msg_undef.get();
593 if (!BT_objc_prop_undef)
594 BT_objc_prop_undef.reset(
new BugType(
596 "Property access on an uninitialized object pointer"));
597 BT = BT_objc_prop_undef.get();
600 if (!BT_objc_subscript_undef)
601 BT_objc_subscript_undef.reset(
new BugType(
603 "Subscript access on an uninitialized object pointer"));
604 BT = BT_objc_subscript_undef.get();
607 assert(BT &&
"Unknown message kind.");
609 auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->
getDescription(), N);
616 C.emitReport(std::move(R));
622void CallAndMessageChecker::checkObjCMessageNil(
const ObjCMethodCall &msg,
624 HandleNilReceiver(
C,
C.getState(), msg);
630 if (!ChecksEnabled[CK_NilReceiver]) {
637 new BugType(OriginalName,
"Receiver in message expression is 'nil'"));
644 llvm::raw_svector_ostream os(buf);
645 os <<
"The receiver of message '";
649 os <<
", which results in forming a null reference";
651 os <<
" and returns a value of type '";
653 os <<
"' that will be garbage";
657 std::make_unique<PathSensitiveBugReport>(*BT_msg_ret, os.str(), N);
663 C.emitReport(std::move(report));
667 return (triple.getVendor() == llvm::Triple::Apple &&
668 (triple.isiOS() || triple.isWatchOS() ||
669 !triple.isMacOSXVersionLT(10,5)));
684 if (CanRetTy->isStructureOrClassType()) {
686 SVal V =
C.getSValBuilder().makeZeroVal(RetTy);
692 if (CanRetTy != Ctx.
VoidTy &&
C.getLocationContext()->getParentMap()
699 (voidPtrSize < returnTypeSize &&
707 emitNilReceiverBug(
C, Msg, N);
724 SVal V =
C.getSValBuilder().makeZeroVal(RetTy);
729 C.addTransition(state);
736bool ento::shouldRegisterCallAndMessageModeling(
const CheckerManager &mgr) {
741 CallAndMessageChecker *checker = mgr.
getChecker<CallAndMessageChecker>();
745#define QUERY_CHECKER_OPTION(OPTION) \
746 checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] = \
747 mgr.getAnalyzerOptions().getCheckerBooleanOption( \
748 mgr.getCurrentCheckerName(), #OPTION);
760bool ento::shouldRegisterCallAndMessageChecker(
const CheckerManager &mgr) {
#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
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
CanQualType getCanonicalType(QualType T) const
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
Represents a delete expression for memory deallocation and destructor calls, e.g.
bool isArrayFormAsWritten() const
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
const T * getTypePtr() const
Retrieve the underlying type pointer, which refers to a canonical type.
Decl - This represents one declaration (or definition), e.g.
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 function declaration or definition.
const ParmVarDecl * getParamDecl(unsigned i) const
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
An expression that sends a message to the given Objective-C object or class.
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.
Represents a parameter to a function.
A (possibly-)qualified type.
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.
Represents a struct/union/class.
field_range fields() const
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
void print(llvm::raw_ostream &OS) const
Prints the full selector name (e.g. "foo:bar:").
A trivial tuple used to represent a source range.
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 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
Represents the memory deallocation call in a C++ delete-expression.
const CXXDeleteExpr * getOriginExpr() const override
Returns the expression whose value will be the result of this call.
Represents a non-static C++ member function call, no matter how it is written.
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)
Used to register checkers.
CheckerNameRef getCurrentCheckerName() const
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
Tag that can use a checker name as a message provider (see SimpleProgramPointTag).
const FieldRegion * getFieldRegion(const FieldDecl *fd, const SubRegion *superRegion)
getFieldRegion - Retrieve or create the memory region associated with a specified FieldDecl.
MemRegion - The root abstract class for all memory regions.
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.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
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.
TypedValueRegion - An abstract class representing regions having a typed value.
virtual QualType getValueType() const =0
While nonloc::CompoundVal covers a few simple use cases, nonloc::LazyCompoundVal is a more performant...
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.
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T