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