xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (revision 6bad4905d73ef9634e23709ba79747e83b27881c)
1 //===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This defines CallAndMessageChecker, a builtin checker that checks for various
11 // errors of call and objc message expressions.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ClangSACheckers.h"
16 #include "clang/StaticAnalyzer/Core/Checker.h"
17 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
18 #include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
21 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
22 #include "clang/AST/ParentMap.h"
23 #include "clang/Basic/TargetInfo.h"
24 #include "llvm/ADT/SmallString.h"
25 
26 using namespace clang;
27 using namespace ento;
28 
29 namespace {
30 class CallAndMessageChecker
31   : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > {
32   mutable OwningPtr<BugType> BT_call_null;
33   mutable OwningPtr<BugType> BT_call_undef;
34   mutable OwningPtr<BugType> BT_call_arg;
35   mutable OwningPtr<BugType> BT_msg_undef;
36   mutable OwningPtr<BugType> BT_objc_prop_undef;
37   mutable OwningPtr<BugType> BT_msg_arg;
38   mutable OwningPtr<BugType> BT_msg_ret;
39 public:
40 
41   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
42   void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
43 
44 private:
45   static void PreVisitProcessArgs(CheckerContext &C, const CallEvent &Call,
46                              const char *BT_desc, OwningPtr<BugType> &BT);
47   static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange,
48                                  const Expr *argEx,
49                                  const bool checkUninitFields,
50                                  const char *BT_desc,
51                                  OwningPtr<BugType> &BT);
52 
53   static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
54   void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
55                           ExplodedNode *N) const;
56 
57   void HandleNilReceiver(CheckerContext &C,
58                          ProgramStateRef state,
59                          ObjCMessage msg) const;
60 
61   static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
62     if (!BT)
63       BT.reset(new BuiltinBug(desc));
64   }
65 };
66 } // end anonymous namespace
67 
68 void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
69                                         const CallExpr *CE) {
70   ExplodedNode *N = C.generateSink();
71   if (!N)
72     return;
73 
74   BugReport *R = new BugReport(*BT, BT->getName(), N);
75   R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
76                                bugreporter::GetCalleeExpr(N), R));
77   C.EmitReport(R);
78 }
79 
80 void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
81                                                 const CallEvent &Call,
82                                                 const char *BT_desc,
83                                                 OwningPtr<BugType> &BT) {
84   // Don't check for uninitialized field values in arguments if the
85   // caller has a body that is available and we have the chance to inline it.
86   // This is a hack, but is a reasonable compromise betweens sometimes warning
87   // and sometimes not depending on if we decide to inline a function.
88   const Decl *D = Call.getDecl();
89   const bool checkUninitFields =
90     !(C.getAnalysisManager().shouldInlineCall() &&
91       (D && D->getBody()));
92 
93   for (unsigned i = 0, e = Call.getNumArgs(); i != e; ++i)
94     if (PreVisitProcessArg(C, Call.getArgSVal(i),
95                            Call.getArgSourceRange(i), Call.getArgExpr(i),
96                            checkUninitFields, BT_desc, BT))
97       return;
98 }
99 
100 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
101                                                SVal V, SourceRange argRange,
102                                                const Expr *argEx,
103                                                const bool checkUninitFields,
104                                                const char *BT_desc,
105                                                OwningPtr<BugType> &BT) {
106   if (V.isUndef()) {
107     if (ExplodedNode *N = C.generateSink()) {
108       LazyInit_BT(BT_desc, BT);
109 
110       // Generate a report for this bug.
111       BugReport *R = new BugReport(*BT, BT->getName(), N);
112       R->addRange(argRange);
113       if (argEx)
114         R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, argEx,
115                                                                    R));
116       C.EmitReport(R);
117     }
118     return true;
119   }
120 
121   if (!checkUninitFields)
122     return false;
123 
124   if (const nonloc::LazyCompoundVal *LV =
125         dyn_cast<nonloc::LazyCompoundVal>(&V)) {
126 
127     class FindUninitializedField {
128     public:
129       SmallVector<const FieldDecl *, 10> FieldChain;
130     private:
131       StoreManager &StoreMgr;
132       MemRegionManager &MrMgr;
133       Store store;
134     public:
135       FindUninitializedField(StoreManager &storeMgr,
136                              MemRegionManager &mrMgr, Store s)
137       : StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
138 
139       bool Find(const TypedValueRegion *R) {
140         QualType T = R->getValueType();
141         if (const RecordType *RT = T->getAsStructureType()) {
142           const RecordDecl *RD = RT->getDecl()->getDefinition();
143           assert(RD && "Referred record has no definition");
144           for (RecordDecl::field_iterator I =
145                RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
146             const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
147             FieldChain.push_back(*I);
148             T = I->getType();
149             if (T->getAsStructureType()) {
150               if (Find(FR))
151                 return true;
152             }
153             else {
154               const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
155               if (V.isUndef())
156                 return true;
157             }
158             FieldChain.pop_back();
159           }
160         }
161 
162         return false;
163       }
164     };
165 
166     const LazyCompoundValData *D = LV->getCVData();
167     FindUninitializedField F(C.getState()->getStateManager().getStoreManager(),
168                              C.getSValBuilder().getRegionManager(),
169                              D->getStore());
170 
171     if (F.Find(D->getRegion())) {
172       if (ExplodedNode *N = C.generateSink()) {
173         LazyInit_BT(BT_desc, BT);
174         SmallString<512> Str;
175         llvm::raw_svector_ostream os(Str);
176         os << "Passed-by-value struct argument contains uninitialized data";
177 
178         if (F.FieldChain.size() == 1)
179           os << " (e.g., field: '" << *F.FieldChain[0] << "')";
180         else {
181           os << " (e.g., via the field chain: '";
182           bool first = true;
183           for (SmallVectorImpl<const FieldDecl *>::iterator
184                DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
185             if (first)
186               first = false;
187             else
188               os << '.';
189             os << **DI;
190           }
191           os << "')";
192         }
193 
194         // Generate a report for this bug.
195         BugReport *R = new BugReport(*BT, os.str(), N);
196         R->addRange(argRange);
197 
198         // FIXME: enhance track back for uninitialized value for arbitrary
199         // memregions
200         C.EmitReport(R);
201       }
202       return true;
203     }
204   }
205 
206   return false;
207 }
208 
209 void CallAndMessageChecker::checkPreStmt(const CallExpr *CE,
210                                          CheckerContext &C) const{
211 
212   const Expr *Callee = CE->getCallee()->IgnoreParens();
213   ProgramStateRef State = C.getState();
214   const LocationContext *LCtx = C.getLocationContext();
215   SVal L = State->getSVal(Callee, LCtx);
216 
217   if (L.isUndef()) {
218     if (!BT_call_undef)
219       BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
220                                          "uninitalized pointer value"));
221     EmitBadCall(BT_call_undef.get(), C, CE);
222     return;
223   }
224 
225   if (L.isZeroConstant()) {
226     if (!BT_call_null)
227       BT_call_null.reset(
228         new BuiltinBug("Called function pointer is null (null dereference)"));
229     EmitBadCall(BT_call_null.get(), C, CE);
230   }
231 
232   // FIXME: This tree of switching can go away if/when we add a check::postCall.
233   if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) {
234     BlockCall Call(CE, State, LCtx);
235     PreVisitProcessArgs(C, Call,
236                         "Block call argument is an uninitialized value",
237                         BT_call_arg);
238   } else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) {
239     CXXMemberCall Call(me, State, LCtx);
240     PreVisitProcessArgs(C, Call,
241                         "Function call argument is an uninitialized value",
242                         BT_call_arg);
243   } else {
244     FunctionCall Call(CE, State, LCtx);
245     PreVisitProcessArgs(C, Call,
246                         "Function call argument is an uninitialized value",
247                         BT_call_arg);
248   }
249 }
250 
251 void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
252                                                 CheckerContext &C) const {
253 
254   ProgramStateRef state = C.getState();
255   const LocationContext *LCtx = C.getLocationContext();
256 
257   // FIXME: Handle 'super'?
258   if (const Expr *receiver = msg.getInstanceReceiver()) {
259     SVal recVal = state->getSVal(receiver, LCtx);
260     if (recVal.isUndef()) {
261       if (ExplodedNode *N = C.generateSink()) {
262         BugType *BT = 0;
263         if (msg.isPureMessageExpr()) {
264           if (!BT_msg_undef)
265             BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
266                                               "is an uninitialized value"));
267           BT = BT_msg_undef.get();
268         }
269         else {
270           if (!BT_objc_prop_undef)
271             BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
272                                               "uninitialized object pointer"));
273           BT = BT_objc_prop_undef.get();
274         }
275         BugReport *R =
276           new BugReport(*BT, BT->getName(), N);
277         R->addRange(receiver->getSourceRange());
278         R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
279                                                                    receiver,
280                                                                    R));
281         C.EmitReport(R);
282       }
283       return;
284     } else {
285       // Bifurcate the state into nil and non-nil ones.
286       DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
287 
288       ProgramStateRef notNilState, nilState;
289       llvm::tie(notNilState, nilState) = state->assume(receiverVal);
290 
291       // Handle receiver must be nil.
292       if (nilState && !notNilState) {
293         HandleNilReceiver(C, state, msg);
294         return;
295       }
296     }
297   }
298 
299   const char *bugDesc = msg.isPropertySetter() ?
300                      "Argument for property setter is an uninitialized value"
301                    : "Argument in message expression is an uninitialized value";
302   // Check for any arguments that are uninitialized/undefined.
303   // FIXME: ObjCMessage is set to be removed soon.
304   PreVisitProcessArgs(C, ObjCMessageSend(msg.getMessageExpr(), state, LCtx),
305                       bugDesc, BT_msg_arg);
306 }
307 
308 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
309                                                const ObjCMessage &msg,
310                                                ExplodedNode *N) const {
311 
312   if (!BT_msg_ret)
313     BT_msg_ret.reset(
314       new BuiltinBug("Receiver in message expression is "
315                      "'nil' and returns a garbage value"));
316 
317   SmallString<200> buf;
318   llvm::raw_svector_ostream os(buf);
319   os << "The receiver of message '" << msg.getSelector().getAsString()
320      << "' is nil and returns a value of type '"
321      << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
322 
323   BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
324   if (const Expr *receiver = msg.getInstanceReceiver()) {
325     report->addRange(receiver->getSourceRange());
326     report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
327                                                                     receiver,
328                                                                     report));
329   }
330   C.EmitReport(report);
331 }
332 
333 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
334   return (triple.getVendor() == llvm::Triple::Apple &&
335           (triple.getOS() == llvm::Triple::IOS ||
336            !triple.isMacOSXVersionLT(10,5)));
337 }
338 
339 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
340                                               ProgramStateRef state,
341                                               ObjCMessage msg) const {
342   ASTContext &Ctx = C.getASTContext();
343 
344   // Check the return type of the message expression.  A message to nil will
345   // return different values depending on the return type and the architecture.
346   QualType RetTy = msg.getType(Ctx);
347   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
348   const LocationContext *LCtx = C.getLocationContext();
349 
350   if (CanRetTy->isStructureOrClassType()) {
351     // Structure returns are safe since the compiler zeroes them out.
352     SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
353     C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
354     return;
355   }
356 
357   // Other cases: check if sizeof(return type) > sizeof(void*)
358   if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
359                                   .isConsumedExpr(msg.getMessageExpr())) {
360     // Compute: sizeof(void *) and sizeof(return type)
361     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
362     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
363 
364     if (voidPtrSize < returnTypeSize &&
365         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
366           (Ctx.FloatTy == CanRetTy ||
367            Ctx.DoubleTy == CanRetTy ||
368            Ctx.LongDoubleTy == CanRetTy ||
369            Ctx.LongLongTy == CanRetTy ||
370            Ctx.UnsignedLongLongTy == CanRetTy))) {
371       if (ExplodedNode *N = C.generateSink(state))
372         emitNilReceiverBug(C, msg, N);
373       return;
374     }
375 
376     // Handle the safe cases where the return value is 0 if the
377     // receiver is nil.
378     //
379     // FIXME: For now take the conservative approach that we only
380     // return null values if we *know* that the receiver is nil.
381     // This is because we can have surprises like:
382     //
383     //   ... = [[NSScreens screens] objectAtIndex:0];
384     //
385     // What can happen is that [... screens] could return nil, but
386     // it most likely isn't nil.  We should assume the semantics
387     // of this case unless we have *a lot* more knowledge.
388     //
389     SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
390     C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
391     return;
392   }
393 
394   C.addTransition(state);
395 }
396 
397 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
398   mgr.registerChecker<CallAndMessageChecker>();
399 }
400