1e5dd7070Spatrick //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This defines CallAndMessageChecker, a builtin checker that checks for various
10e5dd7070Spatrick // errors of call and objc message expressions.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick
14ec727ea7Spatrick #include "clang/AST/ExprCXX.h"
15e5dd7070Spatrick #include "clang/AST/ParentMap.h"
16e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
17ec727ea7Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
18e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
20e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/CheckerManager.h"
21e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
22e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
23e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
24e5dd7070Spatrick #include "llvm/ADT/StringExtras.h"
25ec727ea7Spatrick #include "llvm/Support/Casting.h"
26e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
27e5dd7070Spatrick
28e5dd7070Spatrick using namespace clang;
29e5dd7070Spatrick using namespace ento;
30e5dd7070Spatrick
31e5dd7070Spatrick namespace {
32e5dd7070Spatrick
33e5dd7070Spatrick class CallAndMessageChecker
34ec727ea7Spatrick : public Checker<check::PreObjCMessage, check::ObjCMessageNil,
35e5dd7070Spatrick check::PreCall> {
36e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_call_null;
37e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_call_undef;
38e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_cxx_call_null;
39e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_cxx_call_undef;
40e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_call_arg;
41e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_cxx_delete_undef;
42e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_msg_undef;
43e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_objc_prop_undef;
44e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_objc_subscript_undef;
45e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_msg_arg;
46e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_msg_ret;
47e5dd7070Spatrick mutable std::unique_ptr<BugType> BT_call_few_args;
48e5dd7070Spatrick
49e5dd7070Spatrick public:
50ec727ea7Spatrick // These correspond with the checker options. Looking at other checkers such
51ec727ea7Spatrick // as MallocChecker and CStringChecker, this is similar as to how they pull
52ec727ea7Spatrick // off having a modeling class, but emitting diagnostics under a smaller
53ec727ea7Spatrick // checker's name that can be safely disabled without disturbing the
54ec727ea7Spatrick // underlaying modeling engine.
55ec727ea7Spatrick // The reason behind having *checker options* rather then actual *checkers*
56ec727ea7Spatrick // here is that CallAndMessage is among the oldest checkers out there, and can
57ec727ea7Spatrick // be responsible for the majority of the reports on any given project. This
58ec727ea7Spatrick // is obviously not ideal, but changing checker name has the consequence of
59ec727ea7Spatrick // changing the issue hashes associated with the reports, and databases
60ec727ea7Spatrick // relying on this (CodeChecker, for instance) would suffer greatly.
61ec727ea7Spatrick // If we ever end up making changes to the issue hash generation algorithm, or
62ec727ea7Spatrick // the warning messages here, we should totally jump on the opportunity to
63ec727ea7Spatrick // convert these to actual checkers.
64ec727ea7Spatrick enum CheckKind {
65ec727ea7Spatrick CK_FunctionPointer,
66ec727ea7Spatrick CK_ParameterCount,
67ec727ea7Spatrick CK_CXXThisMethodCall,
68ec727ea7Spatrick CK_CXXDeallocationArg,
69ec727ea7Spatrick CK_ArgInitializedness,
70ec727ea7Spatrick CK_ArgPointeeInitializedness,
71ec727ea7Spatrick CK_NilReceiver,
72ec727ea7Spatrick CK_UndefReceiver,
73ec727ea7Spatrick CK_NumCheckKinds
74ec727ea7Spatrick };
75e5dd7070Spatrick
76*12c85518Srobert bool ChecksEnabled[CK_NumCheckKinds] = {false};
77ec727ea7Spatrick // The original core.CallAndMessage checker name. This should rather be an
78ec727ea7Spatrick // array, as seen in MallocChecker and CStringChecker.
79ec727ea7Spatrick CheckerNameRef OriginalName;
80ec727ea7Spatrick
81e5dd7070Spatrick void checkPreObjCMessage(const ObjCMethodCall &msg, CheckerContext &C) const;
82e5dd7070Spatrick
83e5dd7070Spatrick /// Fill in the return value that results from messaging nil based on the
84e5dd7070Spatrick /// return type and architecture and diagnose if the return value will be
85e5dd7070Spatrick /// garbage.
86e5dd7070Spatrick void checkObjCMessageNil(const ObjCMethodCall &msg, CheckerContext &C) const;
87e5dd7070Spatrick
88e5dd7070Spatrick void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
89e5dd7070Spatrick
90ec727ea7Spatrick ProgramStateRef checkFunctionPointerCall(const CallExpr *CE,
91ec727ea7Spatrick CheckerContext &C,
92ec727ea7Spatrick ProgramStateRef State) const;
93ec727ea7Spatrick
94ec727ea7Spatrick ProgramStateRef checkCXXMethodCall(const CXXInstanceCall *CC,
95ec727ea7Spatrick CheckerContext &C,
96ec727ea7Spatrick ProgramStateRef State) const;
97ec727ea7Spatrick
98ec727ea7Spatrick ProgramStateRef checkParameterCount(const CallEvent &Call, CheckerContext &C,
99ec727ea7Spatrick ProgramStateRef State) const;
100ec727ea7Spatrick
101ec727ea7Spatrick ProgramStateRef checkCXXDeallocation(const CXXDeallocatorCall *DC,
102ec727ea7Spatrick CheckerContext &C,
103ec727ea7Spatrick ProgramStateRef State) const;
104ec727ea7Spatrick
105ec727ea7Spatrick ProgramStateRef checkArgInitializedness(const CallEvent &Call,
106ec727ea7Spatrick CheckerContext &C,
107ec727ea7Spatrick ProgramStateRef State) const;
108ec727ea7Spatrick
109e5dd7070Spatrick private:
110e5dd7070Spatrick bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange ArgRange,
111e5dd7070Spatrick const Expr *ArgEx, int ArgumentNumber,
112e5dd7070Spatrick bool CheckUninitFields, const CallEvent &Call,
113e5dd7070Spatrick std::unique_ptr<BugType> &BT,
114e5dd7070Spatrick const ParmVarDecl *ParamDecl) const;
115e5dd7070Spatrick
116e5dd7070Spatrick static void emitBadCall(BugType *BT, CheckerContext &C, const Expr *BadE);
117e5dd7070Spatrick void emitNilReceiverBug(CheckerContext &C, const ObjCMethodCall &msg,
118e5dd7070Spatrick ExplodedNode *N) const;
119e5dd7070Spatrick
120e5dd7070Spatrick void HandleNilReceiver(CheckerContext &C,
121e5dd7070Spatrick ProgramStateRef state,
122e5dd7070Spatrick const ObjCMethodCall &msg) const;
123e5dd7070Spatrick
LazyInit_BT(const char * desc,std::unique_ptr<BugType> & BT) const124e5dd7070Spatrick void LazyInit_BT(const char *desc, std::unique_ptr<BugType> &BT) const {
125e5dd7070Spatrick if (!BT)
126ec727ea7Spatrick BT.reset(new BuiltinBug(OriginalName, desc));
127e5dd7070Spatrick }
128e5dd7070Spatrick bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
129e5dd7070Spatrick SourceRange ArgRange, const Expr *ArgEx,
130e5dd7070Spatrick std::unique_ptr<BugType> &BT,
131e5dd7070Spatrick const ParmVarDecl *ParamDecl, const char *BD,
132e5dd7070Spatrick int ArgumentNumber) const;
133e5dd7070Spatrick };
134e5dd7070Spatrick } // end anonymous namespace
135e5dd7070Spatrick
emitBadCall(BugType * BT,CheckerContext & C,const Expr * BadE)136e5dd7070Spatrick void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C,
137e5dd7070Spatrick const Expr *BadE) {
138e5dd7070Spatrick ExplodedNode *N = C.generateErrorNode();
139e5dd7070Spatrick if (!N)
140e5dd7070Spatrick return;
141e5dd7070Spatrick
142e5dd7070Spatrick auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
143e5dd7070Spatrick if (BadE) {
144e5dd7070Spatrick R->addRange(BadE->getSourceRange());
145e5dd7070Spatrick if (BadE->isGLValue())
146e5dd7070Spatrick BadE = bugreporter::getDerefExpr(BadE);
147e5dd7070Spatrick bugreporter::trackExpressionValue(N, BadE, *R);
148e5dd7070Spatrick }
149e5dd7070Spatrick C.emitReport(std::move(R));
150e5dd7070Spatrick }
151e5dd7070Spatrick
describeUninitializedArgumentInCall(const CallEvent & Call,int ArgumentNumber,llvm::raw_svector_ostream & Os)152e5dd7070Spatrick static void describeUninitializedArgumentInCall(const CallEvent &Call,
153e5dd7070Spatrick int ArgumentNumber,
154e5dd7070Spatrick llvm::raw_svector_ostream &Os) {
155e5dd7070Spatrick switch (Call.getKind()) {
156e5dd7070Spatrick case CE_ObjCMessage: {
157e5dd7070Spatrick const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call);
158e5dd7070Spatrick switch (Msg.getMessageKind()) {
159e5dd7070Spatrick case OCM_Message:
160e5dd7070Spatrick Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
161e5dd7070Spatrick << " argument in message expression is an uninitialized value";
162e5dd7070Spatrick return;
163e5dd7070Spatrick case OCM_PropertyAccess:
164e5dd7070Spatrick assert(Msg.isSetter() && "Getters have no args");
165e5dd7070Spatrick Os << "Argument for property setter is an uninitialized value";
166e5dd7070Spatrick return;
167e5dd7070Spatrick case OCM_Subscript:
168e5dd7070Spatrick if (Msg.isSetter() && (ArgumentNumber == 0))
169e5dd7070Spatrick Os << "Argument for subscript setter is an uninitialized value";
170e5dd7070Spatrick else
171e5dd7070Spatrick Os << "Subscript index is an uninitialized value";
172e5dd7070Spatrick return;
173e5dd7070Spatrick }
174e5dd7070Spatrick llvm_unreachable("Unknown message kind.");
175e5dd7070Spatrick }
176e5dd7070Spatrick case CE_Block:
177e5dd7070Spatrick Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
178e5dd7070Spatrick << " block call argument is an uninitialized value";
179e5dd7070Spatrick return;
180e5dd7070Spatrick default:
181e5dd7070Spatrick Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
182e5dd7070Spatrick << " function call argument is an uninitialized value";
183e5dd7070Spatrick return;
184e5dd7070Spatrick }
185e5dd7070Spatrick }
186e5dd7070Spatrick
uninitRefOrPointer(CheckerContext & C,const SVal & V,SourceRange ArgRange,const Expr * ArgEx,std::unique_ptr<BugType> & BT,const ParmVarDecl * ParamDecl,const char * BD,int ArgumentNumber) const187e5dd7070Spatrick bool CallAndMessageChecker::uninitRefOrPointer(
188e5dd7070Spatrick CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
189e5dd7070Spatrick std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
190e5dd7070Spatrick int ArgumentNumber) const {
191ec727ea7Spatrick
192ec727ea7Spatrick // The pointee being uninitialized is a sign of code smell, not a bug, no need
193ec727ea7Spatrick // to sink here.
194ec727ea7Spatrick if (!ChecksEnabled[CK_ArgPointeeInitializedness])
195e5dd7070Spatrick return false;
196e5dd7070Spatrick
197e5dd7070Spatrick // No parameter declaration available, i.e. variadic function argument.
198e5dd7070Spatrick if(!ParamDecl)
199e5dd7070Spatrick return false;
200e5dd7070Spatrick
201e5dd7070Spatrick // If parameter is declared as pointer to const in function declaration,
202e5dd7070Spatrick // then check if corresponding argument in function call is
203e5dd7070Spatrick // pointing to undefined symbol value (uninitialized memory).
204e5dd7070Spatrick SmallString<200> Buf;
205e5dd7070Spatrick llvm::raw_svector_ostream Os(Buf);
206e5dd7070Spatrick
207e5dd7070Spatrick if (ParamDecl->getType()->isPointerType()) {
208e5dd7070Spatrick Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
209e5dd7070Spatrick << " function call argument is a pointer to uninitialized value";
210e5dd7070Spatrick } else if (ParamDecl->getType()->isReferenceType()) {
211e5dd7070Spatrick Os << (ArgumentNumber + 1) << llvm::getOrdinalSuffix(ArgumentNumber + 1)
212e5dd7070Spatrick << " function call argument is an uninitialized value";
213e5dd7070Spatrick } else
214e5dd7070Spatrick return false;
215e5dd7070Spatrick
216e5dd7070Spatrick if(!ParamDecl->getType()->getPointeeType().isConstQualified())
217e5dd7070Spatrick return false;
218e5dd7070Spatrick
219e5dd7070Spatrick if (const MemRegion *SValMemRegion = V.getAsRegion()) {
220e5dd7070Spatrick const ProgramStateRef State = C.getState();
221e5dd7070Spatrick const SVal PSV = State->getSVal(SValMemRegion, C.getASTContext().CharTy);
222e5dd7070Spatrick if (PSV.isUndef()) {
223e5dd7070Spatrick if (ExplodedNode *N = C.generateErrorNode()) {
224e5dd7070Spatrick LazyInit_BT(BD, BT);
225e5dd7070Spatrick auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
226e5dd7070Spatrick R->addRange(ArgRange);
227e5dd7070Spatrick if (ArgEx)
228e5dd7070Spatrick bugreporter::trackExpressionValue(N, ArgEx, *R);
229e5dd7070Spatrick
230e5dd7070Spatrick C.emitReport(std::move(R));
231e5dd7070Spatrick }
232e5dd7070Spatrick return true;
233e5dd7070Spatrick }
234e5dd7070Spatrick }
235e5dd7070Spatrick return false;
236e5dd7070Spatrick }
237e5dd7070Spatrick
238e5dd7070Spatrick namespace {
239e5dd7070Spatrick class FindUninitializedField {
240e5dd7070Spatrick public:
241e5dd7070Spatrick SmallVector<const FieldDecl *, 10> FieldChain;
242e5dd7070Spatrick
243e5dd7070Spatrick private:
244e5dd7070Spatrick StoreManager &StoreMgr;
245e5dd7070Spatrick MemRegionManager &MrMgr;
246e5dd7070Spatrick Store store;
247e5dd7070Spatrick
248e5dd7070Spatrick public:
FindUninitializedField(StoreManager & storeMgr,MemRegionManager & mrMgr,Store s)249e5dd7070Spatrick FindUninitializedField(StoreManager &storeMgr, MemRegionManager &mrMgr,
250e5dd7070Spatrick Store s)
251e5dd7070Spatrick : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
252e5dd7070Spatrick
Find(const TypedValueRegion * R)253e5dd7070Spatrick bool Find(const TypedValueRegion *R) {
254e5dd7070Spatrick QualType T = R->getValueType();
255e5dd7070Spatrick if (const RecordType *RT = T->getAsStructureType()) {
256e5dd7070Spatrick const RecordDecl *RD = RT->getDecl()->getDefinition();
257e5dd7070Spatrick assert(RD && "Referred record has no definition");
258e5dd7070Spatrick for (const auto *I : RD->fields()) {
259e5dd7070Spatrick const FieldRegion *FR = MrMgr.getFieldRegion(I, R);
260e5dd7070Spatrick FieldChain.push_back(I);
261e5dd7070Spatrick T = I->getType();
262e5dd7070Spatrick if (T->getAsStructureType()) {
263e5dd7070Spatrick if (Find(FR))
264e5dd7070Spatrick return true;
265e5dd7070Spatrick } else {
266e5dd7070Spatrick const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
267e5dd7070Spatrick if (V.isUndef())
268e5dd7070Spatrick return true;
269e5dd7070Spatrick }
270e5dd7070Spatrick FieldChain.pop_back();
271e5dd7070Spatrick }
272e5dd7070Spatrick }
273e5dd7070Spatrick
274e5dd7070Spatrick return false;
275e5dd7070Spatrick }
276e5dd7070Spatrick };
277e5dd7070Spatrick } // namespace
278e5dd7070Spatrick
PreVisitProcessArg(CheckerContext & C,SVal V,SourceRange ArgRange,const Expr * ArgEx,int ArgumentNumber,bool CheckUninitFields,const CallEvent & Call,std::unique_ptr<BugType> & BT,const ParmVarDecl * ParamDecl) const279e5dd7070Spatrick bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
280e5dd7070Spatrick SVal V,
281e5dd7070Spatrick SourceRange ArgRange,
282e5dd7070Spatrick const Expr *ArgEx,
283e5dd7070Spatrick int ArgumentNumber,
284e5dd7070Spatrick bool CheckUninitFields,
285e5dd7070Spatrick const CallEvent &Call,
286e5dd7070Spatrick std::unique_ptr<BugType> &BT,
287e5dd7070Spatrick const ParmVarDecl *ParamDecl
288e5dd7070Spatrick ) const {
289e5dd7070Spatrick const char *BD = "Uninitialized argument value";
290e5dd7070Spatrick
291e5dd7070Spatrick if (uninitRefOrPointer(C, V, ArgRange, ArgEx, BT, ParamDecl, BD,
292e5dd7070Spatrick ArgumentNumber))
293e5dd7070Spatrick return true;
294e5dd7070Spatrick
295e5dd7070Spatrick if (V.isUndef()) {
296ec727ea7Spatrick if (!ChecksEnabled[CK_ArgInitializedness]) {
297ec727ea7Spatrick C.addSink();
298ec727ea7Spatrick return true;
299ec727ea7Spatrick }
300e5dd7070Spatrick if (ExplodedNode *N = C.generateErrorNode()) {
301e5dd7070Spatrick LazyInit_BT(BD, BT);
302e5dd7070Spatrick // Generate a report for this bug.
303e5dd7070Spatrick SmallString<200> Buf;
304e5dd7070Spatrick llvm::raw_svector_ostream Os(Buf);
305e5dd7070Spatrick describeUninitializedArgumentInCall(Call, ArgumentNumber, Os);
306e5dd7070Spatrick auto R = std::make_unique<PathSensitiveBugReport>(*BT, Os.str(), N);
307e5dd7070Spatrick
308e5dd7070Spatrick R->addRange(ArgRange);
309e5dd7070Spatrick if (ArgEx)
310e5dd7070Spatrick bugreporter::trackExpressionValue(N, ArgEx, *R);
311e5dd7070Spatrick C.emitReport(std::move(R));
312e5dd7070Spatrick }
313e5dd7070Spatrick return true;
314e5dd7070Spatrick }
315e5dd7070Spatrick
316e5dd7070Spatrick if (!CheckUninitFields)
317e5dd7070Spatrick return false;
318e5dd7070Spatrick
319e5dd7070Spatrick if (auto LV = V.getAs<nonloc::LazyCompoundVal>()) {
320e5dd7070Spatrick const LazyCompoundValData *D = LV->getCVData();
321e5dd7070Spatrick FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
322e5dd7070Spatrick C.getSValBuilder().getRegionManager(),
323e5dd7070Spatrick D->getStore());
324e5dd7070Spatrick
325e5dd7070Spatrick if (F.Find(D->getRegion())) {
326ec727ea7Spatrick if (!ChecksEnabled[CK_ArgInitializedness]) {
327ec727ea7Spatrick C.addSink();
328ec727ea7Spatrick return true;
329ec727ea7Spatrick }
330e5dd7070Spatrick if (ExplodedNode *N = C.generateErrorNode()) {
331e5dd7070Spatrick LazyInit_BT(BD, BT);
332e5dd7070Spatrick SmallString<512> Str;
333e5dd7070Spatrick llvm::raw_svector_ostream os(Str);
334e5dd7070Spatrick os << "Passed-by-value struct argument contains uninitialized data";
335e5dd7070Spatrick
336e5dd7070Spatrick if (F.FieldChain.size() == 1)
337e5dd7070Spatrick os << " (e.g., field: '" << *F.FieldChain[0] << "')";
338e5dd7070Spatrick else {
339e5dd7070Spatrick os << " (e.g., via the field chain: '";
340e5dd7070Spatrick bool first = true;
341e5dd7070Spatrick for (SmallVectorImpl<const FieldDecl *>::iterator
342e5dd7070Spatrick DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
343e5dd7070Spatrick if (first)
344e5dd7070Spatrick first = false;
345e5dd7070Spatrick else
346e5dd7070Spatrick os << '.';
347e5dd7070Spatrick os << **DI;
348e5dd7070Spatrick }
349e5dd7070Spatrick os << "')";
350e5dd7070Spatrick }
351e5dd7070Spatrick
352e5dd7070Spatrick // Generate a report for this bug.
353e5dd7070Spatrick auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
354e5dd7070Spatrick R->addRange(ArgRange);
355e5dd7070Spatrick
356e5dd7070Spatrick if (ArgEx)
357e5dd7070Spatrick bugreporter::trackExpressionValue(N, ArgEx, *R);
358e5dd7070Spatrick // FIXME: enhance track back for uninitialized value for arbitrary
359e5dd7070Spatrick // memregions
360e5dd7070Spatrick C.emitReport(std::move(R));
361e5dd7070Spatrick }
362e5dd7070Spatrick return true;
363e5dd7070Spatrick }
364e5dd7070Spatrick }
365e5dd7070Spatrick
366e5dd7070Spatrick return false;
367e5dd7070Spatrick }
368e5dd7070Spatrick
checkFunctionPointerCall(const CallExpr * CE,CheckerContext & C,ProgramStateRef State) const369ec727ea7Spatrick ProgramStateRef CallAndMessageChecker::checkFunctionPointerCall(
370ec727ea7Spatrick const CallExpr *CE, CheckerContext &C, ProgramStateRef State) const {
371e5dd7070Spatrick
372e5dd7070Spatrick const Expr *Callee = CE->getCallee()->IgnoreParens();
373e5dd7070Spatrick const LocationContext *LCtx = C.getLocationContext();
374e5dd7070Spatrick SVal L = State->getSVal(Callee, LCtx);
375e5dd7070Spatrick
376e5dd7070Spatrick if (L.isUndef()) {
377ec727ea7Spatrick if (!ChecksEnabled[CK_FunctionPointer]) {
378ec727ea7Spatrick C.addSink(State);
379ec727ea7Spatrick return nullptr;
380ec727ea7Spatrick }
381e5dd7070Spatrick if (!BT_call_undef)
382e5dd7070Spatrick BT_call_undef.reset(new BuiltinBug(
383ec727ea7Spatrick OriginalName,
384ec727ea7Spatrick "Called function pointer is an uninitialized pointer value"));
385e5dd7070Spatrick emitBadCall(BT_call_undef.get(), C, Callee);
386ec727ea7Spatrick return nullptr;
387e5dd7070Spatrick }
388e5dd7070Spatrick
389e5dd7070Spatrick ProgramStateRef StNonNull, StNull;
390e5dd7070Spatrick std::tie(StNonNull, StNull) = State->assume(L.castAs<DefinedOrUnknownSVal>());
391e5dd7070Spatrick
392e5dd7070Spatrick if (StNull && !StNonNull) {
393ec727ea7Spatrick if (!ChecksEnabled[CK_FunctionPointer]) {
394ec727ea7Spatrick C.addSink(StNull);
395ec727ea7Spatrick return nullptr;
396ec727ea7Spatrick }
397e5dd7070Spatrick if (!BT_call_null)
398e5dd7070Spatrick BT_call_null.reset(new BuiltinBug(
399ec727ea7Spatrick OriginalName, "Called function pointer is null (null dereference)"));
400e5dd7070Spatrick emitBadCall(BT_call_null.get(), C, Callee);
401ec727ea7Spatrick return nullptr;
402e5dd7070Spatrick }
403e5dd7070Spatrick
404ec727ea7Spatrick return StNonNull;
405e5dd7070Spatrick }
406e5dd7070Spatrick
checkParameterCount(const CallEvent & Call,CheckerContext & C,ProgramStateRef State) const407ec727ea7Spatrick ProgramStateRef CallAndMessageChecker::checkParameterCount(
408ec727ea7Spatrick const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
409e5dd7070Spatrick
410ec727ea7Spatrick // If we have a function or block declaration, we can make sure we pass
411ec727ea7Spatrick // enough parameters.
412ec727ea7Spatrick unsigned Params = Call.parameters().size();
413ec727ea7Spatrick if (Call.getNumArgs() >= Params)
414ec727ea7Spatrick return State;
415ec727ea7Spatrick
416ec727ea7Spatrick if (!ChecksEnabled[CK_ParameterCount]) {
417ec727ea7Spatrick C.addSink(State);
418ec727ea7Spatrick return nullptr;
419ec727ea7Spatrick }
420ec727ea7Spatrick
421ec727ea7Spatrick ExplodedNode *N = C.generateErrorNode();
422ec727ea7Spatrick if (!N)
423ec727ea7Spatrick return nullptr;
424ec727ea7Spatrick
425ec727ea7Spatrick LazyInit_BT("Function call with too few arguments", BT_call_few_args);
426ec727ea7Spatrick
427ec727ea7Spatrick SmallString<512> Str;
428ec727ea7Spatrick llvm::raw_svector_ostream os(Str);
429ec727ea7Spatrick if (isa<AnyFunctionCall>(Call)) {
430ec727ea7Spatrick os << "Function ";
431ec727ea7Spatrick } else {
432ec727ea7Spatrick assert(isa<BlockCall>(Call));
433ec727ea7Spatrick os << "Block ";
434ec727ea7Spatrick }
435ec727ea7Spatrick os << "taking " << Params << " argument" << (Params == 1 ? "" : "s")
436ec727ea7Spatrick << " is called with fewer (" << Call.getNumArgs() << ")";
437ec727ea7Spatrick
438ec727ea7Spatrick C.emitReport(
439ec727ea7Spatrick std::make_unique<PathSensitiveBugReport>(*BT_call_few_args, os.str(), N));
440ec727ea7Spatrick return nullptr;
441ec727ea7Spatrick }
442ec727ea7Spatrick
checkCXXMethodCall(const CXXInstanceCall * CC,CheckerContext & C,ProgramStateRef State) const443ec727ea7Spatrick ProgramStateRef CallAndMessageChecker::checkCXXMethodCall(
444ec727ea7Spatrick const CXXInstanceCall *CC, CheckerContext &C, ProgramStateRef State) const {
445ec727ea7Spatrick
446ec727ea7Spatrick SVal V = CC->getCXXThisVal();
447ec727ea7Spatrick if (V.isUndef()) {
448ec727ea7Spatrick if (!ChecksEnabled[CK_CXXThisMethodCall]) {
449ec727ea7Spatrick C.addSink(State);
450ec727ea7Spatrick return nullptr;
451ec727ea7Spatrick }
452ec727ea7Spatrick if (!BT_cxx_call_undef)
453ec727ea7Spatrick BT_cxx_call_undef.reset(new BuiltinBug(
454ec727ea7Spatrick OriginalName, "Called C++ object pointer is uninitialized"));
455ec727ea7Spatrick emitBadCall(BT_cxx_call_undef.get(), C, CC->getCXXThisExpr());
456ec727ea7Spatrick return nullptr;
457ec727ea7Spatrick }
458ec727ea7Spatrick
459ec727ea7Spatrick ProgramStateRef StNonNull, StNull;
460ec727ea7Spatrick std::tie(StNonNull, StNull) = State->assume(V.castAs<DefinedOrUnknownSVal>());
461ec727ea7Spatrick
462ec727ea7Spatrick if (StNull && !StNonNull) {
463ec727ea7Spatrick if (!ChecksEnabled[CK_CXXThisMethodCall]) {
464ec727ea7Spatrick C.addSink(StNull);
465ec727ea7Spatrick return nullptr;
466ec727ea7Spatrick }
467ec727ea7Spatrick if (!BT_cxx_call_null)
468ec727ea7Spatrick BT_cxx_call_null.reset(
469ec727ea7Spatrick new BuiltinBug(OriginalName, "Called C++ object pointer is null"));
470ec727ea7Spatrick emitBadCall(BT_cxx_call_null.get(), C, CC->getCXXThisExpr());
471ec727ea7Spatrick return nullptr;
472ec727ea7Spatrick }
473ec727ea7Spatrick
474ec727ea7Spatrick return StNonNull;
475ec727ea7Spatrick }
476ec727ea7Spatrick
477ec727ea7Spatrick ProgramStateRef
checkCXXDeallocation(const CXXDeallocatorCall * DC,CheckerContext & C,ProgramStateRef State) const478ec727ea7Spatrick CallAndMessageChecker::checkCXXDeallocation(const CXXDeallocatorCall *DC,
479ec727ea7Spatrick CheckerContext &C,
480ec727ea7Spatrick ProgramStateRef State) const {
481ec727ea7Spatrick const CXXDeleteExpr *DE = DC->getOriginExpr();
482ec727ea7Spatrick assert(DE);
483e5dd7070Spatrick SVal Arg = C.getSVal(DE->getArgument());
484ec727ea7Spatrick if (!Arg.isUndef())
485ec727ea7Spatrick return State;
486ec727ea7Spatrick
487ec727ea7Spatrick if (!ChecksEnabled[CK_CXXDeallocationArg]) {
488ec727ea7Spatrick C.addSink(State);
489ec727ea7Spatrick return nullptr;
490ec727ea7Spatrick }
491ec727ea7Spatrick
492e5dd7070Spatrick StringRef Desc;
493e5dd7070Spatrick ExplodedNode *N = C.generateErrorNode();
494e5dd7070Spatrick if (!N)
495ec727ea7Spatrick return nullptr;
496e5dd7070Spatrick if (!BT_cxx_delete_undef)
497e5dd7070Spatrick BT_cxx_delete_undef.reset(
498ec727ea7Spatrick new BuiltinBug(OriginalName, "Uninitialized argument value"));
499e5dd7070Spatrick if (DE->isArrayFormAsWritten())
500e5dd7070Spatrick Desc = "Argument to 'delete[]' is uninitialized";
501e5dd7070Spatrick else
502e5dd7070Spatrick Desc = "Argument to 'delete' is uninitialized";
503e5dd7070Spatrick BugType *BT = BT_cxx_delete_undef.get();
504e5dd7070Spatrick auto R = std::make_unique<PathSensitiveBugReport>(*BT, Desc, N);
505e5dd7070Spatrick bugreporter::trackExpressionValue(N, DE, *R);
506e5dd7070Spatrick C.emitReport(std::move(R));
507ec727ea7Spatrick return nullptr;
508e5dd7070Spatrick }
509e5dd7070Spatrick
checkArgInitializedness(const CallEvent & Call,CheckerContext & C,ProgramStateRef State) const510ec727ea7Spatrick ProgramStateRef CallAndMessageChecker::checkArgInitializedness(
511ec727ea7Spatrick const CallEvent &Call, CheckerContext &C, ProgramStateRef State) const {
512e5dd7070Spatrick
513e5dd7070Spatrick const Decl *D = Call.getDecl();
514e5dd7070Spatrick
515e5dd7070Spatrick // Don't check for uninitialized field values in arguments if the
516e5dd7070Spatrick // caller has a body that is available and we have the chance to inline it.
517e5dd7070Spatrick // This is a hack, but is a reasonable compromise betweens sometimes warning
518e5dd7070Spatrick // and sometimes not depending on if we decide to inline a function.
519e5dd7070Spatrick const bool checkUninitFields =
520e5dd7070Spatrick !(C.getAnalysisManager().shouldInlineCall() && (D && D->getBody()));
521e5dd7070Spatrick
522e5dd7070Spatrick std::unique_ptr<BugType> *BT;
523e5dd7070Spatrick if (isa<ObjCMethodCall>(Call))
524e5dd7070Spatrick BT = &BT_msg_arg;
525e5dd7070Spatrick else
526e5dd7070Spatrick BT = &BT_call_arg;
527e5dd7070Spatrick
528e5dd7070Spatrick const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D);
529e5dd7070Spatrick for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i) {
530e5dd7070Spatrick const ParmVarDecl *ParamDecl = nullptr;
531e5dd7070Spatrick if (FD && i < FD->getNumParams())
532e5dd7070Spatrick ParamDecl = FD->getParamDecl(i);
533e5dd7070Spatrick if (PreVisitProcessArg(C, Call.getArgSVal(i), Call.getArgSourceRange(i),
534ec727ea7Spatrick Call.getArgExpr(i), i, checkUninitFields, Call, *BT,
535ec727ea7Spatrick ParamDecl))
536ec727ea7Spatrick return nullptr;
537e5dd7070Spatrick }
538ec727ea7Spatrick return State;
539ec727ea7Spatrick }
540ec727ea7Spatrick
checkPreCall(const CallEvent & Call,CheckerContext & C) const541ec727ea7Spatrick void CallAndMessageChecker::checkPreCall(const CallEvent &Call,
542ec727ea7Spatrick CheckerContext &C) const {
543ec727ea7Spatrick ProgramStateRef State = C.getState();
544ec727ea7Spatrick
545ec727ea7Spatrick if (const CallExpr *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()))
546ec727ea7Spatrick State = checkFunctionPointerCall(CE, C, State);
547ec727ea7Spatrick
548ec727ea7Spatrick if (!State)
549ec727ea7Spatrick return;
550ec727ea7Spatrick
551ec727ea7Spatrick if (Call.getDecl())
552ec727ea7Spatrick State = checkParameterCount(Call, C, State);
553ec727ea7Spatrick
554ec727ea7Spatrick if (!State)
555ec727ea7Spatrick return;
556ec727ea7Spatrick
557ec727ea7Spatrick if (const auto *CC = dyn_cast<CXXInstanceCall>(&Call))
558ec727ea7Spatrick State = checkCXXMethodCall(CC, C, State);
559ec727ea7Spatrick
560ec727ea7Spatrick if (!State)
561ec727ea7Spatrick return;
562ec727ea7Spatrick
563ec727ea7Spatrick if (const auto *DC = dyn_cast<CXXDeallocatorCall>(&Call))
564ec727ea7Spatrick State = checkCXXDeallocation(DC, C, State);
565ec727ea7Spatrick
566ec727ea7Spatrick if (!State)
567ec727ea7Spatrick return;
568ec727ea7Spatrick
569ec727ea7Spatrick State = checkArgInitializedness(Call, C, State);
570e5dd7070Spatrick
571e5dd7070Spatrick // If we make it here, record our assumptions about the callee.
572e5dd7070Spatrick C.addTransition(State);
573e5dd7070Spatrick }
574e5dd7070Spatrick
checkPreObjCMessage(const ObjCMethodCall & msg,CheckerContext & C) const575e5dd7070Spatrick void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
576e5dd7070Spatrick CheckerContext &C) const {
577e5dd7070Spatrick SVal recVal = msg.getReceiverSVal();
578e5dd7070Spatrick if (recVal.isUndef()) {
579ec727ea7Spatrick if (!ChecksEnabled[CK_UndefReceiver]) {
580ec727ea7Spatrick C.addSink();
581ec727ea7Spatrick return;
582ec727ea7Spatrick }
583e5dd7070Spatrick if (ExplodedNode *N = C.generateErrorNode()) {
584e5dd7070Spatrick BugType *BT = nullptr;
585e5dd7070Spatrick switch (msg.getMessageKind()) {
586e5dd7070Spatrick case OCM_Message:
587e5dd7070Spatrick if (!BT_msg_undef)
588ec727ea7Spatrick BT_msg_undef.reset(new BuiltinBug(OriginalName,
589e5dd7070Spatrick "Receiver in message expression "
590e5dd7070Spatrick "is an uninitialized value"));
591e5dd7070Spatrick BT = BT_msg_undef.get();
592e5dd7070Spatrick break;
593e5dd7070Spatrick case OCM_PropertyAccess:
594e5dd7070Spatrick if (!BT_objc_prop_undef)
595e5dd7070Spatrick BT_objc_prop_undef.reset(new BuiltinBug(
596ec727ea7Spatrick OriginalName,
597ec727ea7Spatrick "Property access on an uninitialized object pointer"));
598e5dd7070Spatrick BT = BT_objc_prop_undef.get();
599e5dd7070Spatrick break;
600e5dd7070Spatrick case OCM_Subscript:
601e5dd7070Spatrick if (!BT_objc_subscript_undef)
602e5dd7070Spatrick BT_objc_subscript_undef.reset(new BuiltinBug(
603ec727ea7Spatrick OriginalName,
604ec727ea7Spatrick "Subscript access on an uninitialized object pointer"));
605e5dd7070Spatrick BT = BT_objc_subscript_undef.get();
606e5dd7070Spatrick break;
607e5dd7070Spatrick }
608e5dd7070Spatrick assert(BT && "Unknown message kind.");
609e5dd7070Spatrick
610e5dd7070Spatrick auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
611e5dd7070Spatrick const ObjCMessageExpr *ME = msg.getOriginExpr();
612e5dd7070Spatrick R->addRange(ME->getReceiverRange());
613e5dd7070Spatrick
614e5dd7070Spatrick // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet.
615e5dd7070Spatrick if (const Expr *ReceiverE = ME->getInstanceReceiver())
616e5dd7070Spatrick bugreporter::trackExpressionValue(N, ReceiverE, *R);
617e5dd7070Spatrick C.emitReport(std::move(R));
618e5dd7070Spatrick }
619e5dd7070Spatrick return;
620e5dd7070Spatrick }
621e5dd7070Spatrick }
622e5dd7070Spatrick
checkObjCMessageNil(const ObjCMethodCall & msg,CheckerContext & C) const623e5dd7070Spatrick void CallAndMessageChecker::checkObjCMessageNil(const ObjCMethodCall &msg,
624e5dd7070Spatrick CheckerContext &C) const {
625e5dd7070Spatrick HandleNilReceiver(C, C.getState(), msg);
626e5dd7070Spatrick }
627e5dd7070Spatrick
emitNilReceiverBug(CheckerContext & C,const ObjCMethodCall & msg,ExplodedNode * N) const628e5dd7070Spatrick void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
629e5dd7070Spatrick const ObjCMethodCall &msg,
630e5dd7070Spatrick ExplodedNode *N) const {
631ec727ea7Spatrick if (!ChecksEnabled[CK_NilReceiver]) {
632ec727ea7Spatrick C.addSink();
633ec727ea7Spatrick return;
634ec727ea7Spatrick }
635e5dd7070Spatrick
636e5dd7070Spatrick if (!BT_msg_ret)
637ec727ea7Spatrick BT_msg_ret.reset(new BuiltinBug(OriginalName,
638ec727ea7Spatrick "Receiver in message expression is 'nil'"));
639e5dd7070Spatrick
640e5dd7070Spatrick const ObjCMessageExpr *ME = msg.getOriginExpr();
641e5dd7070Spatrick
642e5dd7070Spatrick QualType ResTy = msg.getResultType();
643e5dd7070Spatrick
644e5dd7070Spatrick SmallString<200> buf;
645e5dd7070Spatrick llvm::raw_svector_ostream os(buf);
646e5dd7070Spatrick os << "The receiver of message '";
647e5dd7070Spatrick ME->getSelector().print(os);
648e5dd7070Spatrick os << "' is nil";
649e5dd7070Spatrick if (ResTy->isReferenceType()) {
650e5dd7070Spatrick os << ", which results in forming a null reference";
651e5dd7070Spatrick } else {
652e5dd7070Spatrick os << " and returns a value of type '";
653e5dd7070Spatrick msg.getResultType().print(os, C.getLangOpts());
654e5dd7070Spatrick os << "' that will be garbage";
655e5dd7070Spatrick }
656e5dd7070Spatrick
657e5dd7070Spatrick auto report =
658e5dd7070Spatrick std::make_unique<PathSensitiveBugReport>(*BT_msg_ret, os.str(), N);
659e5dd7070Spatrick report->addRange(ME->getReceiverRange());
660e5dd7070Spatrick // FIXME: This won't track "self" in messages to super.
661e5dd7070Spatrick if (const Expr *receiver = ME->getInstanceReceiver()) {
662e5dd7070Spatrick bugreporter::trackExpressionValue(N, receiver, *report);
663e5dd7070Spatrick }
664e5dd7070Spatrick C.emitReport(std::move(report));
665e5dd7070Spatrick }
666e5dd7070Spatrick
supportsNilWithFloatRet(const llvm::Triple & triple)667e5dd7070Spatrick static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
668e5dd7070Spatrick return (triple.getVendor() == llvm::Triple::Apple &&
669e5dd7070Spatrick (triple.isiOS() || triple.isWatchOS() ||
670e5dd7070Spatrick !triple.isMacOSXVersionLT(10,5)));
671e5dd7070Spatrick }
672e5dd7070Spatrick
HandleNilReceiver(CheckerContext & C,ProgramStateRef state,const ObjCMethodCall & Msg) const673e5dd7070Spatrick void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
674e5dd7070Spatrick ProgramStateRef state,
675e5dd7070Spatrick const ObjCMethodCall &Msg) const {
676e5dd7070Spatrick ASTContext &Ctx = C.getASTContext();
677e5dd7070Spatrick static CheckerProgramPointTag Tag(this, "NilReceiver");
678e5dd7070Spatrick
679e5dd7070Spatrick // Check the return type of the message expression. A message to nil will
680e5dd7070Spatrick // return different values depending on the return type and the architecture.
681e5dd7070Spatrick QualType RetTy = Msg.getResultType();
682e5dd7070Spatrick CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
683e5dd7070Spatrick const LocationContext *LCtx = C.getLocationContext();
684e5dd7070Spatrick
685e5dd7070Spatrick if (CanRetTy->isStructureOrClassType()) {
686e5dd7070Spatrick // Structure returns are safe since the compiler zeroes them out.
687e5dd7070Spatrick SVal V = C.getSValBuilder().makeZeroVal(RetTy);
688e5dd7070Spatrick C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
689e5dd7070Spatrick return;
690e5dd7070Spatrick }
691e5dd7070Spatrick
692e5dd7070Spatrick // Other cases: check if sizeof(return type) > sizeof(void*)
693e5dd7070Spatrick if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
694e5dd7070Spatrick .isConsumedExpr(Msg.getOriginExpr())) {
695e5dd7070Spatrick // Compute: sizeof(void *) and sizeof(return type)
696e5dd7070Spatrick const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
697e5dd7070Spatrick const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
698e5dd7070Spatrick
699e5dd7070Spatrick if (CanRetTy.getTypePtr()->isReferenceType()||
700e5dd7070Spatrick (voidPtrSize < returnTypeSize &&
701e5dd7070Spatrick !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
702e5dd7070Spatrick (Ctx.FloatTy == CanRetTy ||
703e5dd7070Spatrick Ctx.DoubleTy == CanRetTy ||
704e5dd7070Spatrick Ctx.LongDoubleTy == CanRetTy ||
705e5dd7070Spatrick Ctx.LongLongTy == CanRetTy ||
706e5dd7070Spatrick Ctx.UnsignedLongLongTy == CanRetTy)))) {
707e5dd7070Spatrick if (ExplodedNode *N = C.generateErrorNode(state, &Tag))
708e5dd7070Spatrick emitNilReceiverBug(C, Msg, N);
709e5dd7070Spatrick return;
710e5dd7070Spatrick }
711e5dd7070Spatrick
712e5dd7070Spatrick // Handle the safe cases where the return value is 0 if the
713e5dd7070Spatrick // receiver is nil.
714e5dd7070Spatrick //
715e5dd7070Spatrick // FIXME: For now take the conservative approach that we only
716e5dd7070Spatrick // return null values if we *know* that the receiver is nil.
717e5dd7070Spatrick // This is because we can have surprises like:
718e5dd7070Spatrick //
719e5dd7070Spatrick // ... = [[NSScreens screens] objectAtIndex:0];
720e5dd7070Spatrick //
721e5dd7070Spatrick // What can happen is that [... screens] could return nil, but
722e5dd7070Spatrick // it most likely isn't nil. We should assume the semantics
723e5dd7070Spatrick // of this case unless we have *a lot* more knowledge.
724e5dd7070Spatrick //
725e5dd7070Spatrick SVal V = C.getSValBuilder().makeZeroVal(RetTy);
726e5dd7070Spatrick C.addTransition(state->BindExpr(Msg.getOriginExpr(), LCtx, V), &Tag);
727e5dd7070Spatrick return;
728e5dd7070Spatrick }
729e5dd7070Spatrick
730e5dd7070Spatrick C.addTransition(state);
731e5dd7070Spatrick }
732e5dd7070Spatrick
registerCallAndMessageModeling(CheckerManager & mgr)733ec727ea7Spatrick void ento::registerCallAndMessageModeling(CheckerManager &mgr) {
734e5dd7070Spatrick mgr.registerChecker<CallAndMessageChecker>();
735e5dd7070Spatrick }
736e5dd7070Spatrick
shouldRegisterCallAndMessageModeling(const CheckerManager & mgr)737ec727ea7Spatrick bool ento::shouldRegisterCallAndMessageModeling(const CheckerManager &mgr) {
738e5dd7070Spatrick return true;
739e5dd7070Spatrick }
740e5dd7070Spatrick
registerCallAndMessageChecker(CheckerManager & mgr)741ec727ea7Spatrick void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
742ec727ea7Spatrick CallAndMessageChecker *checker = mgr.getChecker<CallAndMessageChecker>();
743ec727ea7Spatrick
744ec727ea7Spatrick checker->OriginalName = mgr.getCurrentCheckerName();
745ec727ea7Spatrick
746ec727ea7Spatrick #define QUERY_CHECKER_OPTION(OPTION) \
747ec727ea7Spatrick checker->ChecksEnabled[CallAndMessageChecker::CK_##OPTION] = \
748ec727ea7Spatrick mgr.getAnalyzerOptions().getCheckerBooleanOption( \
749ec727ea7Spatrick mgr.getCurrentCheckerName(), #OPTION);
750ec727ea7Spatrick
751ec727ea7Spatrick QUERY_CHECKER_OPTION(FunctionPointer)
752ec727ea7Spatrick QUERY_CHECKER_OPTION(ParameterCount)
753ec727ea7Spatrick QUERY_CHECKER_OPTION(CXXThisMethodCall)
754ec727ea7Spatrick QUERY_CHECKER_OPTION(CXXDeallocationArg)
755ec727ea7Spatrick QUERY_CHECKER_OPTION(ArgInitializedness)
756ec727ea7Spatrick QUERY_CHECKER_OPTION(ArgPointeeInitializedness)
757ec727ea7Spatrick QUERY_CHECKER_OPTION(NilReceiver)
758ec727ea7Spatrick QUERY_CHECKER_OPTION(UndefReceiver)
759e5dd7070Spatrick }
760e5dd7070Spatrick
shouldRegisterCallAndMessageChecker(const CheckerManager & mgr)761ec727ea7Spatrick bool ento::shouldRegisterCallAndMessageChecker(const CheckerManager &mgr) {
762e5dd7070Spatrick return true;
763e5dd7070Spatrick }
764