/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //= CStringChecker.cpp - Checks calls to C string functions --------*- C++ -*-// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This defines CStringChecker, which is an assortment of checks on calls |
10 | | // to functions in <string.h>. |
11 | | // |
12 | | //===----------------------------------------------------------------------===// |
13 | | |
14 | | #include "InterCheckerAPI.h" |
15 | | #include "clang/Basic/CharInfo.h" |
16 | | #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" |
17 | | #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" |
18 | | #include "clang/StaticAnalyzer/Core/Checker.h" |
19 | | #include "clang/StaticAnalyzer/Core/CheckerManager.h" |
20 | | #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" |
21 | | #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" |
22 | | #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicSize.h" |
23 | | #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" |
24 | | #include "llvm/ADT/STLExtras.h" |
25 | | #include "llvm/ADT/SmallString.h" |
26 | | #include "llvm/ADT/StringExtras.h" |
27 | | #include "llvm/Support/raw_ostream.h" |
28 | | |
29 | | using namespace clang; |
30 | | using namespace ento; |
31 | | |
32 | | namespace { |
33 | | struct AnyArgExpr { |
34 | | // FIXME: Remove constructor in C++17 to turn it into an aggregate. |
35 | | AnyArgExpr(const Expr *Expression, unsigned ArgumentIndex) |
36 | 4.71k | : Expression{Expression}, ArgumentIndex{ArgumentIndex} {} |
37 | | const Expr *Expression; |
38 | | unsigned ArgumentIndex; |
39 | | }; |
40 | | |
41 | | struct SourceArgExpr : AnyArgExpr { |
42 | | using AnyArgExpr::AnyArgExpr; // FIXME: Remove using in C++17. |
43 | | }; |
44 | | |
45 | | struct DestinationArgExpr : AnyArgExpr { |
46 | | using AnyArgExpr::AnyArgExpr; // FIXME: Same. |
47 | | }; |
48 | | |
49 | | struct SizeArgExpr : AnyArgExpr { |
50 | | using AnyArgExpr::AnyArgExpr; // FIXME: Same. |
51 | | }; |
52 | | |
53 | | using ErrorMessage = SmallString<128>; |
54 | | enum class AccessKind { write, read }; |
55 | | |
56 | | static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription, |
57 | 125 | AccessKind Access) { |
58 | 125 | ErrorMessage Message; |
59 | 125 | llvm::raw_svector_ostream Os(Message); |
60 | | |
61 | | // Function classification like: Memory copy function |
62 | 125 | Os << toUppercase(FunctionDescription.front()) |
63 | 125 | << &FunctionDescription.data()[1]; |
64 | | |
65 | 125 | if (Access == AccessKind::write) { |
66 | 93 | Os << " overflows the destination buffer"; |
67 | 32 | } else { // read access |
68 | 32 | Os << " accesses out-of-bound array element"; |
69 | 32 | } |
70 | | |
71 | 125 | return Message; |
72 | 125 | } |
73 | | |
74 | | enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 }; |
75 | | class CStringChecker : public Checker< eval::Call, |
76 | | check::PreStmt<DeclStmt>, |
77 | | check::LiveSymbols, |
78 | | check::DeadSymbols, |
79 | | check::RegionChanges |
80 | | > { |
81 | | mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap, |
82 | | BT_NotCString, BT_AdditionOverflow; |
83 | | |
84 | | mutable const char *CurrentFunctionDescription; |
85 | | |
86 | | public: |
87 | | /// The filter is used to filter out the diagnostics which are not enabled by |
88 | | /// the user. |
89 | | struct CStringChecksFilter { |
90 | | DefaultBool CheckCStringNullArg; |
91 | | DefaultBool CheckCStringOutOfBounds; |
92 | | DefaultBool CheckCStringBufferOverlap; |
93 | | DefaultBool CheckCStringNotNullTerm; |
94 | | |
95 | | CheckerNameRef CheckNameCStringNullArg; |
96 | | CheckerNameRef CheckNameCStringOutOfBounds; |
97 | | CheckerNameRef CheckNameCStringBufferOverlap; |
98 | | CheckerNameRef CheckNameCStringNotNullTerm; |
99 | | }; |
100 | | |
101 | | CStringChecksFilter Filter; |
102 | | |
103 | 617 | static void *getTag() { static int tag; return &tag; } |
104 | | |
105 | | bool evalCall(const CallEvent &Call, CheckerContext &C) const; |
106 | | void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; |
107 | | void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const; |
108 | | void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; |
109 | | |
110 | | ProgramStateRef |
111 | | checkRegionChanges(ProgramStateRef state, |
112 | | const InvalidatedSymbols *, |
113 | | ArrayRef<const MemRegion *> ExplicitRegions, |
114 | | ArrayRef<const MemRegion *> Regions, |
115 | | const LocationContext *LCtx, |
116 | | const CallEvent *Call) const; |
117 | | |
118 | | typedef void (CStringChecker::*FnCheck)(CheckerContext &, |
119 | | const CallExpr *) const; |
120 | | CallDescriptionMap<FnCheck> Callbacks = { |
121 | | {{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy}, |
122 | | {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy}, |
123 | | {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp}, |
124 | | {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove}, |
125 | | {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset}, |
126 | | {{CDF_MaybeBuiltin, "explicit_memset", 3}, &CStringChecker::evalMemset}, |
127 | | {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy}, |
128 | | {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy}, |
129 | | {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy}, |
130 | | {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy}, |
131 | | {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat}, |
132 | | {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat}, |
133 | | {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat}, |
134 | | {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength}, |
135 | | {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength}, |
136 | | {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp}, |
137 | | {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp}, |
138 | | {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp}, |
139 | | {{CDF_MaybeBuiltin, "strncasecmp", 3}, &CStringChecker::evalStrncasecmp}, |
140 | | {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep}, |
141 | | {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy}, |
142 | | {{CDF_MaybeBuiltin, "bcmp", 3}, &CStringChecker::evalMemcmp}, |
143 | | {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero}, |
144 | | {{CDF_MaybeBuiltin, "explicit_bzero", 2}, &CStringChecker::evalBzero}, |
145 | | }; |
146 | | |
147 | | // These require a bit of special handling. |
148 | | CallDescription StdCopy{{"std", "copy"}, 3}, |
149 | | StdCopyBackward{{"std", "copy_backward"}, 3}; |
150 | | |
151 | | FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const; |
152 | | void evalMemcpy(CheckerContext &C, const CallExpr *CE) const; |
153 | | void evalMempcpy(CheckerContext &C, const CallExpr *CE) const; |
154 | | void evalMemmove(CheckerContext &C, const CallExpr *CE) const; |
155 | | void evalBcopy(CheckerContext &C, const CallExpr *CE) const; |
156 | | void evalCopyCommon(CheckerContext &C, const CallExpr *CE, |
157 | | ProgramStateRef state, SizeArgExpr Size, |
158 | | DestinationArgExpr Dest, SourceArgExpr Source, |
159 | | bool Restricted, bool IsMempcpy) const; |
160 | | |
161 | | void evalMemcmp(CheckerContext &C, const CallExpr *CE) const; |
162 | | |
163 | | void evalstrLength(CheckerContext &C, const CallExpr *CE) const; |
164 | | void evalstrnLength(CheckerContext &C, const CallExpr *CE) const; |
165 | | void evalstrLengthCommon(CheckerContext &C, |
166 | | const CallExpr *CE, |
167 | | bool IsStrnlen = false) const; |
168 | | |
169 | | void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; |
170 | | void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; |
171 | | void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; |
172 | | void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const; |
173 | | void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd, |
174 | | bool IsBounded, ConcatFnKind appendK, |
175 | | bool returnPtr = true) const; |
176 | | |
177 | | void evalStrcat(CheckerContext &C, const CallExpr *CE) const; |
178 | | void evalStrncat(CheckerContext &C, const CallExpr *CE) const; |
179 | | void evalStrlcat(CheckerContext &C, const CallExpr *CE) const; |
180 | | |
181 | | void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; |
182 | | void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; |
183 | | void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; |
184 | | void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; |
185 | | void evalStrcmpCommon(CheckerContext &C, |
186 | | const CallExpr *CE, |
187 | | bool IsBounded = false, |
188 | | bool IgnoreCase = false) const; |
189 | | |
190 | | void evalStrsep(CheckerContext &C, const CallExpr *CE) const; |
191 | | |
192 | | void evalStdCopy(CheckerContext &C, const CallExpr *CE) const; |
193 | | void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const; |
194 | | void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const; |
195 | | void evalMemset(CheckerContext &C, const CallExpr *CE) const; |
196 | | void evalBzero(CheckerContext &C, const CallExpr *CE) const; |
197 | | |
198 | | // Utility methods |
199 | | std::pair<ProgramStateRef , ProgramStateRef > |
200 | | static assumeZero(CheckerContext &C, |
201 | | ProgramStateRef state, SVal V, QualType Ty); |
202 | | |
203 | | static ProgramStateRef setCStringLength(ProgramStateRef state, |
204 | | const MemRegion *MR, |
205 | | SVal strLength); |
206 | | static SVal getCStringLengthForRegion(CheckerContext &C, |
207 | | ProgramStateRef &state, |
208 | | const Expr *Ex, |
209 | | const MemRegion *MR, |
210 | | bool hypothetical); |
211 | | SVal getCStringLength(CheckerContext &C, |
212 | | ProgramStateRef &state, |
213 | | const Expr *Ex, |
214 | | SVal Buf, |
215 | | bool hypothetical = false) const; |
216 | | |
217 | | const StringLiteral *getCStringLiteral(CheckerContext &C, |
218 | | ProgramStateRef &state, |
219 | | const Expr *expr, |
220 | | SVal val) const; |
221 | | |
222 | | static ProgramStateRef InvalidateBuffer(CheckerContext &C, |
223 | | ProgramStateRef state, |
224 | | const Expr *Ex, SVal V, |
225 | | bool IsSourceBuffer, |
226 | | const Expr *Size); |
227 | | |
228 | | static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, |
229 | | const MemRegion *MR); |
230 | | |
231 | | static bool memsetAux(const Expr *DstBuffer, SVal CharE, |
232 | | const Expr *Size, CheckerContext &C, |
233 | | ProgramStateRef &State); |
234 | | |
235 | | // Re-usable checks |
236 | | ProgramStateRef checkNonNull(CheckerContext &C, ProgramStateRef State, |
237 | | AnyArgExpr Arg, SVal l) const; |
238 | | ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state, |
239 | | AnyArgExpr Buffer, SVal Element, |
240 | | AccessKind Access) const; |
241 | | ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State, |
242 | | AnyArgExpr Buffer, SizeArgExpr Size, |
243 | | AccessKind Access) const; |
244 | | ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state, |
245 | | SizeArgExpr Size, AnyArgExpr First, |
246 | | AnyArgExpr Second) const; |
247 | | void emitOverlapBug(CheckerContext &C, |
248 | | ProgramStateRef state, |
249 | | const Stmt *First, |
250 | | const Stmt *Second) const; |
251 | | |
252 | | void emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, |
253 | | StringRef WarningMsg) const; |
254 | | void emitOutOfBoundsBug(CheckerContext &C, ProgramStateRef State, |
255 | | const Stmt *S, StringRef WarningMsg) const; |
256 | | void emitNotCStringBug(CheckerContext &C, ProgramStateRef State, |
257 | | const Stmt *S, StringRef WarningMsg) const; |
258 | | void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const; |
259 | | |
260 | | ProgramStateRef checkAdditionOverflow(CheckerContext &C, |
261 | | ProgramStateRef state, |
262 | | NonLoc left, |
263 | | NonLoc right) const; |
264 | | |
265 | | // Return true if the destination buffer of the copy function may be in bound. |
266 | | // Expects SVal of Size to be positive and unsigned. |
267 | | // Expects SVal of FirstBuf to be a FieldRegion. |
268 | | static bool IsFirstBufInBound(CheckerContext &C, |
269 | | ProgramStateRef state, |
270 | | const Expr *FirstBuf, |
271 | | const Expr *Size); |
272 | | }; |
273 | | |
274 | | } //end anonymous namespace |
275 | | |
276 | | REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal) |
277 | | |
278 | | //===----------------------------------------------------------------------===// |
279 | | // Individual checks and utility methods. |
280 | | //===----------------------------------------------------------------------===// |
281 | | |
282 | | std::pair<ProgramStateRef , ProgramStateRef > |
283 | | CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V, |
284 | 4.58k | QualType Ty) { |
285 | 4.58k | Optional<DefinedSVal> val = V.getAs<DefinedSVal>(); |
286 | 4.58k | if (!val) |
287 | 11 | return std::pair<ProgramStateRef , ProgramStateRef >(state, state); |
288 | | |
289 | 4.57k | SValBuilder &svalBuilder = C.getSValBuilder(); |
290 | 4.57k | DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty); |
291 | 4.57k | return state->assume(svalBuilder.evalEQ(state, *val, zero)); |
292 | 4.58k | } |
293 | | |
294 | | ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, |
295 | | ProgramStateRef State, |
296 | 3.67k | AnyArgExpr Arg, SVal l) const { |
297 | | // If a previous check has failed, propagate the failure. |
298 | 3.67k | if (!State) |
299 | 0 | return nullptr; |
300 | | |
301 | 3.67k | ProgramStateRef stateNull, stateNonNull; |
302 | 3.67k | std::tie(stateNull, stateNonNull) = |
303 | 3.67k | assumeZero(C, State, l, Arg.Expression->getType()); |
304 | | |
305 | 3.67k | if (stateNull && !stateNonNull572 ) { |
306 | 169 | if (Filter.CheckCStringNullArg) { |
307 | 169 | SmallString<80> buf; |
308 | 169 | llvm::raw_svector_ostream OS(buf); |
309 | 169 | assert(CurrentFunctionDescription); |
310 | 0 | OS << "Null pointer passed as " << (Arg.ArgumentIndex + 1) |
311 | 169 | << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) << " argument to " |
312 | 169 | << CurrentFunctionDescription; |
313 | | |
314 | 169 | emitNullArgBug(C, stateNull, Arg.Expression, OS.str()); |
315 | 169 | } |
316 | 0 | return nullptr; |
317 | 169 | } |
318 | | |
319 | | // From here on, assume that the value is non-null. |
320 | 3.51k | assert(stateNonNull); |
321 | 0 | return stateNonNull; |
322 | 3.67k | } |
323 | | |
324 | | // FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor? |
325 | | ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, |
326 | | ProgramStateRef state, |
327 | | AnyArgExpr Buffer, SVal Element, |
328 | 778 | AccessKind Access) const { |
329 | | |
330 | | // If a previous check has failed, propagate the failure. |
331 | 778 | if (!state) |
332 | 0 | return nullptr; |
333 | | |
334 | | // Check for out of bound array element access. |
335 | 778 | const MemRegion *R = Element.getAsRegion(); |
336 | 778 | if (!R) |
337 | 0 | return state; |
338 | | |
339 | 778 | const auto *ER = dyn_cast<ElementRegion>(R); |
340 | 778 | if (!ER) |
341 | 0 | return state; |
342 | | |
343 | 778 | if (ER->getValueType() != C.getASTContext().CharTy) |
344 | 1 | return state; |
345 | | |
346 | | // Get the size of the array. |
347 | 777 | const auto *superReg = cast<SubRegion>(ER->getSuperRegion()); |
348 | 777 | DefinedOrUnknownSVal Size = |
349 | 777 | getDynamicSize(state, superReg, C.getSValBuilder()); |
350 | | |
351 | | // Get the index of the accessed element. |
352 | 777 | DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); |
353 | | |
354 | 777 | ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true); |
355 | 777 | ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false); |
356 | 777 | if (StOutBound && !StInBound268 ) { |
357 | | // These checks are either enabled by the CString out-of-bounds checker |
358 | | // explicitly or implicitly by the Malloc checker. |
359 | | // In the latter case we only do modeling but do not emit warning. |
360 | 150 | if (!Filter.CheckCStringOutOfBounds) |
361 | 25 | return nullptr; |
362 | | |
363 | | // Emit a bug report. |
364 | 125 | ErrorMessage Message = |
365 | 125 | createOutOfBoundErrorMsg(CurrentFunctionDescription, Access); |
366 | 125 | emitOutOfBoundsBug(C, StOutBound, Buffer.Expression, Message); |
367 | 125 | return nullptr; |
368 | 150 | } |
369 | | |
370 | | // Array bound check succeeded. From this point forward the array bound |
371 | | // should always succeed. |
372 | 627 | return StInBound; |
373 | 777 | } |
374 | | |
375 | | ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, |
376 | | ProgramStateRef State, |
377 | | AnyArgExpr Buffer, |
378 | | SizeArgExpr Size, |
379 | 668 | AccessKind Access) const { |
380 | | // If a previous check has failed, propagate the failure. |
381 | 668 | if (!State) |
382 | 36 | return nullptr; |
383 | | |
384 | 632 | SValBuilder &svalBuilder = C.getSValBuilder(); |
385 | 632 | ASTContext &Ctx = svalBuilder.getContext(); |
386 | | |
387 | 632 | QualType SizeTy = Size.Expression->getType(); |
388 | 632 | QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); |
389 | | |
390 | | // Check that the first buffer is non-null. |
391 | 632 | SVal BufVal = C.getSVal(Buffer.Expression); |
392 | 632 | State = checkNonNull(C, State, Buffer, BufVal); |
393 | 632 | if (!State) |
394 | 4 | return nullptr; |
395 | | |
396 | | // If out-of-bounds checking is turned off, skip the rest. |
397 | 628 | if (!Filter.CheckCStringOutOfBounds) |
398 | 156 | return State; |
399 | | |
400 | | // Get the access length and make sure it is known. |
401 | | // FIXME: This assumes the caller has already checked that the access length |
402 | | // is positive. And that it's unsigned. |
403 | 472 | SVal LengthVal = C.getSVal(Size.Expression); |
404 | 472 | Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); |
405 | 472 | if (!Length) |
406 | 8 | return State; |
407 | | |
408 | | // Compute the offset of the last element to be accessed: size-1. |
409 | 464 | NonLoc One = svalBuilder.makeIntVal(1, SizeTy).castAs<NonLoc>(); |
410 | 464 | SVal Offset = svalBuilder.evalBinOpNN(State, BO_Sub, *Length, One, SizeTy); |
411 | 464 | if (Offset.isUnknown()) |
412 | 4 | return nullptr; |
413 | 460 | NonLoc LastOffset = Offset.castAs<NonLoc>(); |
414 | | |
415 | | // Check that the first buffer is sufficiently long. |
416 | 460 | SVal BufStart = |
417 | 460 | svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType()); |
418 | 460 | if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { |
419 | | |
420 | 456 | SVal BufEnd = |
421 | 456 | svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy); |
422 | | |
423 | 456 | State = CheckLocation(C, State, Buffer, BufEnd, Access); |
424 | | |
425 | | // If the buffer isn't large enough, abort. |
426 | 456 | if (!State) |
427 | 62 | return nullptr; |
428 | 456 | } |
429 | | |
430 | | // Large enough or not, return this state! |
431 | 398 | return State; |
432 | 460 | } |
433 | | |
434 | | ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, |
435 | | ProgramStateRef state, |
436 | | SizeArgExpr Size, AnyArgExpr First, |
437 | 524 | AnyArgExpr Second) const { |
438 | 524 | if (!Filter.CheckCStringBufferOverlap) |
439 | 173 | return state; |
440 | | |
441 | | // Do a simple check for overlap: if the two arguments are from the same |
442 | | // buffer, see if the end of the first is greater than the start of the second |
443 | | // or vice versa. |
444 | | |
445 | | // If a previous check has failed, propagate the failure. |
446 | 351 | if (!state) |
447 | 36 | return nullptr; |
448 | | |
449 | 315 | ProgramStateRef stateTrue, stateFalse; |
450 | | |
451 | | // Get the buffer values and make sure they're known locations. |
452 | 315 | const LocationContext *LCtx = C.getLocationContext(); |
453 | 315 | SVal firstVal = state->getSVal(First.Expression, LCtx); |
454 | 315 | SVal secondVal = state->getSVal(Second.Expression, LCtx); |
455 | | |
456 | 315 | Optional<Loc> firstLoc = firstVal.getAs<Loc>(); |
457 | 315 | if (!firstLoc) |
458 | 0 | return state; |
459 | | |
460 | 315 | Optional<Loc> secondLoc = secondVal.getAs<Loc>(); |
461 | 315 | if (!secondLoc) |
462 | 1 | return state; |
463 | | |
464 | | // Are the two values the same? |
465 | 314 | SValBuilder &svalBuilder = C.getSValBuilder(); |
466 | 314 | std::tie(stateTrue, stateFalse) = |
467 | 314 | state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc)); |
468 | | |
469 | 314 | if (stateTrue && !stateFalse49 ) { |
470 | | // If the values are known to be equal, that's automatically an overlap. |
471 | 8 | emitOverlapBug(C, stateTrue, First.Expression, Second.Expression); |
472 | 8 | return nullptr; |
473 | 8 | } |
474 | | |
475 | | // assume the two expressions are not equal. |
476 | 306 | assert(stateFalse); |
477 | 0 | state = stateFalse; |
478 | | |
479 | | // Which value comes first? |
480 | 306 | QualType cmpTy = svalBuilder.getConditionType(); |
481 | 306 | SVal reverse = |
482 | 306 | svalBuilder.evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy); |
483 | 306 | Optional<DefinedOrUnknownSVal> reverseTest = |
484 | 306 | reverse.getAs<DefinedOrUnknownSVal>(); |
485 | 306 | if (!reverseTest) |
486 | 0 | return state; |
487 | | |
488 | 306 | std::tie(stateTrue, stateFalse) = state->assume(*reverseTest); |
489 | 306 | if (stateTrue) { |
490 | 289 | if (stateFalse) { |
491 | | // If we don't know which one comes first, we can't perform this test. |
492 | 273 | return state; |
493 | 16 | } else { |
494 | | // Switch the values so that firstVal is before secondVal. |
495 | 16 | std::swap(firstLoc, secondLoc); |
496 | | |
497 | | // Switch the Exprs as well, so that they still correspond. |
498 | 16 | std::swap(First, Second); |
499 | 16 | } |
500 | 289 | } |
501 | | |
502 | | // Get the length, and make sure it too is known. |
503 | 33 | SVal LengthVal = state->getSVal(Size.Expression, LCtx); |
504 | 33 | Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); |
505 | 33 | if (!Length) |
506 | 0 | return state; |
507 | | |
508 | | // Convert the first buffer's start address to char*. |
509 | | // Bail out if the cast fails. |
510 | 33 | ASTContext &Ctx = svalBuilder.getContext(); |
511 | 33 | QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); |
512 | 33 | SVal FirstStart = |
513 | 33 | svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType()); |
514 | 33 | Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>(); |
515 | 33 | if (!FirstStartLoc) |
516 | 0 | return state; |
517 | | |
518 | | // Compute the end of the first buffer. Bail out if THAT fails. |
519 | 33 | SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, *FirstStartLoc, |
520 | 33 | *Length, CharPtrTy); |
521 | 33 | Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>(); |
522 | 33 | if (!FirstEndLoc) |
523 | 0 | return state; |
524 | | |
525 | | // Is the end of the first buffer past the start of the second buffer? |
526 | 33 | SVal Overlap = |
527 | 33 | svalBuilder.evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy); |
528 | 33 | Optional<DefinedOrUnknownSVal> OverlapTest = |
529 | 33 | Overlap.getAs<DefinedOrUnknownSVal>(); |
530 | 33 | if (!OverlapTest) |
531 | 0 | return state; |
532 | | |
533 | 33 | std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest); |
534 | | |
535 | 33 | if (stateTrue && !stateFalse17 ) { |
536 | | // Overlap! |
537 | 17 | emitOverlapBug(C, stateTrue, First.Expression, Second.Expression); |
538 | 17 | return nullptr; |
539 | 17 | } |
540 | | |
541 | | // assume the two expressions don't overlap. |
542 | 16 | assert(stateFalse); |
543 | 0 | return stateFalse; |
544 | 33 | } |
545 | | |
546 | | void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, |
547 | 25 | const Stmt *First, const Stmt *Second) const { |
548 | 25 | ExplodedNode *N = C.generateErrorNode(state); |
549 | 25 | if (!N) |
550 | 0 | return; |
551 | | |
552 | 25 | if (!BT_Overlap) |
553 | 5 | BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap, |
554 | 5 | categories::UnixAPI, "Improper arguments")); |
555 | | |
556 | | // Generate a report for this bug. |
557 | 25 | auto report = std::make_unique<PathSensitiveBugReport>( |
558 | 25 | *BT_Overlap, "Arguments must not be overlapping buffers", N); |
559 | 25 | report->addRange(First->getSourceRange()); |
560 | 25 | report->addRange(Second->getSourceRange()); |
561 | | |
562 | 25 | C.emitReport(std::move(report)); |
563 | 25 | } |
564 | | |
565 | | void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State, |
566 | 169 | const Stmt *S, StringRef WarningMsg) const { |
567 | 169 | if (ExplodedNode *N = C.generateErrorNode(State)) { |
568 | 169 | if (!BT_Null) |
569 | 14 | BT_Null.reset(new BuiltinBug( |
570 | 14 | Filter.CheckNameCStringNullArg, categories::UnixAPI, |
571 | 14 | "Null pointer argument in call to byte string function")); |
572 | | |
573 | 169 | BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get()); |
574 | 169 | auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); |
575 | 169 | Report->addRange(S->getSourceRange()); |
576 | 169 | if (const auto *Ex = dyn_cast<Expr>(S)) |
577 | 169 | bugreporter::trackExpressionValue(N, Ex, *Report); |
578 | 169 | C.emitReport(std::move(Report)); |
579 | 169 | } |
580 | 169 | } |
581 | | |
582 | | void CStringChecker::emitOutOfBoundsBug(CheckerContext &C, |
583 | | ProgramStateRef State, const Stmt *S, |
584 | 125 | StringRef WarningMsg) const { |
585 | 125 | if (ExplodedNode *N = C.generateErrorNode(State)) { |
586 | 125 | if (!BT_Bounds) |
587 | 10 | BT_Bounds.reset(new BuiltinBug( |
588 | 10 | Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds |
589 | 0 | : Filter.CheckNameCStringNullArg, |
590 | 10 | "Out-of-bound array access", |
591 | 10 | "Byte string function accesses out-of-bound array element")); |
592 | | |
593 | 125 | BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Bounds.get()); |
594 | | |
595 | | // FIXME: It would be nice to eventually make this diagnostic more clear, |
596 | | // e.g., by referencing the original declaration or by saying *why* this |
597 | | // reference is outside the range. |
598 | 125 | auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); |
599 | 125 | Report->addRange(S->getSourceRange()); |
600 | 125 | C.emitReport(std::move(Report)); |
601 | 125 | } |
602 | 125 | } |
603 | | |
604 | | void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State, |
605 | | const Stmt *S, |
606 | 46 | StringRef WarningMsg) const { |
607 | 46 | if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { |
608 | 46 | if (!BT_NotCString) |
609 | 6 | BT_NotCString.reset(new BuiltinBug( |
610 | 6 | Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, |
611 | 6 | "Argument is not a null-terminated string.")); |
612 | | |
613 | 46 | auto Report = |
614 | 46 | std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); |
615 | | |
616 | 46 | Report->addRange(S->getSourceRange()); |
617 | 46 | C.emitReport(std::move(Report)); |
618 | 46 | } |
619 | 46 | } |
620 | | |
621 | | void CStringChecker::emitAdditionOverflowBug(CheckerContext &C, |
622 | 0 | ProgramStateRef State) const { |
623 | 0 | if (ExplodedNode *N = C.generateErrorNode(State)) { |
624 | 0 | if (!BT_NotCString) |
625 | 0 | BT_NotCString.reset( |
626 | 0 | new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API", |
627 | 0 | "Sum of expressions causes overflow.")); |
628 | | |
629 | | // This isn't a great error message, but this should never occur in real |
630 | | // code anyway -- you'd have to create a buffer longer than a size_t can |
631 | | // represent, which is sort of a contradiction. |
632 | 0 | const char *WarningMsg = |
633 | 0 | "This expression will create a string whose length is too big to " |
634 | 0 | "be represented as a size_t"; |
635 | |
|
636 | 0 | auto Report = |
637 | 0 | std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); |
638 | 0 | C.emitReport(std::move(Report)); |
639 | 0 | } |
640 | 0 | } |
641 | | |
642 | | ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, |
643 | | ProgramStateRef state, |
644 | | NonLoc left, |
645 | 116 | NonLoc right) const { |
646 | | // If out-of-bounds checking is turned off, skip the rest. |
647 | 116 | if (!Filter.CheckCStringOutOfBounds) |
648 | 39 | return state; |
649 | | |
650 | | // If a previous check has failed, propagate the failure. |
651 | 77 | if (!state) |
652 | 0 | return nullptr; |
653 | | |
654 | 77 | SValBuilder &svalBuilder = C.getSValBuilder(); |
655 | 77 | BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); |
656 | | |
657 | 77 | QualType sizeTy = svalBuilder.getContext().getSizeType(); |
658 | 77 | const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); |
659 | 77 | NonLoc maxVal = svalBuilder.makeIntVal(maxValInt); |
660 | | |
661 | 77 | SVal maxMinusRight; |
662 | 77 | if (right.getAs<nonloc::ConcreteInt>()) { |
663 | 65 | maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right, |
664 | 65 | sizeTy); |
665 | 12 | } else { |
666 | | // Try switching the operands. (The order of these two assignments is |
667 | | // important!) |
668 | 12 | maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left, |
669 | 12 | sizeTy); |
670 | 12 | left = right; |
671 | 12 | } |
672 | | |
673 | 77 | if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) { |
674 | 77 | QualType cmpTy = svalBuilder.getConditionType(); |
675 | | // If left > max - right, we have an overflow. |
676 | 77 | SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left, |
677 | 77 | *maxMinusRightNL, cmpTy); |
678 | | |
679 | 77 | ProgramStateRef stateOverflow, stateOkay; |
680 | 77 | std::tie(stateOverflow, stateOkay) = |
681 | 77 | state->assume(willOverflow.castAs<DefinedOrUnknownSVal>()); |
682 | | |
683 | 77 | if (stateOverflow && !stateOkay0 ) { |
684 | | // We have an overflow. Emit a bug report. |
685 | 0 | emitAdditionOverflowBug(C, stateOverflow); |
686 | 0 | return nullptr; |
687 | 0 | } |
688 | | |
689 | | // From now on, assume an overflow didn't occur. |
690 | 77 | assert(stateOkay); |
691 | 0 | state = stateOkay; |
692 | 77 | } |
693 | | |
694 | 77 | return state; |
695 | 77 | } |
696 | | |
697 | | ProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state, |
698 | | const MemRegion *MR, |
699 | 385 | SVal strLength) { |
700 | 385 | assert(!strLength.isUndef() && "Attempt to set an undefined string length"); |
701 | | |
702 | 0 | MR = MR->StripCasts(); |
703 | | |
704 | 385 | switch (MR->getKind()) { |
705 | 0 | case MemRegion::StringRegionKind: |
706 | | // FIXME: This can happen if we strcpy() into a string region. This is |
707 | | // undefined [C99 6.4.5p6], but we should still warn about it. |
708 | 0 | return state; |
709 | | |
710 | 99 | case MemRegion::SymbolicRegionKind: |
711 | 99 | case MemRegion::AllocaRegionKind: |
712 | 379 | case MemRegion::NonParamVarRegionKind: |
713 | 379 | case MemRegion::ParamVarRegionKind: |
714 | 381 | case MemRegion::FieldRegionKind: |
715 | 381 | case MemRegion::ObjCIvarRegionKind: |
716 | | // These are the types we can currently track string lengths for. |
717 | 381 | break; |
718 | | |
719 | 4 | case MemRegion::ElementRegionKind: |
720 | | // FIXME: Handle element regions by upper-bounding the parent region's |
721 | | // string length. |
722 | 4 | return state; |
723 | | |
724 | 0 | default: |
725 | | // Other regions (mostly non-data) can't have a reliable C string length. |
726 | | // For now, just ignore the change. |
727 | | // FIXME: These are rare but not impossible. We should output some kind of |
728 | | // warning for things like strcpy((char[]){'a', 0}, "b"); |
729 | 0 | return state; |
730 | 385 | } |
731 | | |
732 | 381 | if (strLength.isUnknown()) |
733 | 51 | return state->remove<CStringLength>(MR); |
734 | | |
735 | 330 | return state->set<CStringLength>(MR, strLength); |
736 | 381 | } |
737 | | |
738 | | SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, |
739 | | ProgramStateRef &state, |
740 | | const Expr *Ex, |
741 | | const MemRegion *MR, |
742 | 1.22k | bool hypothetical) { |
743 | 1.22k | if (!hypothetical) { |
744 | | // If there's a recorded length, go ahead and return it. |
745 | 1.17k | const SVal *Recorded = state->get<CStringLength>(MR); |
746 | 1.17k | if (Recorded) |
747 | 661 | return *Recorded; |
748 | 1.17k | } |
749 | | |
750 | | // Otherwise, get a new symbol and update the state. |
751 | 568 | SValBuilder &svalBuilder = C.getSValBuilder(); |
752 | 568 | QualType sizeTy = svalBuilder.getContext().getSizeType(); |
753 | 568 | SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), |
754 | 568 | MR, Ex, sizeTy, |
755 | 568 | C.getLocationContext(), |
756 | 568 | C.blockCount()); |
757 | | |
758 | 568 | if (!hypothetical) { |
759 | 516 | if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) { |
760 | | // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4 |
761 | 516 | BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); |
762 | 516 | const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); |
763 | 516 | llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4); |
764 | 516 | const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt, |
765 | 516 | fourInt); |
766 | 516 | NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt); |
767 | 516 | SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, |
768 | 516 | maxLength, sizeTy); |
769 | 516 | state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true); |
770 | 516 | } |
771 | 516 | state = state->set<CStringLength>(MR, strLength); |
772 | 516 | } |
773 | | |
774 | 568 | return strLength; |
775 | 1.22k | } |
776 | | |
777 | | SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, |
778 | | const Expr *Ex, SVal Buf, |
779 | 2.40k | bool hypothetical) const { |
780 | 2.40k | const MemRegion *MR = Buf.getAsRegion(); |
781 | 2.40k | if (!MR) { |
782 | | // If we can't get a region, see if it's something we /know/ isn't a |
783 | | // C string. In the context of locations, the only time we can issue such |
784 | | // a warning is for labels. |
785 | 16 | if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) { |
786 | 10 | if (Filter.CheckCStringNotNullTerm) { |
787 | 10 | SmallString<120> buf; |
788 | 10 | llvm::raw_svector_ostream os(buf); |
789 | 10 | assert(CurrentFunctionDescription); |
790 | 0 | os << "Argument to " << CurrentFunctionDescription |
791 | 10 | << " is the address of the label '" << Label->getLabel()->getName() |
792 | 10 | << "', which is not a null-terminated string"; |
793 | | |
794 | 10 | emitNotCStringBug(C, state, Ex, os.str()); |
795 | 10 | } |
796 | 0 | return UndefinedVal(); |
797 | 10 | } |
798 | | |
799 | | // If it's not a region and not a label, give up. |
800 | 6 | return UnknownVal(); |
801 | 16 | } |
802 | | |
803 | | // If we have a region, strip casts from it and see if we can figure out |
804 | | // its length. For anything we can't figure out, just return UnknownVal. |
805 | 2.38k | MR = MR->StripCasts(); |
806 | | |
807 | 2.38k | switch (MR->getKind()) { |
808 | 1.08k | case MemRegion::StringRegionKind: { |
809 | | // Modifying the contents of string regions is undefined [C99 6.4.5p6], |
810 | | // so we can assume that the byte length is the correct C string length. |
811 | 1.08k | SValBuilder &svalBuilder = C.getSValBuilder(); |
812 | 1.08k | QualType sizeTy = svalBuilder.getContext().getSizeType(); |
813 | 1.08k | const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral(); |
814 | 1.08k | return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy); |
815 | 0 | } |
816 | 621 | case MemRegion::SymbolicRegionKind: |
817 | 621 | case MemRegion::AllocaRegionKind: |
818 | 1.20k | case MemRegion::NonParamVarRegionKind: |
819 | 1.20k | case MemRegion::ParamVarRegionKind: |
820 | 1.22k | case MemRegion::FieldRegionKind: |
821 | 1.22k | case MemRegion::ObjCIvarRegionKind: |
822 | 1.22k | return getCStringLengthForRegion(C, state, Ex, MR, hypothetical); |
823 | 5 | case MemRegion::CompoundLiteralRegionKind: |
824 | | // FIXME: Can we track this? Is it necessary? |
825 | 5 | return UnknownVal(); |
826 | 31 | case MemRegion::ElementRegionKind: |
827 | | // FIXME: How can we handle this? It's not good enough to subtract the |
828 | | // offset from the base string length; consider "123\x00567" and &a[5]. |
829 | 31 | return UnknownVal(); |
830 | 36 | default: |
831 | | // Other regions (mostly non-data) can't have a reliable C string length. |
832 | | // In this case, an error is emitted and UndefinedVal is returned. |
833 | | // The caller should always be prepared to handle this case. |
834 | 36 | if (Filter.CheckCStringNotNullTerm) { |
835 | 36 | SmallString<120> buf; |
836 | 36 | llvm::raw_svector_ostream os(buf); |
837 | | |
838 | 36 | assert(CurrentFunctionDescription); |
839 | 0 | os << "Argument to " << CurrentFunctionDescription << " is "; |
840 | | |
841 | 36 | if (SummarizeRegion(os, C.getASTContext(), MR)) |
842 | 36 | os << ", which is not a null-terminated string"; |
843 | 0 | else |
844 | 0 | os << "not a null-terminated string"; |
845 | | |
846 | 36 | emitNotCStringBug(C, state, Ex, os.str()); |
847 | 36 | } |
848 | 0 | return UndefinedVal(); |
849 | 2.38k | } |
850 | 2.38k | } |
851 | | |
852 | | const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, |
853 | 752 | ProgramStateRef &state, const Expr *expr, SVal val) const { |
854 | | |
855 | | // Get the memory region pointed to by the val. |
856 | 752 | const MemRegion *bufRegion = val.getAsRegion(); |
857 | 752 | if (!bufRegion) |
858 | 5 | return nullptr; |
859 | | |
860 | | // Strip casts off the memory region. |
861 | 747 | bufRegion = bufRegion->StripCasts(); |
862 | | |
863 | | // Cast the memory region to a string region. |
864 | 747 | const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion); |
865 | 747 | if (!strRegion) |
866 | 2 | return nullptr; |
867 | | |
868 | | // Return the actual string in the string region. |
869 | 745 | return strRegion->getStringLiteral(); |
870 | 747 | } |
871 | | |
872 | | bool CStringChecker::IsFirstBufInBound(CheckerContext &C, |
873 | | ProgramStateRef state, |
874 | | const Expr *FirstBuf, |
875 | 42 | const Expr *Size) { |
876 | | // If we do not know that the buffer is long enough we return 'true'. |
877 | | // Otherwise the parent region of this field region would also get |
878 | | // invalidated, which would lead to warnings based on an unknown state. |
879 | | |
880 | | // Originally copied from CheckBufferAccess and CheckLocation. |
881 | 42 | SValBuilder &svalBuilder = C.getSValBuilder(); |
882 | 42 | ASTContext &Ctx = svalBuilder.getContext(); |
883 | 42 | const LocationContext *LCtx = C.getLocationContext(); |
884 | | |
885 | 42 | QualType sizeTy = Size->getType(); |
886 | 42 | QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); |
887 | 42 | SVal BufVal = state->getSVal(FirstBuf, LCtx); |
888 | | |
889 | 42 | SVal LengthVal = state->getSVal(Size, LCtx); |
890 | 42 | Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); |
891 | 42 | if (!Length) |
892 | 1 | return true; // cf top comment. |
893 | | |
894 | | // Compute the offset of the last element to be accessed: size-1. |
895 | 41 | NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); |
896 | 41 | SVal Offset = svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy); |
897 | 41 | if (Offset.isUnknown()) |
898 | 0 | return true; // cf top comment |
899 | 41 | NonLoc LastOffset = Offset.castAs<NonLoc>(); |
900 | | |
901 | | // Check that the first buffer is sufficiently long. |
902 | 41 | SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); |
903 | 41 | Optional<Loc> BufLoc = BufStart.getAs<Loc>(); |
904 | 41 | if (!BufLoc) |
905 | 1 | return true; // cf top comment. |
906 | | |
907 | 40 | SVal BufEnd = |
908 | 40 | svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, LastOffset, PtrTy); |
909 | | |
910 | | // Check for out of bound array element access. |
911 | 40 | const MemRegion *R = BufEnd.getAsRegion(); |
912 | 40 | if (!R) |
913 | 0 | return true; // cf top comment. |
914 | | |
915 | 40 | const ElementRegion *ER = dyn_cast<ElementRegion>(R); |
916 | 40 | if (!ER) |
917 | 0 | return true; // cf top comment. |
918 | | |
919 | | // FIXME: Does this crash when a non-standard definition |
920 | | // of a library function is encountered? |
921 | 40 | assert(ER->getValueType() == C.getASTContext().CharTy && |
922 | 40 | "IsFirstBufInBound should only be called with char* ElementRegions"); |
923 | | |
924 | | // Get the size of the array. |
925 | 0 | const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); |
926 | 40 | DefinedOrUnknownSVal SizeDV = getDynamicSize(state, superReg, svalBuilder); |
927 | | |
928 | | // Get the index of the accessed element. |
929 | 40 | DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); |
930 | | |
931 | 40 | ProgramStateRef StInBound = state->assumeInBound(Idx, SizeDV, true); |
932 | | |
933 | 40 | return static_cast<bool>(StInBound); |
934 | 40 | } |
935 | | |
936 | | ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, |
937 | | ProgramStateRef state, |
938 | | const Expr *E, SVal V, |
939 | | bool IsSourceBuffer, |
940 | 859 | const Expr *Size) { |
941 | 859 | Optional<Loc> L = V.getAs<Loc>(); |
942 | 859 | if (!L) |
943 | 0 | return state; |
944 | | |
945 | | // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes |
946 | | // some assumptions about the value that CFRefCount can't. Even so, it should |
947 | | // probably be refactored. |
948 | 859 | if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) { |
949 | 853 | const MemRegion *R = MR->getRegion()->StripCasts(); |
950 | | |
951 | | // Are we dealing with an ElementRegion? If so, we should be invalidating |
952 | | // the super-region. |
953 | 853 | if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { |
954 | 97 | R = ER->getSuperRegion(); |
955 | | // FIXME: What about layers of ElementRegions? |
956 | 97 | } |
957 | | |
958 | | // Invalidate this region. |
959 | 853 | const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); |
960 | | |
961 | 853 | bool CausesPointerEscape = false; |
962 | 853 | RegionAndSymbolInvalidationTraits ITraits; |
963 | | // Invalidate and escape only indirect regions accessible through the source |
964 | | // buffer. |
965 | 853 | if (IsSourceBuffer) { |
966 | 374 | ITraits.setTrait(R->getBaseRegion(), |
967 | 374 | RegionAndSymbolInvalidationTraits::TK_PreserveContents); |
968 | 374 | ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); |
969 | 374 | CausesPointerEscape = true; |
970 | 479 | } else { |
971 | 479 | const MemRegion::Kind& K = R->getKind(); |
972 | 479 | if (K == MemRegion::FieldRegionKind) |
973 | 42 | if (Size && IsFirstBufInBound(C, state, E, Size)) { |
974 | | // If destination buffer is a field region and access is in bound, |
975 | | // do not invalidate its super region. |
976 | 35 | ITraits.setTrait( |
977 | 35 | R, |
978 | 35 | RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); |
979 | 35 | } |
980 | 479 | } |
981 | | |
982 | 853 | return state->invalidateRegions(R, E, C.blockCount(), LCtx, |
983 | 853 | CausesPointerEscape, nullptr, nullptr, |
984 | 853 | &ITraits); |
985 | 853 | } |
986 | | |
987 | | // If we have a non-region value by chance, just remove the binding. |
988 | | // FIXME: is this necessary or correct? This handles the non-Region |
989 | | // cases. Is it ever valid to store to these? |
990 | 6 | return state->killBinding(*L); |
991 | 859 | } |
992 | | |
993 | | bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, |
994 | 36 | const MemRegion *MR) { |
995 | 36 | switch (MR->getKind()) { |
996 | 36 | case MemRegion::FunctionCodeRegionKind: { |
997 | 36 | if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl()) |
998 | 36 | os << "the address of the function '" << *FD << '\''; |
999 | 0 | else |
1000 | 0 | os << "the address of a function"; |
1001 | 36 | return true; |
1002 | 0 | } |
1003 | 0 | case MemRegion::BlockCodeRegionKind: |
1004 | 0 | os << "block text"; |
1005 | 0 | return true; |
1006 | 0 | case MemRegion::BlockDataRegionKind: |
1007 | 0 | os << "a block"; |
1008 | 0 | return true; |
1009 | 0 | case MemRegion::CXXThisRegionKind: |
1010 | 0 | case MemRegion::CXXTempObjectRegionKind: |
1011 | 0 | os << "a C++ temp object of type " |
1012 | 0 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); |
1013 | 0 | return true; |
1014 | 0 | case MemRegion::NonParamVarRegionKind: |
1015 | 0 | os << "a variable of type" |
1016 | 0 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); |
1017 | 0 | return true; |
1018 | 0 | case MemRegion::ParamVarRegionKind: |
1019 | 0 | os << "a parameter of type" |
1020 | 0 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); |
1021 | 0 | return true; |
1022 | 0 | case MemRegion::FieldRegionKind: |
1023 | 0 | os << "a field of type " |
1024 | 0 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); |
1025 | 0 | return true; |
1026 | 0 | case MemRegion::ObjCIvarRegionKind: |
1027 | 0 | os << "an instance variable of type " |
1028 | 0 | << cast<TypedValueRegion>(MR)->getValueType().getAsString(); |
1029 | 0 | return true; |
1030 | 0 | default: |
1031 | 0 | return false; |
1032 | 36 | } |
1033 | 36 | } |
1034 | | |
1035 | | bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, |
1036 | | const Expr *Size, CheckerContext &C, |
1037 | 172 | ProgramStateRef &State) { |
1038 | 172 | SVal MemVal = C.getSVal(DstBuffer); |
1039 | 172 | SVal SizeVal = C.getSVal(Size); |
1040 | 172 | const MemRegion *MR = MemVal.getAsRegion(); |
1041 | 172 | if (!MR) |
1042 | 0 | return false; |
1043 | | |
1044 | | // We're about to model memset by producing a "default binding" in the Store. |
1045 | | // Our current implementation - RegionStore - doesn't support default bindings |
1046 | | // that don't cover the whole base region. So we should first get the offset |
1047 | | // and the base region to figure out whether the offset of buffer is 0. |
1048 | 172 | RegionOffset Offset = MR->getAsOffset(); |
1049 | 172 | const MemRegion *BR = Offset.getRegion(); |
1050 | | |
1051 | 172 | Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>(); |
1052 | 172 | if (!SizeNL) |
1053 | 0 | return false; |
1054 | | |
1055 | 172 | SValBuilder &svalBuilder = C.getSValBuilder(); |
1056 | 172 | ASTContext &Ctx = C.getASTContext(); |
1057 | | |
1058 | | // void *memset(void *dest, int ch, size_t count); |
1059 | | // For now we can only handle the case of offset is 0 and concrete char value. |
1060 | 172 | if (Offset.isValid() && !Offset.hasSymbolicOffset() && |
1061 | 171 | Offset.getOffset() == 0) { |
1062 | | // Get the base region's size. |
1063 | 145 | DefinedOrUnknownSVal SizeDV = getDynamicSize(State, BR, svalBuilder); |
1064 | | |
1065 | 145 | ProgramStateRef StateWholeReg, StateNotWholeReg; |
1066 | 145 | std::tie(StateWholeReg, StateNotWholeReg) = |
1067 | 145 | State->assume(svalBuilder.evalEQ(State, SizeDV, *SizeNL)); |
1068 | | |
1069 | | // With the semantic of 'memset()', we should convert the CharVal to |
1070 | | // unsigned char. |
1071 | 145 | CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy); |
1072 | | |
1073 | 145 | ProgramStateRef StateNullChar, StateNonNullChar; |
1074 | 145 | std::tie(StateNullChar, StateNonNullChar) = |
1075 | 145 | assumeZero(C, State, CharVal, Ctx.UnsignedCharTy); |
1076 | | |
1077 | 145 | if (StateWholeReg && !StateNotWholeReg113 && StateNullChar113 && |
1078 | 91 | !StateNonNullChar) { |
1079 | | // If the 'memset()' acts on the whole region of destination buffer and |
1080 | | // the value of the second argument of 'memset()' is zero, bind the second |
1081 | | // argument's value to the destination buffer with 'default binding'. |
1082 | | // FIXME: Since there is no perfect way to bind the non-zero character, we |
1083 | | // can only deal with zero value here. In the future, we need to deal with |
1084 | | // the binding of non-zero value in the case of whole region. |
1085 | 91 | State = State->bindDefaultZero(svalBuilder.makeLoc(BR), |
1086 | 91 | C.getLocationContext()); |
1087 | 54 | } else { |
1088 | | // If the destination buffer's extent is not equal to the value of |
1089 | | // third argument, just invalidate buffer. |
1090 | 54 | State = InvalidateBuffer(C, State, DstBuffer, MemVal, |
1091 | 54 | /*IsSourceBuffer*/ false, Size); |
1092 | 54 | } |
1093 | | |
1094 | 145 | if (StateNullChar && !StateNonNullChar116 ) { |
1095 | | // If the value of the second argument of 'memset()' is zero, set the |
1096 | | // string length of destination buffer to 0 directly. |
1097 | 116 | State = setCStringLength(State, MR, |
1098 | 116 | svalBuilder.makeZeroVal(Ctx.getSizeType())); |
1099 | 29 | } else if (!StateNullChar && StateNonNullChar) { |
1100 | 29 | SVal NewStrLen = svalBuilder.getMetadataSymbolVal( |
1101 | 29 | CStringChecker::getTag(), MR, DstBuffer, Ctx.getSizeType(), |
1102 | 29 | C.getLocationContext(), C.blockCount()); |
1103 | | |
1104 | | // If the value of second argument is not zero, then the string length |
1105 | | // is at least the size argument. |
1106 | 29 | SVal NewStrLenGESize = svalBuilder.evalBinOp( |
1107 | 29 | State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType()); |
1108 | | |
1109 | 29 | State = setCStringLength( |
1110 | 29 | State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(), true), |
1111 | 29 | MR, NewStrLen); |
1112 | 29 | } |
1113 | 27 | } else { |
1114 | | // If the offset is not zero and char value is not concrete, we can do |
1115 | | // nothing but invalidate the buffer. |
1116 | 27 | State = InvalidateBuffer(C, State, DstBuffer, MemVal, |
1117 | 27 | /*IsSourceBuffer*/ false, Size); |
1118 | 27 | } |
1119 | 172 | return true; |
1120 | 172 | } |
1121 | | |
1122 | | //===----------------------------------------------------------------------===// |
1123 | | // evaluation of individual function calls. |
1124 | | //===----------------------------------------------------------------------===// |
1125 | | |
1126 | | void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE, |
1127 | | ProgramStateRef state, SizeArgExpr Size, |
1128 | | DestinationArgExpr Dest, |
1129 | | SourceArgExpr Source, bool Restricted, |
1130 | 256 | bool IsMempcpy) const { |
1131 | 256 | CurrentFunctionDescription = "memory copy function"; |
1132 | | |
1133 | | // See if the size argument is zero. |
1134 | 256 | const LocationContext *LCtx = C.getLocationContext(); |
1135 | 256 | SVal sizeVal = state->getSVal(Size.Expression, LCtx); |
1136 | 256 | QualType sizeTy = Size.Expression->getType(); |
1137 | | |
1138 | 256 | ProgramStateRef stateZeroSize, stateNonZeroSize; |
1139 | 256 | std::tie(stateZeroSize, stateNonZeroSize) = |
1140 | 256 | assumeZero(C, state, sizeVal, sizeTy); |
1141 | | |
1142 | | // Get the value of the Dest. |
1143 | 256 | SVal destVal = state->getSVal(Dest.Expression, LCtx); |
1144 | | |
1145 | | // If the size is zero, there won't be any actual memory access, so |
1146 | | // just bind the return value to the destination buffer and return. |
1147 | 256 | if (stateZeroSize && !stateNonZeroSize48 ) { |
1148 | 16 | stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal); |
1149 | 16 | C.addTransition(stateZeroSize); |
1150 | 16 | return; |
1151 | 16 | } |
1152 | | |
1153 | | // If the size can be nonzero, we have to check the other arguments. |
1154 | 240 | if (stateNonZeroSize) { |
1155 | 240 | state = stateNonZeroSize; |
1156 | | |
1157 | | // Ensure the destination is not null. If it is NULL there will be a |
1158 | | // NULL pointer dereference. |
1159 | 240 | state = checkNonNull(C, state, Dest, destVal); |
1160 | 240 | if (!state) |
1161 | 14 | return; |
1162 | | |
1163 | | // Get the value of the Src. |
1164 | 226 | SVal srcVal = state->getSVal(Source.Expression, LCtx); |
1165 | | |
1166 | | // Ensure the source is not null. If it is NULL there will be a |
1167 | | // NULL pointer dereference. |
1168 | 226 | state = checkNonNull(C, state, Source, srcVal); |
1169 | 226 | if (!state) |
1170 | 16 | return; |
1171 | | |
1172 | | // Ensure the accesses are valid and that the buffers do not overlap. |
1173 | 210 | state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write); |
1174 | 210 | state = CheckBufferAccess(C, state, Source, Size, AccessKind::read); |
1175 | | |
1176 | 210 | if (Restricted) |
1177 | 182 | state = CheckOverlap(C, state, Size, Dest, Source); |
1178 | | |
1179 | 210 | if (!state) |
1180 | 76 | return; |
1181 | | |
1182 | | // If this is mempcpy, get the byte after the last byte copied and |
1183 | | // bind the expr. |
1184 | 134 | if (IsMempcpy) { |
1185 | | // Get the byte after the last byte copied. |
1186 | 41 | SValBuilder &SvalBuilder = C.getSValBuilder(); |
1187 | 41 | ASTContext &Ctx = SvalBuilder.getContext(); |
1188 | 41 | QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); |
1189 | 41 | SVal DestRegCharVal = |
1190 | 41 | SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType()); |
1191 | 41 | SVal lastElement = C.getSValBuilder().evalBinOp( |
1192 | 41 | state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType()); |
1193 | | // If we don't know how much we copied, we can at least |
1194 | | // conjure a return value for later. |
1195 | 41 | if (lastElement.isUnknown()) |
1196 | 9 | lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, |
1197 | 9 | C.blockCount()); |
1198 | | |
1199 | | // The byte after the last byte copied is the return value. |
1200 | 41 | state = state->BindExpr(CE, LCtx, lastElement); |
1201 | 93 | } else { |
1202 | | // All other copies return the destination buffer. |
1203 | | // (Well, bcopy() has a void return type, but this won't hurt.) |
1204 | 93 | state = state->BindExpr(CE, LCtx, destVal); |
1205 | 93 | } |
1206 | | |
1207 | | // Invalidate the destination (regular invalidation without pointer-escaping |
1208 | | // the address of the top-level region). |
1209 | | // FIXME: Even if we can't perfectly model the copy, we should see if we |
1210 | | // can use LazyCompoundVals to copy the source values into the destination. |
1211 | | // This would probably remove any existing bindings past the end of the |
1212 | | // copied region, but that's still an improvement over blank invalidation. |
1213 | 134 | state = |
1214 | 134 | InvalidateBuffer(C, state, Dest.Expression, C.getSVal(Dest.Expression), |
1215 | 134 | /*IsSourceBuffer*/ false, Size.Expression); |
1216 | | |
1217 | | // Invalidate the source (const-invalidation without const-pointer-escaping |
1218 | | // the address of the top-level region). |
1219 | 134 | state = InvalidateBuffer(C, state, Source.Expression, |
1220 | 134 | C.getSVal(Source.Expression), |
1221 | 134 | /*IsSourceBuffer*/ true, nullptr); |
1222 | | |
1223 | 134 | C.addTransition(state); |
1224 | 134 | } |
1225 | 240 | } |
1226 | | |
1227 | 139 | void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { |
1228 | | // void *memcpy(void *restrict dst, const void *restrict src, size_t n); |
1229 | | // The return value is the address of the destination buffer. |
1230 | 139 | DestinationArgExpr Dest = {CE->getArg(0), 0}; |
1231 | 139 | SourceArgExpr Src = {CE->getArg(1), 1}; |
1232 | 139 | SizeArgExpr Size = {CE->getArg(2), 2}; |
1233 | | |
1234 | 139 | ProgramStateRef State = C.getState(); |
1235 | | |
1236 | 139 | constexpr bool IsRestricted = true; |
1237 | 139 | constexpr bool IsMempcpy = false; |
1238 | 139 | evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy); |
1239 | 139 | } |
1240 | | |
1241 | 89 | void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { |
1242 | | // void *mempcpy(void *restrict dst, const void *restrict src, size_t n); |
1243 | | // The return value is a pointer to the byte following the last written byte. |
1244 | 89 | DestinationArgExpr Dest = {CE->getArg(0), 0}; |
1245 | 89 | SourceArgExpr Src = {CE->getArg(1), 1}; |
1246 | 89 | SizeArgExpr Size = {CE->getArg(2), 2}; |
1247 | | |
1248 | 89 | constexpr bool IsRestricted = true; |
1249 | 89 | constexpr bool IsMempcpy = true; |
1250 | 89 | evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); |
1251 | 89 | } |
1252 | | |
1253 | 16 | void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { |
1254 | | // void *memmove(void *dst, const void *src, size_t n); |
1255 | | // The return value is the address of the destination buffer. |
1256 | 16 | DestinationArgExpr Dest = {CE->getArg(0), 0}; |
1257 | 16 | SourceArgExpr Src = {CE->getArg(1), 1}; |
1258 | 16 | SizeArgExpr Size = {CE->getArg(2), 2}; |
1259 | | |
1260 | 16 | constexpr bool IsRestricted = false; |
1261 | 16 | constexpr bool IsMempcpy = false; |
1262 | 16 | evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); |
1263 | 16 | } |
1264 | | |
1265 | 12 | void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { |
1266 | | // void bcopy(const void *src, void *dst, size_t n); |
1267 | 12 | SourceArgExpr Src(CE->getArg(0), 0); |
1268 | 12 | DestinationArgExpr Dest = {CE->getArg(1), 1}; |
1269 | 12 | SizeArgExpr Size = {CE->getArg(2), 2}; |
1270 | | |
1271 | 12 | constexpr bool IsRestricted = false; |
1272 | 12 | constexpr bool IsMempcpy = false; |
1273 | 12 | evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); |
1274 | 12 | } |
1275 | | |
1276 | 54 | void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { |
1277 | | // int memcmp(const void *s1, const void *s2, size_t n); |
1278 | 54 | CurrentFunctionDescription = "memory comparison function"; |
1279 | | |
1280 | 54 | AnyArgExpr Left = {CE->getArg(0), 0}; |
1281 | 54 | AnyArgExpr Right = {CE->getArg(1), 1}; |
1282 | 54 | SizeArgExpr Size = {CE->getArg(2), 2}; |
1283 | | |
1284 | 54 | ProgramStateRef State = C.getState(); |
1285 | 54 | SValBuilder &Builder = C.getSValBuilder(); |
1286 | 54 | const LocationContext *LCtx = C.getLocationContext(); |
1287 | | |
1288 | | // See if the size argument is zero. |
1289 | 54 | SVal sizeVal = State->getSVal(Size.Expression, LCtx); |
1290 | 54 | QualType sizeTy = Size.Expression->getType(); |
1291 | | |
1292 | 54 | ProgramStateRef stateZeroSize, stateNonZeroSize; |
1293 | 54 | std::tie(stateZeroSize, stateNonZeroSize) = |
1294 | 54 | assumeZero(C, State, sizeVal, sizeTy); |
1295 | | |
1296 | | // If the size can be zero, the result will be 0 in that case, and we don't |
1297 | | // have to check either of the buffers. |
1298 | 54 | if (stateZeroSize) { |
1299 | 28 | State = stateZeroSize; |
1300 | 28 | State = State->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType())); |
1301 | 28 | C.addTransition(State); |
1302 | 28 | } |
1303 | | |
1304 | | // If the size can be nonzero, we have to check the other arguments. |
1305 | 54 | if (stateNonZeroSize) { |
1306 | 38 | State = stateNonZeroSize; |
1307 | | // If we know the two buffers are the same, we know the result is 0. |
1308 | | // First, get the two buffers' addresses. Another checker will have already |
1309 | | // made sure they're not undefined. |
1310 | 38 | DefinedOrUnknownSVal LV = |
1311 | 38 | State->getSVal(Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>(); |
1312 | 38 | DefinedOrUnknownSVal RV = |
1313 | 38 | State->getSVal(Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>(); |
1314 | | |
1315 | | // See if they are the same. |
1316 | 38 | ProgramStateRef SameBuffer, NotSameBuffer; |
1317 | 38 | std::tie(SameBuffer, NotSameBuffer) = |
1318 | 38 | State->assume(Builder.evalEQ(State, LV, RV)); |
1319 | | |
1320 | | // If the two arguments are the same buffer, we know the result is 0, |
1321 | | // and we only need to check one size. |
1322 | 38 | if (SameBuffer && !NotSameBuffer22 ) { |
1323 | 6 | State = SameBuffer; |
1324 | 6 | State = CheckBufferAccess(C, State, Left, Size, AccessKind::read); |
1325 | 6 | if (State) { |
1326 | 6 | State = |
1327 | 6 | SameBuffer->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType())); |
1328 | 6 | C.addTransition(State); |
1329 | 6 | } |
1330 | 6 | return; |
1331 | 6 | } |
1332 | | |
1333 | | // If the two arguments might be different buffers, we have to check |
1334 | | // the size of both of them. |
1335 | 32 | assert(NotSameBuffer); |
1336 | 0 | State = CheckBufferAccess(C, State, Right, Size, AccessKind::read); |
1337 | 32 | State = CheckBufferAccess(C, State, Left, Size, AccessKind::read); |
1338 | 32 | if (State) { |
1339 | | // The return value is the comparison result, which we don't know. |
1340 | 20 | SVal CmpV = Builder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); |
1341 | 20 | State = State->BindExpr(CE, LCtx, CmpV); |
1342 | 20 | C.addTransition(State); |
1343 | 20 | } |
1344 | 32 | } |
1345 | 54 | } |
1346 | | |
1347 | | void CStringChecker::evalstrLength(CheckerContext &C, |
1348 | 578 | const CallExpr *CE) const { |
1349 | | // size_t strlen(const char *s); |
1350 | 578 | evalstrLengthCommon(C, CE, /* IsStrnlen = */ false); |
1351 | 578 | } |
1352 | | |
1353 | | void CStringChecker::evalstrnLength(CheckerContext &C, |
1354 | 108 | const CallExpr *CE) const { |
1355 | | // size_t strnlen(const char *s, size_t maxlen); |
1356 | 108 | evalstrLengthCommon(C, CE, /* IsStrnlen = */ true); |
1357 | 108 | } |
1358 | | |
1359 | | void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, |
1360 | 686 | bool IsStrnlen) const { |
1361 | 686 | CurrentFunctionDescription = "string length function"; |
1362 | 686 | ProgramStateRef state = C.getState(); |
1363 | 686 | const LocationContext *LCtx = C.getLocationContext(); |
1364 | | |
1365 | 686 | if (IsStrnlen) { |
1366 | 108 | const Expr *maxlenExpr = CE->getArg(1); |
1367 | 108 | SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); |
1368 | | |
1369 | 108 | ProgramStateRef stateZeroSize, stateNonZeroSize; |
1370 | 108 | std::tie(stateZeroSize, stateNonZeroSize) = |
1371 | 108 | assumeZero(C, state, maxlenVal, maxlenExpr->getType()); |
1372 | | |
1373 | | // If the size can be zero, the result will be 0 in that case, and we don't |
1374 | | // have to check the string itself. |
1375 | 108 | if (stateZeroSize) { |
1376 | 20 | SVal zero = C.getSValBuilder().makeZeroVal(CE->getType()); |
1377 | 20 | stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero); |
1378 | 20 | C.addTransition(stateZeroSize); |
1379 | 20 | } |
1380 | | |
1381 | | // If the size is GUARANTEED to be zero, we're done! |
1382 | 108 | if (!stateNonZeroSize) |
1383 | 10 | return; |
1384 | | |
1385 | | // Otherwise, record the assumption that the size is nonzero. |
1386 | 98 | state = stateNonZeroSize; |
1387 | 98 | } |
1388 | | |
1389 | | // Check that the string argument is non-null. |
1390 | 676 | AnyArgExpr Arg = {CE->getArg(0), 0}; |
1391 | 676 | SVal ArgVal = state->getSVal(Arg.Expression, LCtx); |
1392 | 676 | state = checkNonNull(C, state, Arg, ArgVal); |
1393 | | |
1394 | 676 | if (!state) |
1395 | 10 | return; |
1396 | | |
1397 | 666 | SVal strLength = getCStringLength(C, state, Arg.Expression, ArgVal); |
1398 | | |
1399 | | // If the argument isn't a valid C string, there's no valid state to |
1400 | | // transition to. |
1401 | 666 | if (strLength.isUndef()) |
1402 | 21 | return; |
1403 | | |
1404 | 645 | DefinedOrUnknownSVal result = UnknownVal(); |
1405 | | |
1406 | | // If the check is for strnlen() then bind the return value to no more than |
1407 | | // the maxlen value. |
1408 | 645 | if (IsStrnlen) { |
1409 | 83 | QualType cmpTy = C.getSValBuilder().getConditionType(); |
1410 | | |
1411 | | // It's a little unfortunate to be getting this again, |
1412 | | // but it's not that expensive... |
1413 | 83 | const Expr *maxlenExpr = CE->getArg(1); |
1414 | 83 | SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); |
1415 | | |
1416 | 83 | Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); |
1417 | 83 | Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>(); |
1418 | | |
1419 | 83 | if (strLengthNL && maxlenValNL78 ) { |
1420 | 73 | ProgramStateRef stateStringTooLong, stateStringNotTooLong; |
1421 | | |
1422 | | // Check if the strLength is greater than the maxlen. |
1423 | 73 | std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume( |
1424 | 73 | C.getSValBuilder() |
1425 | 73 | .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy) |
1426 | 73 | .castAs<DefinedOrUnknownSVal>()); |
1427 | | |
1428 | 73 | if (stateStringTooLong && !stateStringNotTooLong58 ) { |
1429 | | // If the string is longer than maxlen, return maxlen. |
1430 | 15 | result = *maxlenValNL; |
1431 | 58 | } else if (stateStringNotTooLong && !stateStringTooLong) { |
1432 | | // If the string is shorter than maxlen, return its length. |
1433 | 15 | result = *strLengthNL; |
1434 | 15 | } |
1435 | 73 | } |
1436 | | |
1437 | 83 | if (result.isUnknown()) { |
1438 | | // If we don't have enough information for a comparison, there's |
1439 | | // no guarantee the full string length will actually be returned. |
1440 | | // All we know is the return value is the min of the string length |
1441 | | // and the limit. This is better than nothing. |
1442 | 53 | result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, |
1443 | 53 | C.blockCount()); |
1444 | 53 | NonLoc resultNL = result.castAs<NonLoc>(); |
1445 | | |
1446 | 53 | if (strLengthNL) { |
1447 | 48 | state = state->assume(C.getSValBuilder().evalBinOpNN( |
1448 | 48 | state, BO_LE, resultNL, *strLengthNL, cmpTy) |
1449 | 48 | .castAs<DefinedOrUnknownSVal>(), true); |
1450 | 48 | } |
1451 | | |
1452 | 53 | if (maxlenValNL) { |
1453 | 48 | state = state->assume(C.getSValBuilder().evalBinOpNN( |
1454 | 48 | state, BO_LE, resultNL, *maxlenValNL, cmpTy) |
1455 | 48 | .castAs<DefinedOrUnknownSVal>(), true); |
1456 | 48 | } |
1457 | 53 | } |
1458 | | |
1459 | 562 | } else { |
1460 | | // This is a plain strlen(), not strnlen(). |
1461 | 562 | result = strLength.castAs<DefinedOrUnknownSVal>(); |
1462 | | |
1463 | | // If we don't know the length of the string, conjure a return |
1464 | | // value, so it can be used in constraints, at least. |
1465 | 562 | if (result.isUnknown()) { |
1466 | 2 | result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, |
1467 | 2 | C.blockCount()); |
1468 | 2 | } |
1469 | 562 | } |
1470 | | |
1471 | | // Bind the return value. |
1472 | 645 | assert(!result.isUnknown() && "Should have conjured a value by now"); |
1473 | 0 | state = state->BindExpr(CE, LCtx, result); |
1474 | 645 | C.addTransition(state); |
1475 | 645 | } |
1476 | | |
1477 | 48 | void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { |
1478 | | // char *strcpy(char *restrict dst, const char *restrict src); |
1479 | 48 | evalStrcpyCommon(C, CE, |
1480 | 48 | /* ReturnEnd = */ false, |
1481 | 48 | /* IsBounded = */ false, |
1482 | 48 | /* appendK = */ ConcatFnKind::none); |
1483 | 48 | } |
1484 | | |
1485 | 67 | void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { |
1486 | | // char *strncpy(char *restrict dst, const char *restrict src, size_t n); |
1487 | 67 | evalStrcpyCommon(C, CE, |
1488 | 67 | /* ReturnEnd = */ false, |
1489 | 67 | /* IsBounded = */ true, |
1490 | 67 | /* appendK = */ ConcatFnKind::none); |
1491 | 67 | } |
1492 | | |
1493 | 14 | void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const { |
1494 | | // char *stpcpy(char *restrict dst, const char *restrict src); |
1495 | 14 | evalStrcpyCommon(C, CE, |
1496 | 14 | /* ReturnEnd = */ true, |
1497 | 14 | /* IsBounded = */ false, |
1498 | 14 | /* appendK = */ ConcatFnKind::none); |
1499 | 14 | } |
1500 | | |
1501 | 75 | void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const { |
1502 | | // size_t strlcpy(char *dest, const char *src, size_t size); |
1503 | 75 | evalStrcpyCommon(C, CE, |
1504 | 75 | /* ReturnEnd = */ true, |
1505 | 75 | /* IsBounded = */ true, |
1506 | 75 | /* appendK = */ ConcatFnKind::none, |
1507 | 75 | /* returnPtr = */ false); |
1508 | 75 | } |
1509 | | |
1510 | 57 | void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { |
1511 | | // char *strcat(char *restrict s1, const char *restrict s2); |
1512 | 57 | evalStrcpyCommon(C, CE, |
1513 | 57 | /* ReturnEnd = */ false, |
1514 | 57 | /* IsBounded = */ false, |
1515 | 57 | /* appendK = */ ConcatFnKind::strcat); |
1516 | 57 | } |
1517 | | |
1518 | 107 | void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const { |
1519 | | //char *strncat(char *restrict s1, const char *restrict s2, size_t n); |
1520 | 107 | evalStrcpyCommon(C, CE, |
1521 | 107 | /* ReturnEnd = */ false, |
1522 | 107 | /* IsBounded = */ true, |
1523 | 107 | /* appendK = */ ConcatFnKind::strcat); |
1524 | 107 | } |
1525 | | |
1526 | 42 | void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const { |
1527 | | // size_t strlcat(char *dst, const char *src, size_t size); |
1528 | | // It will append at most size - strlen(dst) - 1 bytes, |
1529 | | // NULL-terminating the result. |
1530 | 42 | evalStrcpyCommon(C, CE, |
1531 | 42 | /* ReturnEnd = */ false, |
1532 | 42 | /* IsBounded = */ true, |
1533 | 42 | /* appendK = */ ConcatFnKind::strlcat, |
1534 | 42 | /* returnPtr = */ false); |
1535 | 42 | } |
1536 | | |
1537 | | void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, |
1538 | | bool ReturnEnd, bool IsBounded, |
1539 | | ConcatFnKind appendK, |
1540 | 410 | bool returnPtr) const { |
1541 | 410 | if (appendK == ConcatFnKind::none) |
1542 | 204 | CurrentFunctionDescription = "string copy function"; |
1543 | 206 | else |
1544 | 206 | CurrentFunctionDescription = "string concatenation function"; |
1545 | | |
1546 | 410 | ProgramStateRef state = C.getState(); |
1547 | 410 | const LocationContext *LCtx = C.getLocationContext(); |
1548 | | |
1549 | | // Check that the destination is non-null. |
1550 | 410 | DestinationArgExpr Dst = {CE->getArg(0), 0}; |
1551 | 410 | SVal DstVal = state->getSVal(Dst.Expression, LCtx); |
1552 | 410 | state = checkNonNull(C, state, Dst, DstVal); |
1553 | 410 | if (!state) |
1554 | 23 | return; |
1555 | | |
1556 | | // Check that the source is non-null. |
1557 | 387 | SourceArgExpr srcExpr = {CE->getArg(1), 1}; |
1558 | 387 | SVal srcVal = state->getSVal(srcExpr.Expression, LCtx); |
1559 | 387 | state = checkNonNull(C, state, srcExpr, srcVal); |
1560 | 387 | if (!state) |
1561 | 20 | return; |
1562 | | |
1563 | | // Get the string length of the source. |
1564 | 367 | SVal strLength = getCStringLength(C, state, srcExpr.Expression, srcVal); |
1565 | 367 | Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); |
1566 | | |
1567 | | // Get the string length of the destination buffer. |
1568 | 367 | SVal dstStrLength = getCStringLength(C, state, Dst.Expression, DstVal); |
1569 | 367 | Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); |
1570 | | |
1571 | | // If the source isn't a valid C string, give up. |
1572 | 367 | if (strLength.isUndef()) |
1573 | 25 | return; |
1574 | | |
1575 | 342 | SValBuilder &svalBuilder = C.getSValBuilder(); |
1576 | 342 | QualType cmpTy = svalBuilder.getConditionType(); |
1577 | 342 | QualType sizeTy = svalBuilder.getContext().getSizeType(); |
1578 | | |
1579 | | // These two values allow checking two kinds of errors: |
1580 | | // - actual overflows caused by a source that doesn't fit in the destination |
1581 | | // - potential overflows caused by a bound that could exceed the destination |
1582 | 342 | SVal amountCopied = UnknownVal(); |
1583 | 342 | SVal maxLastElementIndex = UnknownVal(); |
1584 | 342 | const char *boundWarning = nullptr; |
1585 | | |
1586 | | // FIXME: Why do we choose the srcExpr if the access has no size? |
1587 | | // Note that the 3rd argument of the call would be the size parameter. |
1588 | 342 | SizeArgExpr SrcExprAsSizeDummy = {srcExpr.Expression, srcExpr.ArgumentIndex}; |
1589 | 342 | state = CheckOverlap( |
1590 | 342 | C, state, |
1591 | 342 | (IsBounded ? SizeArgExpr{CE->getArg(2), 2}259 : SrcExprAsSizeDummy83 ), Dst, |
1592 | 342 | srcExpr); |
1593 | | |
1594 | 342 | if (!state) |
1595 | 1 | return; |
1596 | | |
1597 | | // If the function is strncpy, strncat, etc... it is bounded. |
1598 | 341 | if (IsBounded) { |
1599 | | // Get the max number of characters to copy. |
1600 | 258 | SizeArgExpr lenExpr = {CE->getArg(2), 2}; |
1601 | 258 | SVal lenVal = state->getSVal(lenExpr.Expression, LCtx); |
1602 | | |
1603 | | // Protect against misdeclared strncpy(). |
1604 | 258 | lenVal = |
1605 | 258 | svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType()); |
1606 | | |
1607 | 258 | Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>(); |
1608 | | |
1609 | | // If we know both values, we might be able to figure out how much |
1610 | | // we're copying. |
1611 | 258 | if (strLengthNL && lenValNL248 ) { |
1612 | 235 | switch (appendK) { |
1613 | 121 | case ConcatFnKind::none: |
1614 | 200 | case ConcatFnKind::strcat: { |
1615 | 200 | ProgramStateRef stateSourceTooLong, stateSourceNotTooLong; |
1616 | | // Check if the max number to copy is less than the length of the src. |
1617 | | // If the bound is equal to the source length, strncpy won't null- |
1618 | | // terminate the result! |
1619 | 200 | std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( |
1620 | 200 | svalBuilder |
1621 | 200 | .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) |
1622 | 200 | .castAs<DefinedOrUnknownSVal>()); |
1623 | | |
1624 | 200 | if (stateSourceTooLong && !stateSourceNotTooLong153 ) { |
1625 | | // Max number to copy is less than the length of the src, so the |
1626 | | // actual strLength copied is the max number arg. |
1627 | 83 | state = stateSourceTooLong; |
1628 | 83 | amountCopied = lenVal; |
1629 | | |
1630 | 117 | } else if (!stateSourceTooLong && stateSourceNotTooLong47 ) { |
1631 | | // The source buffer entirely fits in the bound. |
1632 | 47 | state = stateSourceNotTooLong; |
1633 | 47 | amountCopied = strLength; |
1634 | 47 | } |
1635 | 200 | break; |
1636 | 121 | } |
1637 | 35 | case ConcatFnKind::strlcat: |
1638 | 35 | if (!dstStrLengthNL) |
1639 | 4 | return; |
1640 | | |
1641 | | // amountCopied = min (size - dstLen - 1 , srcLen) |
1642 | 31 | SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, |
1643 | 31 | *dstStrLengthNL, sizeTy); |
1644 | 31 | if (!freeSpace.getAs<NonLoc>()) |
1645 | 0 | return; |
1646 | 31 | freeSpace = |
1647 | 31 | svalBuilder.evalBinOp(state, BO_Sub, freeSpace, |
1648 | 31 | svalBuilder.makeIntVal(1, sizeTy), sizeTy); |
1649 | 31 | Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>(); |
1650 | | |
1651 | | // While unlikely, it is possible that the subtraction is |
1652 | | // too complex to compute, let's check whether it succeeded. |
1653 | 31 | if (!freeSpaceNL) |
1654 | 0 | return; |
1655 | 31 | SVal hasEnoughSpace = svalBuilder.evalBinOpNN( |
1656 | 31 | state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy); |
1657 | | |
1658 | 31 | ProgramStateRef TrueState, FalseState; |
1659 | 31 | std::tie(TrueState, FalseState) = |
1660 | 31 | state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>()); |
1661 | | |
1662 | | // srcStrLength <= size - dstStrLength -1 |
1663 | 31 | if (TrueState && !FalseState23 ) { |
1664 | 14 | amountCopied = strLength; |
1665 | 14 | } |
1666 | | |
1667 | | // srcStrLength > size - dstStrLength -1 |
1668 | 31 | if (!TrueState && FalseState8 ) { |
1669 | 8 | amountCopied = freeSpace; |
1670 | 8 | } |
1671 | | |
1672 | 31 | if (TrueState && FalseState23 ) |
1673 | 9 | amountCopied = UnknownVal(); |
1674 | 31 | break; |
1675 | 235 | } |
1676 | 235 | } |
1677 | | // We still want to know if the bound is known to be too large. |
1678 | 254 | if (lenValNL) { |
1679 | 241 | switch (appendK) { |
1680 | 87 | case ConcatFnKind::strcat: |
1681 | | // For strncat, the check is strlen(dst) + lenVal < sizeof(dst) |
1682 | | |
1683 | | // Get the string length of the destination. If the destination is |
1684 | | // memory that can't have a string length, we shouldn't be copying |
1685 | | // into it anyway. |
1686 | 87 | if (dstStrLength.isUndef()) |
1687 | 0 | return; |
1688 | | |
1689 | 87 | if (dstStrLengthNL) { |
1690 | 87 | maxLastElementIndex = svalBuilder.evalBinOpNN( |
1691 | 87 | state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy); |
1692 | | |
1693 | 87 | boundWarning = "Size argument is greater than the free space in the " |
1694 | 87 | "destination buffer"; |
1695 | 87 | } |
1696 | 87 | break; |
1697 | 121 | case ConcatFnKind::none: |
1698 | 154 | case ConcatFnKind::strlcat: |
1699 | | // For strncpy and strlcat, this is just checking |
1700 | | // that lenVal <= sizeof(dst). |
1701 | | // (Yes, strncpy and strncat differ in how they treat termination. |
1702 | | // strncat ALWAYS terminates, but strncpy doesn't.) |
1703 | | |
1704 | | // We need a special case for when the copy size is zero, in which |
1705 | | // case strncpy will do no work at all. Our bounds check uses n-1 |
1706 | | // as the last element accessed, so n == 0 is problematic. |
1707 | 154 | ProgramStateRef StateZeroSize, StateNonZeroSize; |
1708 | 154 | std::tie(StateZeroSize, StateNonZeroSize) = |
1709 | 154 | assumeZero(C, state, *lenValNL, sizeTy); |
1710 | | |
1711 | | // If the size is known to be zero, we're done. |
1712 | 154 | if (StateZeroSize && !StateNonZeroSize14 ) { |
1713 | 9 | if (returnPtr) { |
1714 | 5 | StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal); |
1715 | 4 | } else { |
1716 | 4 | if (appendK == ConcatFnKind::none) { |
1717 | | // strlcpy returns strlen(src) |
1718 | 2 | StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength); |
1719 | 2 | } else { |
1720 | | // strlcat returns strlen(src) + strlen(dst) |
1721 | 2 | SVal retSize = svalBuilder.evalBinOp( |
1722 | 2 | state, BO_Add, strLength, dstStrLength, sizeTy); |
1723 | 2 | StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize); |
1724 | 2 | } |
1725 | 4 | } |
1726 | 9 | C.addTransition(StateZeroSize); |
1727 | 9 | return; |
1728 | 9 | } |
1729 | | |
1730 | | // Otherwise, go ahead and figure out the last element we'll touch. |
1731 | | // We don't record the non-zero assumption here because we can't |
1732 | | // be sure. We won't warn on a possible zero. |
1733 | 145 | NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); |
1734 | 145 | maxLastElementIndex = |
1735 | 145 | svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy); |
1736 | 145 | boundWarning = "Size argument is greater than the length of the " |
1737 | 145 | "destination buffer"; |
1738 | 145 | break; |
1739 | 241 | } |
1740 | 241 | } |
1741 | 83 | } else { |
1742 | | // The function isn't bounded. The amount copied should match the length |
1743 | | // of the source buffer. |
1744 | 83 | amountCopied = strLength; |
1745 | 83 | } |
1746 | | |
1747 | 328 | assert(state); |
1748 | | |
1749 | | // This represents the number of characters copied into the destination |
1750 | | // buffer. (It may not actually be the strlen if the destination buffer |
1751 | | // is not terminated.) |
1752 | 0 | SVal finalStrLength = UnknownVal(); |
1753 | 328 | SVal strlRetVal = UnknownVal(); |
1754 | | |
1755 | 328 | if (appendK == ConcatFnKind::none && !returnPtr159 ) { |
1756 | | // strlcpy returns the sizeof(src) |
1757 | 71 | strlRetVal = strLength; |
1758 | 71 | } |
1759 | | |
1760 | | // If this is an appending function (strcat, strncat...) then set the |
1761 | | // string length to strlen(src) + strlen(dst) since the buffer will |
1762 | | // ultimately contain both. |
1763 | 328 | if (appendK != ConcatFnKind::none) { |
1764 | | // Get the string length of the destination. If the destination is memory |
1765 | | // that can't have a string length, we shouldn't be copying into it anyway. |
1766 | 169 | if (dstStrLength.isUndef()) |
1767 | 0 | return; |
1768 | | |
1769 | 169 | if (appendK == ConcatFnKind::strlcat && dstStrLengthNL35 && strLengthNL34 ) { |
1770 | 34 | strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL, |
1771 | 34 | *dstStrLengthNL, sizeTy); |
1772 | 34 | } |
1773 | | |
1774 | 169 | Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>(); |
1775 | | |
1776 | | // If we know both string lengths, we might know the final string length. |
1777 | 169 | if (amountCopiedNL && dstStrLengthNL116 ) { |
1778 | | // Make sure the two lengths together don't overflow a size_t. |
1779 | 116 | state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL); |
1780 | 116 | if (!state) |
1781 | 0 | return; |
1782 | | |
1783 | 116 | finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL, |
1784 | 116 | *dstStrLengthNL, sizeTy); |
1785 | 116 | } |
1786 | | |
1787 | | // If we couldn't get a single value for the final string length, |
1788 | | // we can at least bound it by the individual lengths. |
1789 | 169 | if (finalStrLength.isUnknown()) { |
1790 | | // Try to get a "hypothetical" string length symbol, which we can later |
1791 | | // set as a real value if that turns out to be the case. |
1792 | 53 | finalStrLength = getCStringLength(C, state, CE, DstVal, true); |
1793 | 53 | assert(!finalStrLength.isUndef()); |
1794 | | |
1795 | 53 | if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) { |
1796 | 52 | if (amountCopiedNL && appendK == ConcatFnKind::none0 ) { |
1797 | | // we overwrite dst string with the src |
1798 | | // finalStrLength >= srcStrLength |
1799 | 0 | SVal sourceInResult = svalBuilder.evalBinOpNN( |
1800 | 0 | state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy); |
1801 | 0 | state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(), |
1802 | 0 | true); |
1803 | 0 | if (!state) |
1804 | 0 | return; |
1805 | 0 | } |
1806 | | |
1807 | 52 | if (dstStrLengthNL && appendK != ConcatFnKind::none) { |
1808 | | // we extend the dst string with the src |
1809 | | // finalStrLength >= dstStrLength |
1810 | 52 | SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE, |
1811 | 52 | *finalStrLengthNL, |
1812 | 52 | *dstStrLengthNL, |
1813 | 52 | cmpTy); |
1814 | 52 | state = |
1815 | 52 | state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true); |
1816 | 52 | if (!state) |
1817 | 0 | return; |
1818 | 52 | } |
1819 | 52 | } |
1820 | 53 | } |
1821 | | |
1822 | 159 | } else { |
1823 | | // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and |
1824 | | // the final string length will match the input string length. |
1825 | 159 | finalStrLength = amountCopied; |
1826 | 159 | } |
1827 | | |
1828 | 328 | SVal Result; |
1829 | | |
1830 | 328 | if (returnPtr) { |
1831 | | // The final result of the function will either be a pointer past the last |
1832 | | // copied element, or a pointer to the start of the destination buffer. |
1833 | 222 | Result = (ReturnEnd ? UnknownVal()14 : DstVal208 ); |
1834 | 106 | } else { |
1835 | 106 | if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none71 ) |
1836 | | //strlcpy, strlcat |
1837 | 106 | Result = strlRetVal; |
1838 | 0 | else |
1839 | 0 | Result = finalStrLength; |
1840 | 106 | } |
1841 | | |
1842 | 328 | assert(state); |
1843 | | |
1844 | | // If the destination is a MemRegion, try to check for a buffer overflow and |
1845 | | // record the new string length. |
1846 | 328 | if (Optional<loc::MemRegionVal> dstRegVal = |
1847 | 328 | DstVal.getAs<loc::MemRegionVal>()) { |
1848 | 328 | QualType ptrTy = Dst.Expression->getType(); |
1849 | | |
1850 | | // If we have an exact value on a bounded copy, use that to check for |
1851 | | // overflows, rather than our estimate about how much is actually copied. |
1852 | 328 | if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) { |
1853 | 230 | SVal maxLastElement = |
1854 | 230 | svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy); |
1855 | | |
1856 | 230 | state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write); |
1857 | 230 | if (!state) |
1858 | 68 | return; |
1859 | 230 | } |
1860 | | |
1861 | | // Then, if the final length is known... |
1862 | 260 | if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) { |
1863 | 219 | SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, |
1864 | 219 | *knownStrLength, ptrTy); |
1865 | | |
1866 | | // ...and we haven't checked the bound, we'll check the actual copy. |
1867 | 219 | if (!boundWarning) { |
1868 | 92 | state = CheckLocation(C, state, Dst, lastElement, AccessKind::write); |
1869 | 92 | if (!state) |
1870 | 20 | return; |
1871 | 92 | } |
1872 | | |
1873 | | // If this is a stpcpy-style copy, the last element is the return value. |
1874 | 199 | if (returnPtr && ReturnEnd147 ) |
1875 | 10 | Result = lastElement; |
1876 | 199 | } |
1877 | | |
1878 | | // Invalidate the destination (regular invalidation without pointer-escaping |
1879 | | // the address of the top-level region). This must happen before we set the |
1880 | | // C string length because invalidation will clear the length. |
1881 | | // FIXME: Even if we can't perfectly model the copy, we should see if we |
1882 | | // can use LazyCompoundVals to copy the source values into the destination. |
1883 | | // This would probably remove any existing bindings past the end of the |
1884 | | // string, but that's still an improvement over blank invalidation. |
1885 | 240 | state = InvalidateBuffer(C, state, Dst.Expression, *dstRegVal, |
1886 | 240 | /*IsSourceBuffer*/ false, nullptr); |
1887 | | |
1888 | | // Invalidate the source (const-invalidation without const-pointer-escaping |
1889 | | // the address of the top-level region). |
1890 | 240 | state = InvalidateBuffer(C, state, srcExpr.Expression, srcVal, |
1891 | 240 | /*IsSourceBuffer*/ true, nullptr); |
1892 | | |
1893 | | // Set the C string length of the destination, if we know it. |
1894 | 240 | if (IsBounded && (appendK == ConcatFnKind::none)177 ) { |
1895 | | // strncpy is annoying in that it doesn't guarantee to null-terminate |
1896 | | // the result string. If the original string didn't fit entirely inside |
1897 | | // the bound (including the null-terminator), we don't know how long the |
1898 | | // result is. |
1899 | 88 | if (amountCopied != strLength) |
1900 | 55 | finalStrLength = UnknownVal(); |
1901 | 88 | } |
1902 | 240 | state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength); |
1903 | 240 | } |
1904 | | |
1905 | 240 | assert(state); |
1906 | | |
1907 | 240 | if (returnPtr) { |
1908 | | // If this is a stpcpy-style copy, but we were unable to check for a buffer |
1909 | | // overflow, we still need a result. Conjure a return value. |
1910 | 157 | if (ReturnEnd && Result.isUnknown()10 ) { |
1911 | 0 | Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); |
1912 | 0 | } |
1913 | 157 | } |
1914 | | // Set the return value. |
1915 | 240 | state = state->BindExpr(CE, LCtx, Result); |
1916 | 240 | C.addTransition(state); |
1917 | 240 | } |
1918 | | |
1919 | 111 | void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { |
1920 | | //int strcmp(const char *s1, const char *s2); |
1921 | 111 | evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ false); |
1922 | 111 | } |
1923 | | |
1924 | 115 | void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { |
1925 | | //int strncmp(const char *s1, const char *s2, size_t n); |
1926 | 115 | evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ false); |
1927 | 115 | } |
1928 | | |
1929 | | void CStringChecker::evalStrcasecmp(CheckerContext &C, |
1930 | 100 | const CallExpr *CE) const { |
1931 | | //int strcasecmp(const char *s1, const char *s2); |
1932 | 100 | evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ true); |
1933 | 100 | } |
1934 | | |
1935 | | void CStringChecker::evalStrncasecmp(CheckerContext &C, |
1936 | 116 | const CallExpr *CE) const { |
1937 | | //int strncasecmp(const char *s1, const char *s2, size_t n); |
1938 | 116 | evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ true); |
1939 | 116 | } |
1940 | | |
1941 | | void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, |
1942 | 442 | bool IsBounded, bool IgnoreCase) const { |
1943 | 442 | CurrentFunctionDescription = "string comparison function"; |
1944 | 442 | ProgramStateRef state = C.getState(); |
1945 | 442 | const LocationContext *LCtx = C.getLocationContext(); |
1946 | | |
1947 | | // Check that the first string is non-null |
1948 | 442 | AnyArgExpr Left = {CE->getArg(0), 0}; |
1949 | 442 | SVal LeftVal = state->getSVal(Left.Expression, LCtx); |
1950 | 442 | state = checkNonNull(C, state, Left, LeftVal); |
1951 | 442 | if (!state) |
1952 | 20 | return; |
1953 | | |
1954 | | // Check that the second string is non-null. |
1955 | 422 | AnyArgExpr Right = {CE->getArg(1), 1}; |
1956 | 422 | SVal RightVal = state->getSVal(Right.Expression, LCtx); |
1957 | 422 | state = checkNonNull(C, state, Right, RightVal); |
1958 | 422 | if (!state) |
1959 | 41 | return; |
1960 | | |
1961 | | // Get the string length of the first string or give up. |
1962 | 381 | SVal LeftLength = getCStringLength(C, state, Left.Expression, LeftVal); |
1963 | 381 | if (LeftLength.isUndef()) |
1964 | 0 | return; |
1965 | | |
1966 | | // Get the string length of the second string or give up. |
1967 | 381 | SVal RightLength = getCStringLength(C, state, Right.Expression, RightVal); |
1968 | 381 | if (RightLength.isUndef()) |
1969 | 0 | return; |
1970 | | |
1971 | | // If we know the two buffers are the same, we know the result is 0. |
1972 | | // First, get the two buffers' addresses. Another checker will have already |
1973 | | // made sure they're not undefined. |
1974 | 381 | DefinedOrUnknownSVal LV = LeftVal.castAs<DefinedOrUnknownSVal>(); |
1975 | 381 | DefinedOrUnknownSVal RV = RightVal.castAs<DefinedOrUnknownSVal>(); |
1976 | | |
1977 | | // See if they are the same. |
1978 | 381 | SValBuilder &svalBuilder = C.getSValBuilder(); |
1979 | 381 | DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); |
1980 | 381 | ProgramStateRef StSameBuf, StNotSameBuf; |
1981 | 381 | std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); |
1982 | | |
1983 | | // If the two arguments might be the same buffer, we know the result is 0, |
1984 | | // and we only need to check one size. |
1985 | 381 | if (StSameBuf) { |
1986 | 11 | StSameBuf = StSameBuf->BindExpr(CE, LCtx, |
1987 | 11 | svalBuilder.makeZeroVal(CE->getType())); |
1988 | 11 | C.addTransition(StSameBuf); |
1989 | | |
1990 | | // If the two arguments are GUARANTEED to be the same, we're done! |
1991 | 11 | if (!StNotSameBuf) |
1992 | 5 | return; |
1993 | 11 | } |
1994 | | |
1995 | 376 | assert(StNotSameBuf); |
1996 | 0 | state = StNotSameBuf; |
1997 | | |
1998 | | // At this point we can go about comparing the two buffers. |
1999 | | // For now, we only do this if they're both known string literals. |
2000 | | |
2001 | | // Attempt to extract string literals from both expressions. |
2002 | 376 | const StringLiteral *LeftStrLiteral = |
2003 | 376 | getCStringLiteral(C, state, Left.Expression, LeftVal); |
2004 | 376 | const StringLiteral *RightStrLiteral = |
2005 | 376 | getCStringLiteral(C, state, Right.Expression, RightVal); |
2006 | 376 | bool canComputeResult = false; |
2007 | 376 | SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, |
2008 | 376 | C.blockCount()); |
2009 | | |
2010 | 376 | if (LeftStrLiteral && RightStrLiteral375 ) { |
2011 | 370 | StringRef LeftStrRef = LeftStrLiteral->getString(); |
2012 | 370 | StringRef RightStrRef = RightStrLiteral->getString(); |
2013 | | |
2014 | 370 | if (IsBounded) { |
2015 | | // Get the max number of characters to compare. |
2016 | 200 | const Expr *lenExpr = CE->getArg(2); |
2017 | 200 | SVal lenVal = state->getSVal(lenExpr, LCtx); |
2018 | | |
2019 | | // If the length is known, we can get the right substrings. |
2020 | 200 | if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) { |
2021 | | // Create substrings of each to compare the prefix. |
2022 | 200 | LeftStrRef = LeftStrRef.substr(0, (size_t)len->getZExtValue()); |
2023 | 200 | RightStrRef = RightStrRef.substr(0, (size_t)len->getZExtValue()); |
2024 | 200 | canComputeResult = true; |
2025 | 200 | } |
2026 | 170 | } else { |
2027 | | // This is a normal, unbounded strcmp. |
2028 | 170 | canComputeResult = true; |
2029 | 170 | } |
2030 | | |
2031 | 370 | if (canComputeResult) { |
2032 | | // Real strcmp stops at null characters. |
2033 | 370 | size_t s1Term = LeftStrRef.find('\0'); |
2034 | 370 | if (s1Term != StringRef::npos) |
2035 | 20 | LeftStrRef = LeftStrRef.substr(0, s1Term); |
2036 | | |
2037 | 370 | size_t s2Term = RightStrRef.find('\0'); |
2038 | 370 | if (s2Term != StringRef::npos) |
2039 | 20 | RightStrRef = RightStrRef.substr(0, s2Term); |
2040 | | |
2041 | | // Use StringRef's comparison methods to compute the actual result. |
2042 | 370 | int compareRes = IgnoreCase ? LeftStrRef.compare_lower(RightStrRef)185 |
2043 | 185 | : LeftStrRef.compare(RightStrRef); |
2044 | | |
2045 | | // The strcmp function returns an integer greater than, equal to, or less |
2046 | | // than zero, [c11, p7.24.4.2]. |
2047 | 370 | if (compareRes == 0) { |
2048 | 110 | resultVal = svalBuilder.makeIntVal(compareRes, CE->getType()); |
2049 | 110 | } |
2050 | 260 | else { |
2051 | 260 | DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType()); |
2052 | | // Constrain strcmp's result range based on the result of StringRef's |
2053 | | // comparison methods. |
2054 | 260 | BinaryOperatorKind op = (compareRes == 1) ? BO_GT110 : BO_LT150 ; |
2055 | 260 | SVal compareWithZero = |
2056 | 260 | svalBuilder.evalBinOp(state, op, resultVal, zeroVal, |
2057 | 260 | svalBuilder.getConditionType()); |
2058 | 260 | DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>(); |
2059 | 260 | state = state->assume(compareWithZeroVal, true); |
2060 | 260 | } |
2061 | 370 | } |
2062 | 370 | } |
2063 | | |
2064 | 376 | state = state->BindExpr(CE, LCtx, resultVal); |
2065 | | |
2066 | | // Record this as a possible path. |
2067 | 376 | C.addTransition(state); |
2068 | 376 | } |
2069 | | |
2070 | 30 | void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { |
2071 | | //char *strsep(char **stringp, const char *delim); |
2072 | | // Sanity: does the search string parameter match the return type? |
2073 | 30 | SourceArgExpr SearchStrPtr = {CE->getArg(0), 0}; |
2074 | | |
2075 | 30 | QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType(); |
2076 | 30 | if (CharPtrTy.isNull() || |
2077 | 30 | CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType()) |
2078 | 0 | return; |
2079 | | |
2080 | 30 | CurrentFunctionDescription = "strsep()"; |
2081 | 30 | ProgramStateRef State = C.getState(); |
2082 | 30 | const LocationContext *LCtx = C.getLocationContext(); |
2083 | | |
2084 | | // Check that the search string pointer is non-null (though it may point to |
2085 | | // a null string). |
2086 | 30 | SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx); |
2087 | 30 | State = checkNonNull(C, State, SearchStrPtr, SearchStrVal); |
2088 | 30 | if (!State) |
2089 | 5 | return; |
2090 | | |
2091 | | // Check that the delimiter string is non-null. |
2092 | 25 | AnyArgExpr DelimStr = {CE->getArg(1), 1}; |
2093 | 25 | SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx); |
2094 | 25 | State = checkNonNull(C, State, DelimStr, DelimStrVal); |
2095 | 25 | if (!State) |
2096 | 5 | return; |
2097 | | |
2098 | 20 | SValBuilder &SVB = C.getSValBuilder(); |
2099 | 20 | SVal Result; |
2100 | 20 | if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) { |
2101 | | // Get the current value of the search string pointer, as a char*. |
2102 | 20 | Result = State->getSVal(*SearchStrLoc, CharPtrTy); |
2103 | | |
2104 | | // Invalidate the search string, representing the change of one delimiter |
2105 | | // character to NUL. |
2106 | 20 | State = InvalidateBuffer(C, State, SearchStrPtr.Expression, Result, |
2107 | 20 | /*IsSourceBuffer*/ false, nullptr); |
2108 | | |
2109 | | // Overwrite the search string pointer. The new value is either an address |
2110 | | // further along in the same string, or NULL if there are no more tokens. |
2111 | 20 | State = State->bindLoc(*SearchStrLoc, |
2112 | 20 | SVB.conjureSymbolVal(getTag(), |
2113 | 20 | CE, |
2114 | 20 | LCtx, |
2115 | 20 | CharPtrTy, |
2116 | 20 | C.blockCount()), |
2117 | 20 | LCtx); |
2118 | 0 | } else { |
2119 | 0 | assert(SearchStrVal.isUnknown()); |
2120 | | // Conjure a symbolic value. It's the best we can do. |
2121 | 0 | Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); |
2122 | 0 | } |
2123 | | |
2124 | | // Set the return value, and finish. |
2125 | 0 | State = State->BindExpr(CE, LCtx, Result); |
2126 | 20 | C.addTransition(State); |
2127 | 20 | } |
2128 | | |
2129 | | // These should probably be moved into a C++ standard library checker. |
2130 | 7 | void CStringChecker::evalStdCopy(CheckerContext &C, const CallExpr *CE) const { |
2131 | 7 | evalStdCopyCommon(C, CE); |
2132 | 7 | } |
2133 | | |
2134 | | void CStringChecker::evalStdCopyBackward(CheckerContext &C, |
2135 | 5 | const CallExpr *CE) const { |
2136 | 5 | evalStdCopyCommon(C, CE); |
2137 | 5 | } |
2138 | | |
2139 | | void CStringChecker::evalStdCopyCommon(CheckerContext &C, |
2140 | 12 | const CallExpr *CE) const { |
2141 | 12 | if (!CE->getArg(2)->getType()->isPointerType()) |
2142 | 2 | return; |
2143 | | |
2144 | 10 | ProgramStateRef State = C.getState(); |
2145 | | |
2146 | 10 | const LocationContext *LCtx = C.getLocationContext(); |
2147 | | |
2148 | | // template <class _InputIterator, class _OutputIterator> |
2149 | | // _OutputIterator |
2150 | | // copy(_InputIterator __first, _InputIterator __last, |
2151 | | // _OutputIterator __result) |
2152 | | |
2153 | | // Invalidate the destination buffer |
2154 | 10 | const Expr *Dst = CE->getArg(2); |
2155 | 10 | SVal DstVal = State->getSVal(Dst, LCtx); |
2156 | 10 | State = InvalidateBuffer(C, State, Dst, DstVal, /*IsSource=*/false, |
2157 | 10 | /*Size=*/nullptr); |
2158 | | |
2159 | 10 | SValBuilder &SVB = C.getSValBuilder(); |
2160 | | |
2161 | 10 | SVal ResultVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); |
2162 | 10 | State = State->BindExpr(CE, LCtx, ResultVal); |
2163 | | |
2164 | 10 | C.addTransition(State); |
2165 | 10 | } |
2166 | | |
2167 | 159 | void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const { |
2168 | | // void *memset(void *s, int c, size_t n); |
2169 | 159 | CurrentFunctionDescription = "memory set function"; |
2170 | | |
2171 | 159 | DestinationArgExpr Buffer = {CE->getArg(0), 0}; |
2172 | 159 | AnyArgExpr CharE = {CE->getArg(1), 1}; |
2173 | 159 | SizeArgExpr Size = {CE->getArg(2), 2}; |
2174 | | |
2175 | 159 | ProgramStateRef State = C.getState(); |
2176 | | |
2177 | | // See if the size argument is zero. |
2178 | 159 | const LocationContext *LCtx = C.getLocationContext(); |
2179 | 159 | SVal SizeVal = C.getSVal(Size.Expression); |
2180 | 159 | QualType SizeTy = Size.Expression->getType(); |
2181 | | |
2182 | 159 | ProgramStateRef ZeroSize, NonZeroSize; |
2183 | 159 | std::tie(ZeroSize, NonZeroSize) = assumeZero(C, State, SizeVal, SizeTy); |
2184 | | |
2185 | | // Get the value of the memory area. |
2186 | 159 | SVal BufferPtrVal = C.getSVal(Buffer.Expression); |
2187 | | |
2188 | | // If the size is zero, there won't be any actual memory access, so |
2189 | | // just bind the return value to the buffer and return. |
2190 | 159 | if (ZeroSize && !NonZeroSize0 ) { |
2191 | 0 | ZeroSize = ZeroSize->BindExpr(CE, LCtx, BufferPtrVal); |
2192 | 0 | C.addTransition(ZeroSize); |
2193 | 0 | return; |
2194 | 0 | } |
2195 | | |
2196 | | // Ensure the memory area is not null. |
2197 | | // If it is NULL there will be a NULL pointer dereference. |
2198 | 159 | State = checkNonNull(C, NonZeroSize, Buffer, BufferPtrVal); |
2199 | 159 | if (!State) |
2200 | 1 | return; |
2201 | | |
2202 | 158 | State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write); |
2203 | 158 | if (!State) |
2204 | 2 | return; |
2205 | | |
2206 | | // According to the values of the arguments, bind the value of the second |
2207 | | // argument to the destination buffer and set string length, or just |
2208 | | // invalidate the destination buffer. |
2209 | 156 | if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression), |
2210 | 156 | Size.Expression, C, State)) |
2211 | 0 | return; |
2212 | | |
2213 | 156 | State = State->BindExpr(CE, LCtx, BufferPtrVal); |
2214 | 156 | C.addTransition(State); |
2215 | 156 | } |
2216 | | |
2217 | 30 | void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const { |
2218 | 30 | CurrentFunctionDescription = "memory clearance function"; |
2219 | | |
2220 | 30 | DestinationArgExpr Buffer = {CE->getArg(0), 0}; |
2221 | 30 | SizeArgExpr Size = {CE->getArg(1), 1}; |
2222 | 30 | SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy); |
2223 | | |
2224 | 30 | ProgramStateRef State = C.getState(); |
2225 | | |
2226 | | // See if the size argument is zero. |
2227 | 30 | SVal SizeVal = C.getSVal(Size.Expression); |
2228 | 30 | QualType SizeTy = Size.Expression->getType(); |
2229 | | |
2230 | 30 | ProgramStateRef StateZeroSize, StateNonZeroSize; |
2231 | 30 | std::tie(StateZeroSize, StateNonZeroSize) = |
2232 | 30 | assumeZero(C, State, SizeVal, SizeTy); |
2233 | | |
2234 | | // If the size is zero, there won't be any actual memory access, |
2235 | | // In this case we just return. |
2236 | 30 | if (StateZeroSize && !StateNonZeroSize0 ) { |
2237 | 0 | C.addTransition(StateZeroSize); |
2238 | 0 | return; |
2239 | 0 | } |
2240 | | |
2241 | | // Get the value of the memory area. |
2242 | 30 | SVal MemVal = C.getSVal(Buffer.Expression); |
2243 | | |
2244 | | // Ensure the memory area is not null. |
2245 | | // If it is NULL there will be a NULL pointer dereference. |
2246 | 30 | State = checkNonNull(C, StateNonZeroSize, Buffer, MemVal); |
2247 | 30 | if (!State) |
2248 | 10 | return; |
2249 | | |
2250 | 20 | State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write); |
2251 | 20 | if (!State) |
2252 | 4 | return; |
2253 | | |
2254 | 16 | if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State)) |
2255 | 0 | return; |
2256 | | |
2257 | 16 | C.addTransition(State); |
2258 | 16 | } |
2259 | | |
2260 | | //===----------------------------------------------------------------------===// |
2261 | | // The driver method, and other Checker callbacks. |
2262 | | //===----------------------------------------------------------------------===// |
2263 | | |
2264 | | CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call, |
2265 | 34.0k | CheckerContext &C) const { |
2266 | 34.0k | const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); |
2267 | 34.0k | if (!CE) |
2268 | 3.35k | return nullptr; |
2269 | | |
2270 | 30.7k | const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); |
2271 | 30.7k | if (!FD) |
2272 | 19 | return nullptr; |
2273 | | |
2274 | 30.6k | if (Call.isCalled(StdCopy)) { |
2275 | 7 | return &CStringChecker::evalStdCopy; |
2276 | 30.6k | } else if (Call.isCalled(StdCopyBackward)) { |
2277 | 5 | return &CStringChecker::evalStdCopyBackward; |
2278 | 5 | } |
2279 | | |
2280 | | // Pro-actively check that argument types are safe to do arithmetic upon. |
2281 | | // We do not want to crash if someone accidentally passes a structure |
2282 | | // into, say, a C++ overload of any of these functions. We could not check |
2283 | | // that for std::copy because they may have arguments of other types. |
2284 | 30.6k | for (auto I : CE->arguments()) { |
2285 | 29.1k | QualType T = I->getType(); |
2286 | 29.1k | if (!T->isIntegralOrEnumerationType() && !T->isPointerType()19.6k ) |
2287 | 11.5k | return nullptr; |
2288 | 29.1k | } |
2289 | | |
2290 | 19.1k | const FnCheck *Callback = Callbacks.lookup(Call); |
2291 | 19.1k | if (Callback) |
2292 | 2.06k | return *Callback; |
2293 | | |
2294 | 17.0k | return nullptr; |
2295 | 19.1k | } |
2296 | | |
2297 | 34.0k | bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { |
2298 | 34.0k | FnCheck Callback = identifyCall(Call, C); |
2299 | | |
2300 | | // If the callee isn't a string function, let another checker handle it. |
2301 | 34.0k | if (!Callback) |
2302 | 31.9k | return false; |
2303 | | |
2304 | | // Check and evaluate the call. |
2305 | 2.07k | const auto *CE = cast<CallExpr>(Call.getOriginExpr()); |
2306 | 2.07k | (this->*Callback)(C, CE); |
2307 | | |
2308 | | // If the evaluate call resulted in no change, chain to the next eval call |
2309 | | // handler. |
2310 | | // Note, the custom CString evaluation calls assume that basic safety |
2311 | | // properties are held. However, if the user chooses to turn off some of these |
2312 | | // checks, we ignore the issues and leave the call evaluation to a generic |
2313 | | // handler. |
2314 | 2.07k | return C.isDifferent(); |
2315 | 34.0k | } |
2316 | | |
2317 | 11.9k | void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { |
2318 | | // Record string length for char a[] = "abc"; |
2319 | 11.9k | ProgramStateRef state = C.getState(); |
2320 | | |
2321 | 11.9k | for (const auto *I : DS->decls()) { |
2322 | 11.9k | const VarDecl *D = dyn_cast<VarDecl>(I); |
2323 | 11.9k | if (!D) |
2324 | 0 | continue; |
2325 | | |
2326 | | // FIXME: Handle array fields of structs. |
2327 | 11.9k | if (!D->getType()->isArrayType()) |
2328 | 11.2k | continue; |
2329 | | |
2330 | 714 | const Expr *Init = D->getInit(); |
2331 | 714 | if (!Init) |
2332 | 212 | continue; |
2333 | 502 | if (!isa<StringLiteral>(Init)) |
2334 | 314 | continue; |
2335 | | |
2336 | 188 | Loc VarLoc = state->getLValue(D, C.getLocationContext()); |
2337 | 188 | const MemRegion *MR = VarLoc.getAsRegion(); |
2338 | 188 | if (!MR) |
2339 | 0 | continue; |
2340 | | |
2341 | 188 | SVal StrVal = C.getSVal(Init); |
2342 | 188 | assert(StrVal.isValid() && "Initializer string is unknown or undefined"); |
2343 | 0 | DefinedOrUnknownSVal strLength = |
2344 | 188 | getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>(); |
2345 | | |
2346 | 188 | state = state->set<CStringLength>(MR, strLength); |
2347 | 188 | } |
2348 | | |
2349 | 11.9k | C.addTransition(state); |
2350 | 11.9k | } |
2351 | | |
2352 | | ProgramStateRef |
2353 | | CStringChecker::checkRegionChanges(ProgramStateRef state, |
2354 | | const InvalidatedSymbols *, |
2355 | | ArrayRef<const MemRegion *> ExplicitRegions, |
2356 | | ArrayRef<const MemRegion *> Regions, |
2357 | | const LocationContext *LCtx, |
2358 | 53.5k | const CallEvent *Call) const { |
2359 | 53.5k | CStringLengthTy Entries = state->get<CStringLength>(); |
2360 | 53.5k | if (Entries.isEmpty()) |
2361 | 52.5k | return state; |
2362 | | |
2363 | 1.00k | llvm::SmallPtrSet<const MemRegion *, 8> Invalidated; |
2364 | 1.00k | llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions; |
2365 | | |
2366 | | // First build sets for the changed regions and their super-regions. |
2367 | 1.00k | for (ArrayRef<const MemRegion *>::iterator |
2368 | 2.23k | I = Regions.begin(), E = Regions.end(); I != E; ++I1.22k ) { |
2369 | 1.22k | const MemRegion *MR = *I; |
2370 | 1.22k | Invalidated.insert(MR); |
2371 | | |
2372 | 1.22k | SuperRegions.insert(MR); |
2373 | 2.14k | while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) { |
2374 | 911 | MR = SR->getSuperRegion(); |
2375 | 911 | SuperRegions.insert(MR); |
2376 | 911 | } |
2377 | 1.22k | } |
2378 | | |
2379 | 1.00k | CStringLengthTy::Factory &F = state->get_context<CStringLength>(); |
2380 | | |
2381 | | // Then loop over the entries in the current state. |
2382 | 1.00k | for (CStringLengthTy::iterator I = Entries.begin(), |
2383 | 2.20k | E = Entries.end(); I != E; ++I1.19k ) { |
2384 | 1.19k | const MemRegion *MR = I.getKey(); |
2385 | | |
2386 | | // Is this entry for a super-region of a changed region? |
2387 | 1.19k | if (SuperRegions.count(MR)) { |
2388 | 583 | Entries = F.remove(Entries, MR); |
2389 | 583 | continue; |
2390 | 583 | } |
2391 | | |
2392 | | // Is this entry for a sub-region of a changed region? |
2393 | 613 | const MemRegion *Super = MR; |
2394 | 1.23k | while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) { |
2395 | 647 | Super = SR->getSuperRegion(); |
2396 | 647 | if (Invalidated.count(Super)) { |
2397 | 24 | Entries = F.remove(Entries, MR); |
2398 | 24 | break; |
2399 | 24 | } |
2400 | 647 | } |
2401 | 613 | } |
2402 | | |
2403 | 1.00k | return state->set<CStringLength>(Entries); |
2404 | 53.5k | } |
2405 | | |
2406 | | void CStringChecker::checkLiveSymbols(ProgramStateRef state, |
2407 | 133k | SymbolReaper &SR) const { |
2408 | | // Mark all symbols in our string length map as valid. |
2409 | 133k | CStringLengthTy Entries = state->get<CStringLength>(); |
2410 | | |
2411 | 133k | for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); |
2412 | 135k | I != E; ++I2.78k ) { |
2413 | 2.78k | SVal Len = I.getData(); |
2414 | | |
2415 | 2.78k | for (SymExpr::symbol_iterator si = Len.symbol_begin(), |
2416 | 4.45k | se = Len.symbol_end(); si != se; ++si1.66k ) |
2417 | 1.66k | SR.markInUse(*si); |
2418 | 2.78k | } |
2419 | 133k | } |
2420 | | |
2421 | | void CStringChecker::checkDeadSymbols(SymbolReaper &SR, |
2422 | 133k | CheckerContext &C) const { |
2423 | 133k | ProgramStateRef state = C.getState(); |
2424 | 133k | CStringLengthTy Entries = state->get<CStringLength>(); |
2425 | 133k | if (Entries.isEmpty()) |
2426 | 130k | return; |
2427 | | |
2428 | 2.31k | CStringLengthTy::Factory &F = state->get_context<CStringLength>(); |
2429 | 2.31k | for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); |
2430 | 5.10k | I != E; ++I2.78k ) { |
2431 | 2.78k | SVal Len = I.getData(); |
2432 | 2.78k | if (SymbolRef Sym = Len.getAsSymbol()) { |
2433 | 1.61k | if (SR.isDead(Sym)) |
2434 | 437 | Entries = F.remove(Entries, I.getKey()); |
2435 | 1.61k | } |
2436 | 2.78k | } |
2437 | | |
2438 | 2.31k | state = state->set<CStringLength>(Entries); |
2439 | 2.31k | C.addTransition(state); |
2440 | 2.31k | } |
2441 | | |
2442 | 235 | void ento::registerCStringModeling(CheckerManager &Mgr) { |
2443 | 235 | Mgr.registerChecker<CStringChecker>(); |
2444 | 235 | } |
2445 | | |
2446 | 1.57k | bool ento::shouldRegisterCStringModeling(const CheckerManager &mgr) { |
2447 | 1.57k | return true; |
2448 | 1.57k | } |
2449 | | |
2450 | | #define REGISTER_CHECKER(name) \ |
2451 | 123 | void ento::register##name(CheckerManager &mgr) { \ |
2452 | 123 | CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ |
2453 | 123 | checker->Filter.Check##name = true; \ |
2454 | 123 | checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ |
2455 | 123 | } \ clang::ento::registerCStringNullArg(clang::ento::CheckerManager&) Line | Count | Source | 2451 | 65 | void ento::register##name(CheckerManager &mgr) { \ | 2452 | 65 | CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ | 2453 | 65 | checker->Filter.Check##name = true; \ | 2454 | 65 | checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ | 2455 | 65 | } \ |
clang::ento::registerCStringOutOfBounds(clang::ento::CheckerManager&) Line | Count | Source | 2451 | 18 | void ento::register##name(CheckerManager &mgr) { \ | 2452 | 18 | CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ | 2453 | 18 | checker->Filter.Check##name = true; \ | 2454 | 18 | checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ | 2455 | 18 | } \ |
clang::ento::registerCStringBufferOverlap(clang::ento::CheckerManager&) Line | Count | Source | 2451 | 20 | void ento::register##name(CheckerManager &mgr) { \ | 2452 | 20 | CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ | 2453 | 20 | checker->Filter.Check##name = true; \ | 2454 | 20 | checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ | 2455 | 20 | } \ |
clang::ento::registerCStringNotNullTerm(clang::ento::CheckerManager&) Line | Count | Source | 2451 | 20 | void ento::register##name(CheckerManager &mgr) { \ | 2452 | 20 | CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ | 2453 | 20 | checker->Filter.Check##name = true; \ | 2454 | 20 | checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ | 2455 | 20 | } \ |
|
2456 | | \ |
2457 | 250 | bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } clang::ento::shouldRegisterCStringNullArg(clang::ento::CheckerManager const&) Line | Count | Source | 2457 | 134 | bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } |
clang::ento::shouldRegisterCStringOutOfBounds(clang::ento::CheckerManager const&) Line | Count | Source | 2457 | 36 | bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } |
clang::ento::shouldRegisterCStringBufferOverlap(clang::ento::CheckerManager const&) Line | Count | Source | 2457 | 40 | bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } |
clang::ento::shouldRegisterCStringNotNullTerm(clang::ento::CheckerManager const&) Line | Count | Source | 2457 | 40 | bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } |
|
2458 | | |
2459 | | REGISTER_CHECKER(CStringNullArg) |
2460 | | REGISTER_CHECKER(CStringOutOfBounds) |
2461 | | REGISTER_CHECKER(CStringBufferOverlap) |
2462 | | REGISTER_CHECKER(CStringNotNullTerm) |