xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp (revision d1d76b2da7493dbba6ab174ff483e73661bd07d7)
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/CheckerContext.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/ObjCMessage.h"
20 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21 #include "clang/AST/ParentMap.h"
22 #include "clang/Basic/TargetInfo.h"
23 #include "llvm/ADT/SmallString.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
28 namespace {
29 class CallAndMessageChecker
30   : public Checker< check::PreStmt<CallExpr>, check::PreObjCMessage > {
31   mutable OwningPtr<BugType> BT_call_null;
32   mutable OwningPtr<BugType> BT_call_undef;
33   mutable OwningPtr<BugType> BT_call_arg;
34   mutable OwningPtr<BugType> BT_msg_undef;
35   mutable OwningPtr<BugType> BT_objc_prop_undef;
36   mutable OwningPtr<BugType> BT_msg_arg;
37   mutable OwningPtr<BugType> BT_msg_ret;
38 public:
39 
40   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
41   void checkPreObjCMessage(ObjCMessage msg, CheckerContext &C) const;
42 
43 private:
44   static void PreVisitProcessArgs(CheckerContext &C,CallOrObjCMessage callOrMsg,
45                              const char *BT_desc, OwningPtr<BugType> &BT);
46   static bool PreVisitProcessArg(CheckerContext &C, SVal V,SourceRange argRange,
47                                  const Expr *argEx,
48                                  const bool checkUninitFields,
49                                  const char *BT_desc,
50                                  OwningPtr<BugType> &BT);
51 
52   static void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
53   void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
54                           ExplodedNode *N) const;
55 
56   void HandleNilReceiver(CheckerContext &C,
57                          ProgramStateRef state,
58                          ObjCMessage msg) const;
59 
60   static void LazyInit_BT(const char *desc, OwningPtr<BugType> &BT) {
61     if (!BT)
62       BT.reset(new BuiltinBug(desc));
63   }
64 };
65 } // end anonymous namespace
66 
67 void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
68                                         const CallExpr *CE) {
69   ExplodedNode *N = C.generateSink();
70   if (!N)
71     return;
72 
73   BugReport *R = new BugReport(*BT, BT->getName(), N);
74   R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
75                                bugreporter::GetCalleeExpr(N), R));
76   C.EmitReport(R);
77 }
78 
79 void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
80                                                 CallOrObjCMessage callOrMsg,
81                                                 const char *BT_desc,
82                                                 OwningPtr<BugType> &BT) {
83   // Don't check for uninitialized field values in arguments if the
84   // caller has a body that is available and we have the chance to inline it.
85   // This is a hack, but is a reasonable compromise betweens sometimes warning
86   // and sometimes not depending on if we decide to inline a function.
87   const Decl *D = callOrMsg.getDecl();
88   const bool checkUninitFields =
89     !(C.getAnalysisManager().shouldInlineCall() &&
90       (D && D->getBody()));
91 
92   for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
93     if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
94                            callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
95                            checkUninitFields,
96                            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   const LocationContext *LCtx = C.getLocationContext();
214   SVal L = C.getState()->getSVal(Callee, LCtx);
215 
216   if (L.isUndef()) {
217     if (!BT_call_undef)
218       BT_call_undef.reset(new BuiltinBug("Called function pointer is an "
219                                          "uninitalized pointer value"));
220     EmitBadCall(BT_call_undef.get(), C, CE);
221     return;
222   }
223 
224   if (isa<loc::ConcreteInt>(L)) {
225     if (!BT_call_null)
226       BT_call_null.reset(
227         new BuiltinBug("Called function pointer is null (null dereference)"));
228     EmitBadCall(BT_call_null.get(), C, CE);
229   }
230 
231   PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState(), LCtx),
232                       "Function call argument is an uninitialized value",
233                       BT_call_arg);
234 }
235 
236 void CallAndMessageChecker::checkPreObjCMessage(ObjCMessage msg,
237                                                 CheckerContext &C) const {
238 
239   ProgramStateRef state = C.getState();
240   const LocationContext *LCtx = C.getLocationContext();
241 
242   // FIXME: Handle 'super'?
243   if (const Expr *receiver = msg.getInstanceReceiver()) {
244     SVal recVal = state->getSVal(receiver, LCtx);
245     if (recVal.isUndef()) {
246       if (ExplodedNode *N = C.generateSink()) {
247         BugType *BT = 0;
248         if (msg.isPureMessageExpr()) {
249           if (!BT_msg_undef)
250             BT_msg_undef.reset(new BuiltinBug("Receiver in message expression "
251                                               "is an uninitialized value"));
252           BT = BT_msg_undef.get();
253         }
254         else {
255           if (!BT_objc_prop_undef)
256             BT_objc_prop_undef.reset(new BuiltinBug("Property access on an "
257                                               "uninitialized object pointer"));
258           BT = BT_objc_prop_undef.get();
259         }
260         BugReport *R =
261           new BugReport(*BT, BT->getName(), N);
262         R->addRange(receiver->getSourceRange());
263         R->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
264                                                                    receiver,
265                                                                    R));
266         C.EmitReport(R);
267       }
268       return;
269     } else {
270       // Bifurcate the state into nil and non-nil ones.
271       DefinedOrUnknownSVal receiverVal = cast<DefinedOrUnknownSVal>(recVal);
272 
273       ProgramStateRef notNilState, nilState;
274       llvm::tie(notNilState, nilState) = state->assume(receiverVal);
275 
276       // Handle receiver must be nil.
277       if (nilState && !notNilState) {
278         HandleNilReceiver(C, state, msg);
279         return;
280       }
281     }
282   }
283 
284   const char *bugDesc = msg.isPropertySetter() ?
285                      "Argument for property setter is an uninitialized value"
286                    : "Argument in message expression is an uninitialized value";
287   // Check for any arguments that are uninitialized/undefined.
288   PreVisitProcessArgs(C, CallOrObjCMessage(msg, state, LCtx),
289                       bugDesc, BT_msg_arg);
290 }
291 
292 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
293                                                const ObjCMessage &msg,
294                                                ExplodedNode *N) const {
295 
296   if (!BT_msg_ret)
297     BT_msg_ret.reset(
298       new BuiltinBug("Receiver in message expression is "
299                      "'nil' and returns a garbage value"));
300 
301   SmallString<200> buf;
302   llvm::raw_svector_ostream os(buf);
303   os << "The receiver of message '" << msg.getSelector().getAsString()
304      << "' is nil and returns a value of type '"
305      << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
306 
307   BugReport *report = new BugReport(*BT_msg_ret, os.str(), N);
308   if (const Expr *receiver = msg.getInstanceReceiver()) {
309     report->addRange(receiver->getSourceRange());
310     report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,
311                                                                     receiver,
312                                                                     report));
313   }
314   C.EmitReport(report);
315 }
316 
317 static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
318   return (triple.getVendor() == llvm::Triple::Apple &&
319           (triple.getOS() == llvm::Triple::IOS ||
320            !triple.isMacOSXVersionLT(10,5)));
321 }
322 
323 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
324                                               ProgramStateRef state,
325                                               ObjCMessage msg) const {
326   ASTContext &Ctx = C.getASTContext();
327 
328   // Check the return type of the message expression.  A message to nil will
329   // return different values depending on the return type and the architecture.
330   QualType RetTy = msg.getType(Ctx);
331   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
332   const LocationContext *LCtx = C.getLocationContext();
333 
334   if (CanRetTy->isStructureOrClassType()) {
335     // Structure returns are safe since the compiler zeroes them out.
336     SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
337     C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
338     return;
339   }
340 
341   // Other cases: check if sizeof(return type) > sizeof(void*)
342   if (CanRetTy != Ctx.VoidTy && C.getLocationContext()->getParentMap()
343                                   .isConsumedExpr(msg.getMessageExpr())) {
344     // Compute: sizeof(void *) and sizeof(return type)
345     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
346     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
347 
348     if (voidPtrSize < returnTypeSize &&
349         !(supportsNilWithFloatRet(Ctx.getTargetInfo().getTriple()) &&
350           (Ctx.FloatTy == CanRetTy ||
351            Ctx.DoubleTy == CanRetTy ||
352            Ctx.LongDoubleTy == CanRetTy ||
353            Ctx.LongLongTy == CanRetTy ||
354            Ctx.UnsignedLongLongTy == CanRetTy))) {
355       if (ExplodedNode *N = C.generateSink(state))
356         emitNilReceiverBug(C, msg, N);
357       return;
358     }
359 
360     // Handle the safe cases where the return value is 0 if the
361     // receiver is nil.
362     //
363     // FIXME: For now take the conservative approach that we only
364     // return null values if we *know* that the receiver is nil.
365     // This is because we can have surprises like:
366     //
367     //   ... = [[NSScreens screens] objectAtIndex:0];
368     //
369     // What can happen is that [... screens] could return nil, but
370     // it most likely isn't nil.  We should assume the semantics
371     // of this case unless we have *a lot* more knowledge.
372     //
373     SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
374     C.addTransition(state->BindExpr(msg.getMessageExpr(), LCtx, V));
375     return;
376   }
377 
378   C.addTransition(state);
379 }
380 
381 void ento::registerCallAndMessageChecker(CheckerManager &mgr) {
382   mgr.registerChecker<CallAndMessageChecker>();
383 }
384