]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/Checker/CallAndMessageChecker.cpp
Update clang to r97873.
[FreeBSD/FreeBSD.git] / lib / Checker / CallAndMessageChecker.cpp
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 "clang/Basic/TargetInfo.h"
16 #include "clang/Checker/PathSensitive/CheckerVisitor.h"
17 #include "clang/Checker/BugReporter/BugReporter.h"
18 #include "clang/AST/ParentMap.h"
19 #include "GRExprEngineInternalChecks.h"
20
21 using namespace clang;
22
23 namespace {
24 class CallAndMessageChecker
25   : public CheckerVisitor<CallAndMessageChecker> {
26   BugType *BT_call_null;
27   BugType *BT_call_undef;  
28   BugType *BT_call_arg;
29   BugType *BT_msg_undef;
30   BugType *BT_msg_arg;
31   BugType *BT_msg_ret;
32 public:
33   CallAndMessageChecker() :
34     BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
35     BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {}
36
37   static void *getTag() {
38     static int x = 0;
39     return &x;
40   }
41
42   void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
43   void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
44   bool EvalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
45
46 private:
47   void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
48   void EmitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
49                           ExplodedNode *N);
50     
51   void HandleNilReceiver(CheckerContext &C, const GRState *state,
52                          const ObjCMessageExpr *ME);    
53 };
54 } // end anonymous namespace
55
56 void clang::RegisterCallAndMessageChecker(GRExprEngine &Eng) {
57   Eng.registerCheck(new CallAndMessageChecker());
58 }
59
60 void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
61                                         const CallExpr *CE) {
62   ExplodedNode *N = C.GenerateSink();
63   if (!N)
64     return;
65     
66   EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
67   R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
68                        bugreporter::GetCalleeExpr(N));
69   C.EmitReport(R);
70 }
71
72 void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C, 
73                                              const CallExpr *CE){
74   
75   const Expr *Callee = CE->getCallee()->IgnoreParens();
76   SVal L = C.getState()->getSVal(Callee);
77   
78   if (L.isUndef()) {
79     if (!BT_call_undef)
80       BT_call_undef =
81         new BuiltinBug("Called function pointer is an undefined pointer value");
82     EmitBadCall(BT_call_undef, C, CE);
83     return;
84   }
85   
86   if (isa<loc::ConcreteInt>(L)) {
87     if (!BT_call_null)
88       BT_call_null =
89         new BuiltinBug("Called function pointer is null (null dereference)");
90     EmitBadCall(BT_call_null, C, CE);
91   }  
92   
93   for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
94        I != E; ++I) {
95     if (C.getState()->getSVal(*I).isUndef()) {
96       if (ExplodedNode *N = C.GenerateSink()) {
97         if (!BT_call_arg)
98           BT_call_arg = new BuiltinBug("Pass-by-value argument in function call"
99                                        " is undefined");
100         // Generate a report for this bug.
101         EnhancedBugReport *R = new EnhancedBugReport(*BT_call_arg,
102                                                      BT_call_arg->getName(), N);
103         R->addRange((*I)->getSourceRange());
104         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
105         C.EmitReport(R);
106         return;
107       }
108     }
109   }
110 }
111
112 void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
113                                                     const ObjCMessageExpr *ME) {
114
115   const GRState *state = C.getState();
116
117   if (const Expr *receiver = ME->getReceiver())
118     if (state->getSVal(receiver).isUndef()) {
119       if (ExplodedNode *N = C.GenerateSink()) {
120         if (!BT_msg_undef)
121           BT_msg_undef =
122             new BuiltinBug("Receiver in message expression is a garbage value");
123         EnhancedBugReport *R =
124           new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
125         R->addRange(receiver->getSourceRange());
126         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
127                              receiver);
128         C.EmitReport(R);
129       }
130       return;
131     }
132
133   // Check for any arguments that are uninitialized/undefined.
134   for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
135          E = ME->arg_end(); I != E; ++I) {
136     if (state->getSVal(*I).isUndef()) {
137       if (ExplodedNode *N = C.GenerateSink()) {
138         if (!BT_msg_arg)
139           BT_msg_arg =
140             new BuiltinBug("Pass-by-value argument in message expression"
141                            " is undefined");      
142         // Generate a report for this bug.
143         EnhancedBugReport *R = new EnhancedBugReport(*BT_msg_arg,
144                                                      BT_msg_arg->getName(), N);
145         R->addRange((*I)->getSourceRange());
146         R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, *I);
147         C.EmitReport(R);
148         return;
149       }
150     }
151   }
152 }
153
154 bool CallAndMessageChecker::EvalNilReceiver(CheckerContext &C,
155                                             const ObjCMessageExpr *ME) {
156   HandleNilReceiver(C, C.getState(), ME);
157   return true; // Nil receiver is not handled elsewhere.
158 }
159
160 void CallAndMessageChecker::EmitNilReceiverBug(CheckerContext &C,
161                                                const ObjCMessageExpr *ME,
162                                                ExplodedNode *N) {
163   
164   if (!BT_msg_ret)
165     BT_msg_ret =
166       new BuiltinBug("Receiver in message expression is "
167                      "'nil' and returns a garbage value");
168   
169   llvm::SmallString<200> buf;
170   llvm::raw_svector_ostream os(buf);
171   os << "The receiver of message '" << ME->getSelector().getAsString()
172      << "' is nil and returns a value of type '"
173      << ME->getType().getAsString() << "' that will be garbage";
174   
175   EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
176   const Expr *receiver = ME->getReceiver();
177   report->addRange(receiver->getSourceRange());
178   report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, 
179                             receiver);
180   C.EmitReport(report);  
181 }
182
183 static bool SupportsNilWithFloatRet(const llvm::Triple &triple) {
184   return triple.getVendor() == llvm::Triple::Apple &&
185          triple.getDarwinMajorNumber() >= 9;
186 }
187
188 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
189                                               const GRState *state,
190                                               const ObjCMessageExpr *ME) {
191   
192   // Check the return type of the message expression.  A message to nil will
193   // return different values depending on the return type and the architecture.
194   QualType RetTy = ME->getType();
195   
196   ASTContext &Ctx = C.getASTContext();
197   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
198
199   if (CanRetTy->isStructureType()) {
200     // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
201     // have the "use of undefined value" be smarter about where the
202     // undefined value came from.
203     if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
204       if (ExplodedNode* N = C.GenerateSink(state))
205         EmitNilReceiverBug(C, ME, N);
206       return;
207     }
208
209     // The result is not consumed by a surrounding expression.  Just propagate
210     // the current state.
211     C.addTransition(state);
212     return;
213   }
214
215   // Other cases: check if the return type is smaller than void*.
216   if (CanRetTy != Ctx.VoidTy &&
217       C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
218     // Compute: sizeof(void *) and sizeof(return type)
219     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);    
220     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
221
222     if (voidPtrSize < returnTypeSize &&
223         !(SupportsNilWithFloatRet(Ctx.Target.getTriple()) &&
224           (Ctx.FloatTy == CanRetTy ||
225            Ctx.DoubleTy == CanRetTy ||
226            Ctx.LongDoubleTy == CanRetTy ||
227            Ctx.LongLongTy == CanRetTy))) {
228       if (ExplodedNode* N = C.GenerateSink(state))
229         EmitNilReceiverBug(C, ME, N);
230       return;
231     }
232
233     // Handle the safe cases where the return value is 0 if the
234     // receiver is nil.
235     //
236     // FIXME: For now take the conservative approach that we only
237     // return null values if we *know* that the receiver is nil.
238     // This is because we can have surprises like:
239     //
240     //   ... = [[NSScreens screens] objectAtIndex:0];
241     //
242     // What can happen is that [... screens] could return nil, but
243     // it most likely isn't nil.  We should assume the semantics
244     // of this case unless we have *a lot* more knowledge.
245     //
246     SVal V = C.getValueManager().makeZeroVal(ME->getType());
247     C.GenerateNode(state->BindExpr(ME, V));
248     return;
249   }
250   
251   C.addTransition(state);
252 }