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));
130 std::unique_ptr<BugType> &BT,
132 int ArgumentNumber)
const;
142 auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->
getDescription(), N);
149 C.emitReport(std::move(R));
154 llvm::raw_svector_ostream &Os) {
155 switch (
Call.getKind()) {
160 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
161 <<
" argument in message expression is an uninitialized value";
164 assert(Msg.
isSetter() &&
"Getters have no args");
165 Os <<
"Argument for property setter is an uninitialized value";
168 if (Msg.
isSetter() && (ArgumentNumber == 0))
169 Os <<
"Argument for subscript setter is an uninitialized value";
171 Os <<
"Subscript index is an uninitialized value";
174 llvm_unreachable(
"Unknown message kind.");
177 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
178 <<
" block call argument is an uninitialized value";
181 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
182 <<
" function call argument is an uninitialized value";
187bool CallAndMessageChecker::uninitRefOrPointer(
189 std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl,
const char *BD,
190 int ArgumentNumber)
const {
194 if (!ChecksEnabled[CK_ArgPointeeInitializedness])
205 llvm::raw_svector_ostream Os(Buf);
208 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
209 <<
" function call argument is a pointer to uninitialized value";
211 Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
212 <<
" function call argument is an uninitialized value";
219 if (
const MemRegion *SValMemRegion =
V.getAsRegion()) {
221 const SVal PSV = State->getSVal(SValMemRegion,
C.getASTContext().CharTy);
225 auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
226 R->addRange(ArgRange);
230 C.emitReport(std::move(R));
239class FindUninitializedField {
251 : StoreMgr(storeMgr), MrMgr(mrMgr), store(
s) {}
257 assert(RD &&
"Referred record has no definition");
258 for (
const auto *I : RD->
fields()) {
260 FieldChain.push_back(I);
270 FieldChain.pop_back();
284 bool CheckUninitFields,
286 std::unique_ptr<BugType> &BT,
289 const char *BD =
"Uninitialized argument value";
291 if (uninitRefOrPointer(
C,
V, ArgRange, ArgEx, BT, ParamDecl, BD,
296 if (!ChecksEnabled[CK_ArgInitializedness]) {
304 llvm::raw_svector_ostream Os(Buf);
306 auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
308 R->addRange(ArgRange);
311 C.emitReport(std::move(R));
316 if (!CheckUninitFields)
321 FindUninitializedField F(
C.getState()->getStateManager().getStoreManager(),
322 C.getSValBuilder().getRegionManager(),
326 if (!ChecksEnabled[CK_ArgInitializedness]) {
333 llvm::raw_svector_ostream os(Str);
334 os <<
"Passed-by-value struct argument contains uninitialized data";
336 if (F.FieldChain.size() == 1)
337 os <<
" (e.g., field: '" << *F.FieldChain[0] <<
"')";
339 os <<
" (e.g., via the field chain: '";
342 DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
353 auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
354 R->addRange(ArgRange);
360 C.emitReport(std::move(R));
374 SVal L = State->getSVal(Callee, LCtx);
377 if (!ChecksEnabled[CK_FunctionPointer]) {
382 BT_call_undef.reset(
new BugType(
384 "Called function pointer is an uninitialized pointer value"));
385 emitBadCall(BT_call_undef.get(),
C, Callee);
392 if (StNull && !StNonNull) {
393 if (!ChecksEnabled[CK_FunctionPointer]) {
398 BT_call_null.reset(
new BugType(
399 OriginalName,
"Called function pointer is null (null dereference)"));
400 emitBadCall(BT_call_null.get(),
C, Callee);
412 unsigned Params =
Call.parameters().size();
413 if (
Call.getNumArgs() >= Params)
416 if (!ChecksEnabled[CK_ParameterCount]) {
425 LazyInit_BT(
"Function call with too few arguments", BT_call_few_args);
428 llvm::raw_svector_ostream os(Str);
429 if (isa<AnyFunctionCall>(
Call)) {
432 assert(isa<BlockCall>(
Call));
435 os <<
"taking " << Params <<
" argument" << (Params == 1 ?
"" :
"s")
436 <<
" is called with fewer (" <<
Call.getNumArgs() <<
")";
439 std::make_unique<PathSensitiveBugReport>(*BT_call_few_args, os.str(), N));
448 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
452 if (!BT_cxx_call_undef)
453 BT_cxx_call_undef.reset(
new BugType(
454 OriginalName,
"Called C++ object pointer is uninitialized"));
462 if (StNull && !StNonNull) {
463 if (!ChecksEnabled[CK_CXXThisMethodCall]) {
467 if (!BT_cxx_call_null)
468 BT_cxx_call_null.reset(
469 new BugType(OriginalName,
"Called C++ object pointer is null"));
487 if (!ChecksEnabled[CK_CXXDeallocationArg]) {
496 if (!BT_cxx_delete_undef)
497 BT_cxx_delete_undef.reset(
498 new BugType(OriginalName,
"Uninitialized argument value"));
500 Desc =
"Argument to 'delete[]' is uninitialized";
502 Desc =
"Argument to 'delete' is uninitialized";
504 std::make_unique<PathSensitiveBugReport>(*BT_cxx_delete_undef, Desc, N);
506 C.emitReport(std::move(R));
519 const bool checkUninitFields =
520 !(
C.getAnalysisManager().shouldInlineCall() && (D && D->
getBody()));
522 std::unique_ptr<BugType> *BT;
523 if (isa<ObjCMethodCall>(
Call))
528 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
529 for (
unsigned i = 0, e =
Call.getNumArgs(); i != e; ++i) {
531 if (FD && i < FD->getNumParams())
533 if (PreVisitProcessArg(
C,
Call.getArgSVal(i),
Call.getArgSourceRange(i),
534 Call.getArgExpr(i), i, checkUninitFields,
Call, *BT,
541void CallAndMessageChecker::checkPreCall(
const CallEvent &
Call,
545 if (
const CallExpr *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr()))
546 State = checkFunctionPointerCall(CE,
C, State);
552 State = checkParameterCount(
Call,
C, State);
557 if (
const auto *CC = dyn_cast<CXXInstanceCall>(&
Call))
558 State = checkCXXMethodCall(CC,
C, State);
563 if (
const auto *DC = dyn_cast<CXXDeallocatorCall>(&
Call))
564 State = checkCXXDeallocation(DC,
C, State);
569 State = checkArgInitializedness(
Call,
C, State);
572 C.addTransition(State);
575void CallAndMessageChecker::checkPreObjCMessage(
const ObjCMethodCall &msg,
579 if (!ChecksEnabled[CK_UndefReceiver]) {
588 BT_msg_undef.reset(
new BugType(OriginalName,
589 "Receiver in message expression "
590 "is an uninitialized value"));
591 BT = BT_msg_undef.get();
594 if (!BT_objc_prop_undef)
595 BT_objc_prop_undef.reset(
new BugType(
597 "Property access on an uninitialized object pointer"));
598 BT = BT_objc_prop_undef.get();
601 if (!BT_objc_subscript_undef)
602 BT_objc_subscript_undef.reset(
new BugType(
604 "Subscript access on an uninitialized object pointer"));
605 BT = BT_objc_subscript_undef.get();
608 assert(BT &&
"Unknown message kind.");
610 auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->
getDescription(), N);
617 C.emitReport(std::move(R));
623void CallAndMessageChecker::checkObjCMessageNil(
const ObjCMethodCall &msg,
625 HandleNilReceiver(
C,
C.getState(), msg);
631 if (!ChecksEnabled[CK_NilReceiver]) {
638 new BugType(OriginalName,
"Receiver in message expression is 'nil'"));
645 llvm::raw_svector_ostream os(buf);
646 os <<
"The receiver of message '";
650 os <<
", which results in forming a null reference";
652 os <<
" and returns a value of type '";
654 os <<
"' that will be garbage";
658 std::make_unique<PathSensitiveBugReport>(*BT_msg_ret, os.str(), N);
664 C.emitReport(std::move(report));
668 return (triple.getVendor() == llvm::Triple::Apple &&
669 (triple.isiOS() || triple.isWatchOS() ||
670 !triple.isMacOSXVersionLT(10,5)));
685 if (CanRetTy->isStructureOrClassType()) {
687 SVal V =
C.getSValBuilder().makeZeroVal(RetTy);
693 if (CanRetTy != Ctx.
VoidTy &&
C.getLocationContext()->getParentMap()
700 (voidPtrSize < returnTypeSize &&
708 emitNilReceiverBug(
C, Msg, N);
725 SVal V =
C.getSValBuilder().makeZeroVal(RetTy);
730 C.addTransition(state);
737bool ento::shouldRegisterCallAndMessageModeling(
const CheckerManager &mgr) {
742 CallAndMessageChecker *checker = mgr.
getChecker<CallAndMessageChecker>();
746#define QUERY_CHECKER_OPTION(OPTION) \
747 checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] = \
748 mgr.getAnalyzerOptions().getCheckerBooleanOption( \
749 mgr.getCurrentCheckerName(), #OPTION);
761bool 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 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.
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
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.