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 // TODO: If Size is tainted and we cannot prove that it is smaller or equal
1342 // to the size of the destination buffer, then emit a warning
1343 // that an attacker may provoke a buffer overflow error.
1344 state = stateNonZeroSize;
1345
1346 // Ensure the destination is not null. If it is NULL there will be a
1347 // NULL pointer dereference.
1348 state = checkNonNull(C, state, Dest, destVal);
1349 if (!state)
1350 return;
1351
1352 // Get the value of the Src.
1353 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1354
1355 // Ensure the source is not null. If it is NULL there will be a
1356 // NULL pointer dereference.
1357 state = checkNonNull(C, state, Source, srcVal);
1358 if (!state)
1359 return;
1360
1361 // Ensure the accesses are valid and that the buffers do not overlap.
1362 state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, CK);
1363 state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, CK);
1364
1365 if (Restricted)
1366 state = CheckOverlap(C, state, Size, Dest, Source, CK);
1367
1368 if (!state)
1369 return;
1370
1371 // If this is mempcpy, get the byte after the last byte copied and
1372 // bind the expr.
1373 if (IsMempcpy) {
1374 // Get the byte after the last byte copied.
1375 SValBuilder &SvalBuilder = C.getSValBuilder();
1376 ASTContext &Ctx = SvalBuilder.getContext();
1377 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1378 SVal DestRegCharVal =
1379 SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1380 SVal lastElement = C.getSValBuilder().evalBinOp(
1381 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1382 // If we don't know how much we copied, we can at least
1383 // conjure a return value for later.
1384 if (lastElement.isUnknown())
1385 lastElement = C.getSValBuilder().conjureSymbolVal(
1386 nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
1387
1388 // The byte after the last byte copied is the return value.
1389 state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement);
1390 } else {
1391 // All other copies return the destination buffer.
1392 // (Well, bcopy() has a void return type, but this won't hurt.)
1393 state = state->BindExpr(Call.getOriginExpr(), LCtx, destVal);
1394 }
1395
1396 // Invalidate the destination (regular invalidation without pointer-escaping
1397 // the address of the top-level region).
1398 // FIXME: Even if we can't perfectly model the copy, we should see if we
1399 // can use LazyCompoundVals to copy the source values into the destination.
1400 // This would probably remove any existing bindings past the end of the
1401 // copied region, but that's still an improvement over blank invalidation.
1402 state = invalidateDestinationBufferBySize(
1403 C, state, Dest.Expression, C.getSVal(Dest.Expression), sizeVal,
1404 Size.Expression->getType());
1405
1406 // Invalidate the source (const-invalidation without const-pointer-escaping
1407 // the address of the top-level region).
1408 state = invalidateSourceBuffer(C, state, Source.Expression,
1409 C.getSVal(Source.Expression));
1410
1411 C.addTransition(state);
1412 }
1413}
1414
1415void CStringChecker::evalMemcpy(CheckerContext &C, const CallEvent &Call,
1416 CharKind CK) const {
1417 // void *memcpy(void *restrict dst, const void *restrict src, size_t n);
1418 // The return value is the address of the destination buffer.
1419 DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
1420 SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
1421 SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
1422
1423 ProgramStateRef State = C.getState();
1424
1425 constexpr bool IsRestricted = true;
1426 constexpr bool IsMempcpy = false;
1427 evalCopyCommon(C, Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1428}
1429
1430void CStringChecker::evalMempcpy(CheckerContext &C, const CallEvent &Call,
1431 CharKind CK) const {
1432 // void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
1433 // The return value is a pointer to the byte following the last written byte.
1434 DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
1435 SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
1436 SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
1437
1438 constexpr bool IsRestricted = true;
1439 constexpr bool IsMempcpy = true;
1440 evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
1441 IsMempcpy, CK);
1442}
1443
1444void CStringChecker::evalMemmove(CheckerContext &C, const CallEvent &Call,
1445 CharKind CK) const {
1446 // void *memmove(void *dst, const void *src, size_t n);
1447 // The return value is the address of the destination buffer.
1448 DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
1449 SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
1450 SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
1451
1452 constexpr bool IsRestricted = false;
1453 constexpr bool IsMempcpy = false;
1454 evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
1455 IsMempcpy, CK);
1456}
1457
1458void CStringChecker::evalBcopy(CheckerContext &C, const CallEvent &Call) const {
1459 // void bcopy(const void *src, void *dst, size_t n);
1460 SourceArgExpr Src{{Call.getArgExpr(0), 0}};
1461 DestinationArgExpr Dest = {{Call.getArgExpr(1), 1}};
1462 SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
1463
1464 constexpr bool IsRestricted = false;
1465 constexpr bool IsMempcpy = false;
1466 evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
1467 IsMempcpy, CharKind::Regular);
1468}
1469
1470void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
1471 CharKind CK) const {
1472 // int memcmp(const void *s1, const void *s2, size_t n);
1473 CurrentFunctionDescription = "memory comparison function";
1474
1475 AnyArgExpr Left = {Call.getArgExpr(0), 0};
1476 AnyArgExpr Right = {Call.getArgExpr(1), 1};
1477 SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
1478
1479 ProgramStateRef State = C.getState();
1480 SValBuilder &Builder = C.getSValBuilder();
1481 const LocationContext *LCtx = C.getLocationContext();
1482
1483 // See if the size argument is zero.
1484 SVal sizeVal = State->getSVal(Size.Expression, LCtx);
1485 QualType sizeTy = Size.Expression->getType();
1486
1487 ProgramStateRef stateZeroSize, stateNonZeroSize;
1488 std::tie(stateZeroSize, stateNonZeroSize) =
1489 assumeZero(C, State, sizeVal, sizeTy);
1490
1491 // If the size can be zero, the result will be 0 in that case, and we don't
1492 // have to check either of the buffers.
1493 if (stateZeroSize) {
1494 State = stateZeroSize;
1495 State = State->BindExpr(Call.getOriginExpr(), LCtx,
1496 Builder.makeZeroVal(Call.getResultType()));
1497 C.addTransition(State);
1498 }
1499
1500 // If the size can be nonzero, we have to check the other arguments.
1501 if (stateNonZeroSize) {
1502 State = stateNonZeroSize;
1503 // If we know the two buffers are the same, we know the result is 0.
1504 // First, get the two buffers' addresses. Another checker will have already
1505 // made sure they're not undefined.
1507 State->getSVal(Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1509 State->getSVal(Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1510
1511 // See if they are the same.
1512 ProgramStateRef SameBuffer, NotSameBuffer;
1513 std::tie(SameBuffer, NotSameBuffer) =
1514 State->assume(Builder.evalEQ(State, LV, RV));
1515
1516 // If the two arguments are the same buffer, we know the result is 0,
1517 // and we only need to check one size.
1518 if (SameBuffer && !NotSameBuffer) {
1519 State = SameBuffer;
1520 State = CheckBufferAccess(C, State, Left, Size, AccessKind::read);
1521 if (State) {
1522 State = SameBuffer->BindExpr(Call.getOriginExpr(), LCtx,
1523 Builder.makeZeroVal(Call.getResultType()));
1524 C.addTransition(State);
1525 }
1526 return;
1527 }
1528
1529 // If the two arguments might be different buffers, we have to check
1530 // the size of both of them.
1531 assert(NotSameBuffer);
1532 State = CheckBufferAccess(C, State, Right, Size, AccessKind::read, CK);
1533 State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
1534 if (State) {
1535 // The return value is the comparison result, which we don't know.
1536 SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
1537 C.blockCount());
1538 State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
1539 C.addTransition(State);
1540 }
1541 }
1542}
1543
1544void CStringChecker::evalstrLength(CheckerContext &C,
1545 const CallEvent &Call) const {
1546 // size_t strlen(const char *s);
1547 evalstrLengthCommon(C, Call, /* IsStrnlen = */ false);
1548}
1549
1550void CStringChecker::evalstrnLength(CheckerContext &C,
1551 const CallEvent &Call) const {
1552 // size_t strnlen(const char *s, size_t maxlen);
1553 evalstrLengthCommon(C, Call, /* IsStrnlen = */ true);
1554}
1555
1556void CStringChecker::evalstrLengthCommon(CheckerContext &C,
1557 const CallEvent &Call,
1558 bool IsStrnlen) const {
1559 CurrentFunctionDescription = "string length function";
1560 ProgramStateRef state = C.getState();
1561 const LocationContext *LCtx = C.getLocationContext();
1562
1563 if (IsStrnlen) {
1564 const Expr *maxlenExpr = Call.getArgExpr(1);
1565 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1566
1567 ProgramStateRef stateZeroSize, stateNonZeroSize;
1568 std::tie(stateZeroSize, stateNonZeroSize) =
1569 assumeZero(C, state, maxlenVal, maxlenExpr->getType());
1570
1571 // If the size can be zero, the result will be 0 in that case, and we don't
1572 // have to check the string itself.
1573 if (stateZeroSize) {
1574 SVal zero = C.getSValBuilder().makeZeroVal(Call.getResultType());
1575 stateZeroSize = stateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, zero);
1576 C.addTransition(stateZeroSize);
1577 }
1578
1579 // If the size is GUARANTEED to be zero, we're done!
1580 if (!stateNonZeroSize)
1581 return;
1582
1583 // Otherwise, record the assumption that the size is nonzero.
1584 state = stateNonZeroSize;
1585 }
1586
1587 // Check that the string argument is non-null.
1588 AnyArgExpr Arg = {Call.getArgExpr(0), 0};
1589 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1590 state = checkNonNull(C, state, Arg, ArgVal);
1591
1592 if (!state)
1593 return;
1594
1595 SVal strLength = getCStringLength(C, state, Arg.Expression, ArgVal);
1596
1597 // If the argument isn't a valid C string, there's no valid state to
1598 // transition to.
1599 if (strLength.isUndef())
1600 return;
1601
1603
1604 // If the check is for strnlen() then bind the return value to no more than
1605 // the maxlen value.
1606 if (IsStrnlen) {
1607 QualType cmpTy = C.getSValBuilder().getConditionType();
1608
1609 // It's a little unfortunate to be getting this again,
1610 // but it's not that expensive...
1611 const Expr *maxlenExpr = Call.getArgExpr(1);
1612 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1613
1614 std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
1615 std::optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
1616
1617 if (strLengthNL && maxlenValNL) {
1618 ProgramStateRef stateStringTooLong, stateStringNotTooLong;
1619
1620 // Check if the strLength is greater than the maxlen.
1621 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1622 C.getSValBuilder()
1623 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1624 .castAs<DefinedOrUnknownSVal>());
1625
1626 if (stateStringTooLong && !stateStringNotTooLong) {
1627 // If the string is longer than maxlen, return maxlen.
1628 result = *maxlenValNL;
1629 } else if (stateStringNotTooLong && !stateStringTooLong) {
1630 // If the string is shorter than maxlen, return its length.
1631 result = *strLengthNL;
1632 }
1633 }
1634
1635 if (result.isUnknown()) {
1636 // If we don't have enough information for a comparison, there's
1637 // no guarantee the full string length will actually be returned.
1638 // All we know is the return value is the min of the string length
1639 // and the limit. This is better than nothing.
1640 result = C.getSValBuilder().conjureSymbolVal(
1641 nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
1642 NonLoc resultNL = result.castAs<NonLoc>();
1643
1644 if (strLengthNL) {
1645 state = state->assume(C.getSValBuilder().evalBinOpNN(
1646 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1647 .castAs<DefinedOrUnknownSVal>(), true);
1648 }
1649
1650 if (maxlenValNL) {
1651 state = state->assume(C.getSValBuilder().evalBinOpNN(
1652 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1653 .castAs<DefinedOrUnknownSVal>(), true);
1654 }
1655 }
1656
1657 } else {
1658 // This is a plain strlen(), not strnlen().
1659 result = strLength.castAs<DefinedOrUnknownSVal>();
1660
1661 // If we don't know the length of the string, conjure a return
1662 // value, so it can be used in constraints, at least.
1663 if (result.isUnknown()) {
1664 result = C.getSValBuilder().conjureSymbolVal(
1665 nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
1666 }
1667 }
1668
1669 // Bind the return value.
1670 assert(!result.isUnknown() && "Should have conjured a value by now");
1671 state = state->BindExpr(Call.getOriginExpr(), LCtx, result);
1672 C.addTransition(state);
1673}
1674
1675void CStringChecker::evalStrcpy(CheckerContext &C,
1676 const CallEvent &Call) const {
1677 // char *strcpy(char *restrict dst, const char *restrict src);
1678 evalStrcpyCommon(C, Call,
1679 /* ReturnEnd = */ false,
1680 /* IsBounded = */ false,
1681 /* appendK = */ ConcatFnKind::none);
1682}
1683
1684void CStringChecker::evalStrncpy(CheckerContext &C,
1685 const CallEvent &Call) const {
1686 // char *strncpy(char *restrict dst, const char *restrict src, size_t n);
1687 evalStrcpyCommon(C, Call,
1688 /* ReturnEnd = */ false,
1689 /* IsBounded = */ true,
1690 /* appendK = */ ConcatFnKind::none);
1691}
1692
1693void CStringChecker::evalStpcpy(CheckerContext &C,
1694 const CallEvent &Call) const {
1695 // char *stpcpy(char *restrict dst, const char *restrict src);
1696 evalStrcpyCommon(C, Call,
1697 /* ReturnEnd = */ true,
1698 /* IsBounded = */ false,
1699 /* appendK = */ ConcatFnKind::none);
1700}
1701
1702void CStringChecker::evalStrlcpy(CheckerContext &C,
1703 const CallEvent &Call) const {
1704 // size_t strlcpy(char *dest, const char *src, size_t size);
1705 evalStrcpyCommon(C, Call,
1706 /* ReturnEnd = */ true,
1707 /* IsBounded = */ true,
1708 /* appendK = */ ConcatFnKind::none,
1709 /* returnPtr = */ false);
1710}
1711
1712void CStringChecker::evalStrcat(CheckerContext &C,
1713 const CallEvent &Call) const {
1714 // char *strcat(char *restrict s1, const char *restrict s2);
1715 evalStrcpyCommon(C, Call,
1716 /* ReturnEnd = */ false,
1717 /* IsBounded = */ false,
1718 /* appendK = */ ConcatFnKind::strcat);
1719}
1720
1721void CStringChecker::evalStrncat(CheckerContext &C,
1722 const CallEvent &Call) const {
1723 // char *strncat(char *restrict s1, const char *restrict s2, size_t n);
1724 evalStrcpyCommon(C, Call,
1725 /* ReturnEnd = */ false,
1726 /* IsBounded = */ true,
1727 /* appendK = */ ConcatFnKind::strcat);
1728}
1729
1730void CStringChecker::evalStrlcat(CheckerContext &C,
1731 const CallEvent &Call) const {
1732 // size_t strlcat(char *dst, const char *src, size_t size);
1733 // It will append at most size - strlen(dst) - 1 bytes,
1734 // NULL-terminating the result.
1735 evalStrcpyCommon(C, Call,
1736 /* ReturnEnd = */ false,
1737 /* IsBounded = */ true,
1738 /* appendK = */ ConcatFnKind::strlcat,
1739 /* returnPtr = */ false);
1740}
1741
1742void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
1743 bool ReturnEnd, bool IsBounded,
1744 ConcatFnKind appendK,
1745 bool returnPtr) const {
1746 if (appendK == ConcatFnKind::none)
1747 CurrentFunctionDescription = "string copy function";
1748 else
1749 CurrentFunctionDescription = "string concatenation function";
1750
1751 ProgramStateRef state = C.getState();
1752 const LocationContext *LCtx = C.getLocationContext();
1753
1754 // Check that the destination is non-null.
1755 DestinationArgExpr Dst = {{Call.getArgExpr(0), 0}};
1756 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1757 state = checkNonNull(C, state, Dst, DstVal);
1758 if (!state)
1759 return;
1760
1761 // Check that the source is non-null.
1762 SourceArgExpr srcExpr = {{Call.getArgExpr(1), 1}};
1763 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1764 state = checkNonNull(C, state, srcExpr, srcVal);
1765 if (!state)
1766 return;
1767
1768 // Get the string length of the source.
1769 SVal strLength = getCStringLength(C, state, srcExpr.Expression, srcVal);
1770 std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
1771
1772 // Get the string length of the destination buffer.
1773 SVal dstStrLength = getCStringLength(C, state, Dst.Expression, DstVal);
1774 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1775
1776 // If the source isn't a valid C string, give up.
1777 if (strLength.isUndef())
1778 return;
1779
1780 SValBuilder &svalBuilder = C.getSValBuilder();
1781 QualType cmpTy = svalBuilder.getConditionType();
1782 QualType sizeTy = svalBuilder.getContext().getSizeType();
1783
1784 // These two values allow checking two kinds of errors:
1785 // - actual overflows caused by a source that doesn't fit in the destination
1786 // - potential overflows caused by a bound that could exceed the destination
1787 SVal amountCopied = UnknownVal();
1788 SVal maxLastElementIndex = UnknownVal();
1789 const char *boundWarning = nullptr;
1790
1791 // FIXME: Why do we choose the srcExpr if the access has no size?
1792 // Note that the 3rd argument of the call would be the size parameter.
1793 SizeArgExpr SrcExprAsSizeDummy = {
1794 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1795 state = CheckOverlap(
1796 C, state,
1797 (IsBounded ? SizeArgExpr{{Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1798 Dst, srcExpr);
1799
1800 if (!state)
1801 return;
1802
1803 // If the function is strncpy, strncat, etc... it is bounded.
1804 if (IsBounded) {
1805 // Get the max number of characters to copy.
1806 SizeArgExpr lenExpr = {{Call.getArgExpr(2), 2}};
1807 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1808
1809 // Protect against misdeclared strncpy().
1810 lenVal =
1811 svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1812
1813 std::optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
1814
1815 // If we know both values, we might be able to figure out how much
1816 // we're copying.
1817 if (strLengthNL && lenValNL) {
1818 switch (appendK) {
1819 case ConcatFnKind::none:
1820 case ConcatFnKind::strcat: {
1821 ProgramStateRef stateSourceTooLong, stateSourceNotTooLong;
1822 // Check if the max number to copy is less than the length of the src.
1823 // If the bound is equal to the source length, strncpy won't null-
1824 // terminate the result!
1825 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1826 svalBuilder
1827 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1828 .castAs<DefinedOrUnknownSVal>());
1829
1830 if (stateSourceTooLong && !stateSourceNotTooLong) {
1831 // Max number to copy is less than the length of the src, so the
1832 // actual strLength copied is the max number arg.
1833 state = stateSourceTooLong;
1834 amountCopied = lenVal;
1835
1836 } else if (!stateSourceTooLong && stateSourceNotTooLong) {
1837 // The source buffer entirely fits in the bound.
1838 state = stateSourceNotTooLong;
1839 amountCopied = strLength;
1840 }
1841 break;
1842 }
1843 case ConcatFnKind::strlcat:
1844 if (!dstStrLengthNL)
1845 return;
1846
1847 // amountCopied = min (size - dstLen - 1 , srcLen)
1848 SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
1849 *dstStrLengthNL, sizeTy);
1850 if (!isa<NonLoc>(freeSpace))
1851 return;
1852 freeSpace =
1853 svalBuilder.evalBinOp(state, BO_Sub, freeSpace,
1854 svalBuilder.makeIntVal(1, sizeTy), sizeTy);
1855 std::optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>();
1856
1857 // While unlikely, it is possible that the subtraction is
1858 // too complex to compute, let's check whether it succeeded.
1859 if (!freeSpaceNL)
1860 return;
1861 SVal hasEnoughSpace = svalBuilder.evalBinOpNN(
1862 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1863
1864 ProgramStateRef TrueState, FalseState;
1865 std::tie(TrueState, FalseState) =
1866 state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>());
1867
1868 // srcStrLength <= size - dstStrLength -1
1869 if (TrueState && !FalseState) {
1870 amountCopied = strLength;
1871 }
1872
1873 // srcStrLength > size - dstStrLength -1
1874 if (!TrueState && FalseState) {
1875 amountCopied = freeSpace;
1876 }
1877
1878 if (TrueState && FalseState)
1879 amountCopied = UnknownVal();
1880 break;
1881 }
1882 }
1883 // We still want to know if the bound is known to be too large.
1884 if (lenValNL) {
1885 switch (appendK) {
1886 case ConcatFnKind::strcat:
1887 // For strncat, the check is strlen(dst) + lenVal < sizeof(dst)
1888
1889 // Get the string length of the destination. If the destination is
1890 // memory that can't have a string length, we shouldn't be copying
1891 // into it anyway.
1892 if (dstStrLength.isUndef())
1893 return;
1894
1895 if (dstStrLengthNL) {
1896 maxLastElementIndex = svalBuilder.evalBinOpNN(
1897 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1898
1899 boundWarning = "Size argument is greater than the free space in the "
1900 "destination buffer";
1901 }
1902 break;
1903 case ConcatFnKind::none:
1904 case ConcatFnKind::strlcat:
1905 // For strncpy and strlcat, this is just checking
1906 // that lenVal <= sizeof(dst).
1907 // (Yes, strncpy and strncat differ in how they treat termination.
1908 // strncat ALWAYS terminates, but strncpy doesn't.)
1909
1910 // We need a special case for when the copy size is zero, in which
1911 // case strncpy will do no work at all. Our bounds check uses n-1
1912 // as the last element accessed, so n == 0 is problematic.
1913 ProgramStateRef StateZeroSize, StateNonZeroSize;
1914 std::tie(StateZeroSize, StateNonZeroSize) =
1915 assumeZero(C, state, *lenValNL, sizeTy);
1916
1917 // If the size is known to be zero, we're done.
1918 if (StateZeroSize && !StateNonZeroSize) {
1919 if (returnPtr) {
1920 StateZeroSize =
1921 StateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, DstVal);
1922 } else {
1923 if (appendK == ConcatFnKind::none) {
1924 // strlcpy returns strlen(src)
1925 StateZeroSize = StateZeroSize->BindExpr(Call.getOriginExpr(),
1926 LCtx, strLength);
1927 } else {
1928 // strlcat returns strlen(src) + strlen(dst)
1929 SVal retSize = svalBuilder.evalBinOp(
1930 state, BO_Add, strLength, dstStrLength, sizeTy);
1931 StateZeroSize =
1932 StateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, retSize);
1933 }
1934 }
1935 C.addTransition(StateZeroSize);
1936 return;
1937 }
1938
1939 // Otherwise, go ahead and figure out the last element we'll touch.
1940 // We don't record the non-zero assumption here because we can't
1941 // be sure. We won't warn on a possible zero.
1942 NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
1943 maxLastElementIndex =
1944 svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
1945 boundWarning = "Size argument is greater than the length of the "
1946 "destination buffer";
1947 break;
1948 }
1949 }
1950 } else {
1951 // The function isn't bounded. The amount copied should match the length
1952 // of the source buffer.
1953 amountCopied = strLength;
1954 }
1955
1956 assert(state);
1957
1958 // This represents the number of characters copied into the destination
1959 // buffer. (It may not actually be the strlen if the destination buffer
1960 // is not terminated.)
1961 SVal finalStrLength = UnknownVal();
1962 SVal strlRetVal = UnknownVal();
1963
1964 if (appendK == ConcatFnKind::none && !returnPtr) {
1965 // strlcpy returns the sizeof(src)
1966 strlRetVal = strLength;
1967 }
1968
1969 // If this is an appending function (strcat, strncat...) then set the
1970 // string length to strlen(src) + strlen(dst) since the buffer will
1971 // ultimately contain both.
1972 if (appendK != ConcatFnKind::none) {
1973 // Get the string length of the destination. If the destination is memory
1974 // that can't have a string length, we shouldn't be copying into it anyway.
1975 if (dstStrLength.isUndef())
1976 return;
1977
1978 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
1979 strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL,
1980 *dstStrLengthNL, sizeTy);
1981 }
1982
1983 std::optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>();
1984
1985 // If we know both string lengths, we might know the final string length.
1986 if (amountCopiedNL && dstStrLengthNL) {
1987 // Make sure the two lengths together don't overflow a size_t.
1988 state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL);
1989 if (!state)
1990 return;
1991
1992 finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL,
1993 *dstStrLengthNL, sizeTy);
1994 }
1995
1996 // If we couldn't get a single value for the final string length,
1997 // we can at least bound it by the individual lengths.
1998 if (finalStrLength.isUnknown()) {
1999 // Try to get a "hypothetical" string length symbol, which we can later
2000 // set as a real value if that turns out to be the case.
2001 finalStrLength =
2002 getCStringLength(C, state, Call.getOriginExpr(), DstVal, true);
2003 assert(!finalStrLength.isUndef());
2004
2005 if (std::optional<NonLoc> finalStrLengthNL =
2006 finalStrLength.getAs<NonLoc>()) {
2007 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2008 // we overwrite dst string with the src
2009 // finalStrLength >= srcStrLength
2010 SVal sourceInResult = svalBuilder.evalBinOpNN(
2011 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2012 state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(),
2013 true);
2014 if (!state)
2015 return;
2016 }
2017
2018 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2019 // we extend the dst string with the src
2020 // finalStrLength >= dstStrLength
2021 SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE,
2022 *finalStrLengthNL,
2023 *dstStrLengthNL,
2024 cmpTy);
2025 state =
2026 state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true);
2027 if (!state)
2028 return;
2029 }
2030 }
2031 }
2032
2033 } else {
2034 // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and
2035 // the final string length will match the input string length.
2036 finalStrLength = amountCopied;
2037 }
2038
2039 SVal Result;
2040
2041 if (returnPtr) {
2042 // The final result of the function will either be a pointer past the last
2043 // copied element, or a pointer to the start of the destination buffer.
2044 Result = (ReturnEnd ? UnknownVal() : DstVal);
2045 } else {
2046 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2047 //strlcpy, strlcat
2048 Result = strlRetVal;
2049 else
2050 Result = finalStrLength;
2051 }
2052
2053 assert(state);
2054
2055 // If the destination is a MemRegion, try to check for a buffer overflow and
2056 // record the new string length.
2057 if (std::optional<loc::MemRegionVal> dstRegVal =
2058 DstVal.getAs<loc::MemRegionVal>()) {
2059 QualType ptrTy = Dst.Expression->getType();
2060
2061 // If we have an exact value on a bounded copy, use that to check for
2062 // overflows, rather than our estimate about how much is actually copied.
2063 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
2064 SVal maxLastElement =
2065 svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2066
2067 // Check if the first byte of the destination is writable.
2068 state = CheckLocation(C, state, Dst, DstVal, AccessKind::write);
2069 if (!state)
2070 return;
2071 // Check if the last byte of the destination is writable.
2072 state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write);
2073 if (!state)
2074 return;
2075 }
2076
2077 // Then, if the final length is known...
2078 if (std::optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
2079 SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
2080 *knownStrLength, ptrTy);
2081
2082 // ...and we haven't checked the bound, we'll check the actual copy.
2083 if (!boundWarning) {
2084 // Check if the first byte of the destination is writable.
2085 state = CheckLocation(C, state, Dst, DstVal, AccessKind::write);
2086 if (!state)
2087 return;
2088 // Check if the last byte of the destination is writable.
2089 state = CheckLocation(C, state, Dst, lastElement, AccessKind::write);
2090 if (!state)
2091 return;
2092 }
2093
2094 // If this is a stpcpy-style copy, the last element is the return value.
2095 if (returnPtr && ReturnEnd)
2096 Result = lastElement;
2097 }
2098
2099 // Invalidate the destination (regular invalidation without pointer-escaping
2100 // the address of the top-level region). This must happen before we set the
2101 // C string length because invalidation will clear the length.
2102 // FIXME: Even if we can't perfectly model the copy, we should see if we
2103 // can use LazyCompoundVals to copy the source values into the destination.
2104 // This would probably remove any existing bindings past the end of the
2105 // string, but that's still an improvement over blank invalidation.
2106 state = invalidateDestinationBufferBySize(C, state, Dst.Expression,
2107 *dstRegVal, amountCopied,
2108 C.getASTContext().getSizeType());
2109
2110 // Invalidate the source (const-invalidation without const-pointer-escaping
2111 // the address of the top-level region).
2112 state = invalidateSourceBuffer(C, state, srcExpr.Expression, srcVal);
2113
2114 // Set the C string length of the destination, if we know it.
2115 if (IsBounded && (appendK == ConcatFnKind::none)) {
2116 // strncpy is annoying in that it doesn't guarantee to null-terminate
2117 // the result string. If the original string didn't fit entirely inside
2118 // the bound (including the null-terminator), we don't know how long the
2119 // result is.
2120 if (amountCopied != strLength)
2121 finalStrLength = UnknownVal();
2122 }
2123 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2124 }
2125
2126 assert(state);
2127
2128 if (returnPtr) {
2129 // If this is a stpcpy-style copy, but we were unable to check for a buffer
2130 // overflow, we still need a result. Conjure a return value.
2131 if (ReturnEnd && Result.isUnknown()) {
2132 Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
2133 C.blockCount());
2134 }
2135 }
2136 // Set the return value.
2137 state = state->BindExpr(Call.getOriginExpr(), LCtx, Result);
2138 C.addTransition(state);
2139}
2140
2141void CStringChecker::evalStrcmp(CheckerContext &C,
2142 const CallEvent &Call) const {
2143 //int strcmp(const char *s1, const char *s2);
2144 evalStrcmpCommon(C, Call, /* IsBounded = */ false, /* IgnoreCase = */ false);
2145}
2146
2147void CStringChecker::evalStrncmp(CheckerContext &C,
2148 const CallEvent &Call) const {
2149 //int strncmp(const char *s1, const char *s2, size_t n);
2150 evalStrcmpCommon(C, Call, /* IsBounded = */ true, /* IgnoreCase = */ false);
2151}
2152
2153void CStringChecker::evalStrcasecmp(CheckerContext &C,
2154 const CallEvent &Call) const {
2155 //int strcasecmp(const char *s1, const char *s2);
2156 evalStrcmpCommon(C, Call, /* IsBounded = */ false, /* IgnoreCase = */ true);
2157}
2158
2159void CStringChecker::evalStrncasecmp(CheckerContext &C,
2160 const CallEvent &Call) const {
2161 //int strncasecmp(const char *s1, const char *s2, size_t n);
2162 evalStrcmpCommon(C, Call, /* IsBounded = */ true, /* IgnoreCase = */ true);
2163}
2164
2165void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
2166 bool IsBounded, bool IgnoreCase) const {
2167 CurrentFunctionDescription = "string comparison function";
2168 ProgramStateRef state = C.getState();
2169 const LocationContext *LCtx = C.getLocationContext();
2170
2171 // Check that the first string is non-null
2172 AnyArgExpr Left = {Call.getArgExpr(0), 0};
2173 SVal LeftVal = state->getSVal(Left.Expression, LCtx);
2174 state = checkNonNull(C, state, Left, LeftVal);
2175 if (!state)
2176 return;
2177
2178 // Check that the second string is non-null.
2179 AnyArgExpr Right = {Call.getArgExpr(1), 1};
2180 SVal RightVal = state->getSVal(Right.Expression, LCtx);
2181 state = checkNonNull(C, state, Right, RightVal);
2182 if (!state)
2183 return;
2184
2185 // Get the string length of the first string or give up.
2186 SVal LeftLength = getCStringLength(C, state, Left.Expression, LeftVal);
2187 if (LeftLength.isUndef())
2188 return;
2189
2190 // Get the string length of the second string or give up.
2191 SVal RightLength = getCStringLength(C, state, Right.Expression, RightVal);
2192 if (RightLength.isUndef())
2193 return;
2194
2195 // If we know the two buffers are the same, we know the result is 0.
2196 // First, get the two buffers' addresses. Another checker will have already
2197 // made sure they're not undefined.
2200
2201 // See if they are the same.
2202 SValBuilder &svalBuilder = C.getSValBuilder();
2203 DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
2204 ProgramStateRef StSameBuf, StNotSameBuf;
2205 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2206
2207 // If the two arguments might be the same buffer, we know the result is 0,
2208 // and we only need to check one size.
2209 if (StSameBuf) {
2210 StSameBuf =
2211 StSameBuf->BindExpr(Call.getOriginExpr(), LCtx,
2212 svalBuilder.makeZeroVal(Call.getResultType()));
2213 C.addTransition(StSameBuf);
2214
2215 // If the two arguments are GUARANTEED to be the same, we're done!
2216 if (!StNotSameBuf)
2217 return;
2218 }
2219
2220 assert(StNotSameBuf);
2221 state = StNotSameBuf;
2222
2223 // At this point we can go about comparing the two buffers.
2224 // For now, we only do this if they're both known string literals.
2225
2226 // Attempt to extract string literals from both expressions.
2227 const StringLiteral *LeftStrLiteral =
2228 getCStringLiteral(C, state, Left.Expression, LeftVal);
2229 const StringLiteral *RightStrLiteral =
2230 getCStringLiteral(C, state, Right.Expression, RightVal);
2231 bool canComputeResult = false;
2232 SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
2233 LCtx, C.blockCount());
2234
2235 if (LeftStrLiteral && RightStrLiteral) {
2236 StringRef LeftStrRef = LeftStrLiteral->getString();
2237 StringRef RightStrRef = RightStrLiteral->getString();
2238
2239 if (IsBounded) {
2240 // Get the max number of characters to compare.
2241 const Expr *lenExpr = Call.getArgExpr(2);
2242 SVal lenVal = state->getSVal(lenExpr, LCtx);
2243
2244 // If the length is known, we can get the right substrings.
2245 if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2246 // Create substrings of each to compare the prefix.
2247 LeftStrRef = LeftStrRef.substr(0, (size_t)len->getZExtValue());
2248 RightStrRef = RightStrRef.substr(0, (size_t)len->getZExtValue());
2249 canComputeResult = true;
2250 }
2251 } else {
2252 // This is a normal, unbounded strcmp.
2253 canComputeResult = true;
2254 }
2255
2256 if (canComputeResult) {
2257 // Real strcmp stops at null characters.
2258 size_t s1Term = LeftStrRef.find('\0');
2259 if (s1Term != StringRef::npos)
2260 LeftStrRef = LeftStrRef.substr(0, s1Term);
2261
2262 size_t s2Term = RightStrRef.find('\0');
2263 if (s2Term != StringRef::npos)
2264 RightStrRef = RightStrRef.substr(0, s2Term);
2265
2266 // Use StringRef's comparison methods to compute the actual result.
2267 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2268 : LeftStrRef.compare(RightStrRef);
2269
2270 // The strcmp function returns an integer greater than, equal to, or less
2271 // than zero, [c11, p7.24.4.2].
2272 if (compareRes == 0) {
2273 resultVal = svalBuilder.makeIntVal(compareRes, Call.getResultType());
2274 }
2275 else {
2276 DefinedSVal zeroVal = svalBuilder.makeIntVal(0, Call.getResultType());
2277 // Constrain strcmp's result range based on the result of StringRef's
2278 // comparison methods.
2279 BinaryOperatorKind op = (compareRes > 0) ? BO_GT : BO_LT;
2280 SVal compareWithZero =
2281 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2282 svalBuilder.getConditionType());
2283 DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>();
2284 state = state->assume(compareWithZeroVal, true);
2285 }
2286 }
2287 }
2288
2289 state = state->BindExpr(Call.getOriginExpr(), LCtx, resultVal);
2290
2291 // Record this as a possible path.
2292 C.addTransition(state);
2293}
2294
2295void CStringChecker::evalStrsep(CheckerContext &C,
2296 const CallEvent &Call) const {
2297 // char *strsep(char **stringp, const char *delim);
2298 // Verify whether the search string parameter matches the return type.
2299 SourceArgExpr SearchStrPtr = {{Call.getArgExpr(0), 0}};
2300
2301 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2302 if (CharPtrTy.isNull() || Call.getResultType().getUnqualifiedType() !=
2303 CharPtrTy.getUnqualifiedType())
2304 return;
2305
2306 CurrentFunctionDescription = "strsep()";
2307 ProgramStateRef State = C.getState();
2308 const LocationContext *LCtx = C.getLocationContext();
2309
2310 // Check that the search string pointer is non-null (though it may point to
2311 // a null string).
2312 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2313 State = checkNonNull(C, State, SearchStrPtr, SearchStrVal);
2314 if (!State)
2315 return;
2316
2317 // Check that the delimiter string is non-null.
2318 AnyArgExpr DelimStr = {Call.getArgExpr(1), 1};
2319 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2320 State = checkNonNull(C, State, DelimStr, DelimStrVal);
2321 if (!State)
2322 return;
2323
2324 SValBuilder &SVB = C.getSValBuilder();
2325 SVal Result;
2326 if (std::optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
2327 // Get the current value of the search string pointer, as a char*.
2328 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2329
2330 // Invalidate the search string, representing the change of one delimiter
2331 // character to NUL.
2332 // As the replacement never overflows, do not invalidate its super region.
2333 State = invalidateDestinationBufferNeverOverflows(
2334 C, State, SearchStrPtr.Expression, Result);
2335
2336 // Overwrite the search string pointer. The new value is either an address
2337 // further along in the same string, or NULL if there are no more tokens.
2338 State =
2339 State->bindLoc(*SearchStrLoc,
2340 SVB.conjureSymbolVal(getTag(), Call.getOriginExpr(),
2341 LCtx, CharPtrTy, C.blockCount()),
2342 LCtx);
2343 } else {
2344 assert(SearchStrVal.isUnknown());
2345 // Conjure a symbolic value. It's the best we can do.
2346 Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
2347 C.blockCount());
2348 }
2349
2350 // Set the return value, and finish.
2351 State = State->BindExpr(Call.getOriginExpr(), LCtx, Result);
2352 C.addTransition(State);
2353}
2354
2355// These should probably be moved into a C++ standard library checker.
2356void CStringChecker::evalStdCopy(CheckerContext &C,
2357 const CallEvent &Call) const {
2358 evalStdCopyCommon(C, Call);
2359}
2360
2361void CStringChecker::evalStdCopyBackward(CheckerContext &C,
2362 const CallEvent &Call) const {
2363 evalStdCopyCommon(C, Call);
2364}
2365
2366void CStringChecker::evalStdCopyCommon(CheckerContext &C,
2367 const CallEvent &Call) const {
2368 if (!Call.getArgExpr(2)->getType()->isPointerType())
2369 return;
2370
2371 ProgramStateRef State = C.getState();
2372
2373 const LocationContext *LCtx = C.getLocationContext();
2374
2375 // template <class _InputIterator, class _OutputIterator>
2376 // _OutputIterator
2377 // copy(_InputIterator __first, _InputIterator __last,
2378 // _OutputIterator __result)
2379
2380 // Invalidate the destination buffer
2381 const Expr *Dst = Call.getArgExpr(2);
2382 SVal DstVal = State->getSVal(Dst, LCtx);
2383 // FIXME: As we do not know how many items are copied, we also invalidate the
2384 // super region containing the target location.
2385 State =
2386 invalidateDestinationBufferAlwaysEscapeSuperRegion(C, State, Dst, DstVal);
2387
2388 SValBuilder &SVB = C.getSValBuilder();
2389
2390 SVal ResultVal =
2391 SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
2392 State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);
2393
2394 C.addTransition(State);
2395}
2396
2397void CStringChecker::evalMemset(CheckerContext &C,
2398 const CallEvent &Call) const {
2399 // void *memset(void *s, int c, size_t n);
2400 CurrentFunctionDescription = "memory set function";
2401
2402 DestinationArgExpr Buffer = {{Call.getArgExpr(0), 0}};
2403 AnyArgExpr CharE = {Call.getArgExpr(1), 1};
2404 SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
2405
2406 ProgramStateRef State = C.getState();
2407
2408 // See if the size argument is zero.
2409 const LocationContext *LCtx = C.getLocationContext();
2410 SVal SizeVal = C.getSVal(Size.Expression);
2411 QualType SizeTy = Size.Expression->getType();
2412
2413 ProgramStateRef ZeroSize, NonZeroSize;
2414 std::tie(ZeroSize, NonZeroSize) = assumeZero(C, State, SizeVal, SizeTy);
2415
2416 // Get the value of the memory area.
2417 SVal BufferPtrVal = C.getSVal(Buffer.Expression);
2418
2419 // If the size is zero, there won't be any actual memory access, so
2420 // just bind the return value to the buffer and return.
2421 if (ZeroSize && !NonZeroSize) {
2422 ZeroSize = ZeroSize->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
2423 C.addTransition(ZeroSize);
2424 return;
2425 }
2426
2427 // Ensure the memory area is not null.
2428 // If it is NULL there will be a NULL pointer dereference.
2429 State = checkNonNull(C, NonZeroSize, Buffer, BufferPtrVal);
2430 if (!State)
2431 return;
2432
2433 State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write);
2434 if (!State)
2435 return;
2436
2437 // According to the values of the arguments, bind the value of the second
2438 // argument to the destination buffer and set string length, or just
2439 // invalidate the destination buffer.
2440 if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression),
2441 Size.Expression, C, State))
2442 return;
2443
2444 State = State->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
2445 C.addTransition(State);
2446}
2447
2448void CStringChecker::evalBzero(CheckerContext &C, const CallEvent &Call) const {
2449 CurrentFunctionDescription = "memory clearance function";
2450
2451 DestinationArgExpr Buffer = {{Call.getArgExpr(0), 0}};
2452 SizeArgExpr Size = {{Call.getArgExpr(1), 1}};
2453 SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy);
2454
2455 ProgramStateRef State = C.getState();
2456
2457 // See if the size argument is zero.
2458 SVal SizeVal = C.getSVal(Size.Expression);
2459 QualType SizeTy = Size.Expression->getType();
2460
2461 ProgramStateRef StateZeroSize, StateNonZeroSize;
2462 std::tie(StateZeroSize, StateNonZeroSize) =
2463 assumeZero(C, State, SizeVal, SizeTy);
2464
2465 // If the size is zero, there won't be any actual memory access,
2466 // In this case we just return.
2467 if (StateZeroSize && !StateNonZeroSize) {
2468 C.addTransition(StateZeroSize);
2469 return;
2470 }
2471
2472 // Get the value of the memory area.
2473 SVal MemVal = C.getSVal(Buffer.Expression);
2474
2475 // Ensure the memory area is not null.
2476 // If it is NULL there will be a NULL pointer dereference.
2477 State = checkNonNull(C, StateNonZeroSize, Buffer, MemVal);
2478 if (!State)
2479 return;
2480
2481 State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write);
2482 if (!State)
2483 return;
2484
2485 if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State))
2486 return;
2487
2488 C.addTransition(State);
2489}
2490
2491void CStringChecker::evalSprintf(CheckerContext &C,
2492 const CallEvent &Call) const {
2493 CurrentFunctionDescription = "'sprintf'";
2494 evalSprintfCommon(C, Call, /* IsBounded = */ false);
2495}
2496
2497void CStringChecker::evalSnprintf(CheckerContext &C,
2498 const CallEvent &Call) const {
2499 CurrentFunctionDescription = "'snprintf'";
2500 evalSprintfCommon(C, Call, /* IsBounded = */ true);
2501}
2502
2503void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallEvent &Call,
2504 bool IsBounded) const {
2505 ProgramStateRef State = C.getState();
2506 const auto *CE = cast<CallExpr>(Call.getOriginExpr());
2507 DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
2508
2509 const auto NumParams = Call.parameters().size();
2510 if (CE->getNumArgs() < NumParams) {
2511 // This is an invalid call, let's just ignore it.
2512 return;
2513 }
2514
2515 const auto AllArguments =
2516 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2517 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2518
2519 for (const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2520 // We consider only string buffers
2521 if (const QualType type = ArgExpr->getType();
2522 !type->isAnyPointerType() ||
2523 !type->getPointeeType()->isAnyCharacterType())
2524 continue;
2525 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
2526
2527 // Ensure the buffers do not overlap.
2528 SizeArgExpr SrcExprAsSizeDummy = {
2529 {Source.Expression, Source.ArgumentIndex}};
2530 State = CheckOverlap(
2531 C, State,
2532 (IsBounded ? SizeArgExpr{{Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2533 Dest, Source);
2534 if (!State)
2535 return;
2536 }
2537
2538 C.addTransition(State);
2539}
2540
2541//===----------------------------------------------------------------------===//
2542// The driver method, and other Checker callbacks.
2543//===----------------------------------------------------------------------===//
2544
2545CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call,
2546 CheckerContext &C) const {
2547 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
2548 if (!CE)
2549 return nullptr;
2550
2551 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
2552 if (!FD)
2553 return nullptr;
2554
2555 if (StdCopy.matches(Call))
2556 return &CStringChecker::evalStdCopy;
2557 if (StdCopyBackward.matches(Call))
2558 return &CStringChecker::evalStdCopyBackward;
2559
2560 // Pro-actively check that argument types are safe to do arithmetic upon.
2561 // We do not want to crash if someone accidentally passes a structure
2562 // into, say, a C++ overload of any of these functions. We could not check
2563 // that for std::copy because they may have arguments of other types.
2564 for (auto I : CE->arguments()) {
2565 QualType T = I->getType();
2567 return nullptr;
2568 }
2569
2570 const FnCheck *Callback = Callbacks.lookup(Call);
2571 if (Callback)
2572 return *Callback;
2573
2574 return nullptr;
2575}
2576
2577bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
2578 FnCheck Callback = identifyCall(Call, C);
2579
2580 // If the callee isn't a string function, let another checker handle it.
2581 if (!Callback)
2582 return false;
2583
2584 // Check and evaluate the call.
2585 assert(isa<CallExpr>(Call.getOriginExpr()));
2586 Callback(this, C, Call);
2587
2588 // If the evaluate call resulted in no change, chain to the next eval call
2589 // handler.
2590 // Note, the custom CString evaluation calls assume that basic safety
2591 // properties are held. However, if the user chooses to turn off some of these
2592 // checks, we ignore the issues and leave the call evaluation to a generic
2593 // handler.
2594 return C.isDifferent();
2595}
2596
2597void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
2598 // Record string length for char a[] = "abc";
2599 ProgramStateRef state = C.getState();
2600
2601 for (const auto *I : DS->decls()) {
2602 const VarDecl *D = dyn_cast<VarDecl>(I);
2603 if (!D)
2604 continue;
2605
2606 // FIXME: Handle array fields of structs.
2607 if (!D->getType()->isArrayType())
2608 continue;
2609
2610 const Expr *Init = D->getInit();
2611 if (!Init)
2612 continue;
2613 if (!isa<StringLiteral>(Init))
2614 continue;
2615
2616 Loc VarLoc = state->getLValue(D, C.getLocationContext());
2617 const MemRegion *MR = VarLoc.getAsRegion();
2618 if (!MR)
2619 continue;
2620
2621 SVal StrVal = C.getSVal(Init);
2622 assert(StrVal.isValid() && "Initializer string is unknown or undefined");
2623 DefinedOrUnknownSVal strLength =
2624 getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>();
2625
2626 state = state->set<CStringLength>(MR, strLength);
2627 }
2628
2629 C.addTransition(state);
2630}
2631
2633CStringChecker::checkRegionChanges(ProgramStateRef state,
2634 const InvalidatedSymbols *,
2635 ArrayRef<const MemRegion *> ExplicitRegions,
2637 const LocationContext *LCtx,
2638 const CallEvent *Call) const {
2639 CStringLengthTy Entries = state->get<CStringLength>();
2640 if (Entries.isEmpty())
2641 return state;
2642
2645
2646 // First build sets for the changed regions and their super-regions.
2647 for (const MemRegion *MR : Regions) {
2648 Invalidated.insert(MR);
2649
2650 SuperRegions.insert(MR);
2651 while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2652 MR = SR->getSuperRegion();
2653 SuperRegions.insert(MR);
2654 }
2655 }
2656
2657 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2658
2659 // Then loop over the entries in the current state.
2660 for (const MemRegion *MR : llvm::make_first_range(Entries)) {
2661 // Is this entry for a super-region of a changed region?
2662 if (SuperRegions.count(MR)) {
2663 Entries = F.remove(Entries, MR);
2664 continue;
2665 }
2666
2667 // Is this entry for a sub-region of a changed region?
2668 const MemRegion *Super = MR;
2669 while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2670 Super = SR->getSuperRegion();
2671 if (Invalidated.count(Super)) {
2672 Entries = F.remove(Entries, MR);
2673 break;
2674 }
2675 }
2676 }
2677
2678 return state->set<CStringLength>(Entries);
2679}
2680
2681void CStringChecker::checkLiveSymbols(ProgramStateRef state,
2682 SymbolReaper &SR) const {
2683 // Mark all symbols in our string length map as valid.
2684 CStringLengthTy Entries = state->get<CStringLength>();
2685
2686 for (SVal Len : llvm::make_second_range(Entries)) {
2687 for (SymbolRef Sym : Len.symbols())
2688 SR.markInUse(Sym);
2689 }
2690}
2691
2692void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2693 CheckerContext &C) const {
2694 ProgramStateRef state = C.getState();
2695 CStringLengthTy Entries = state->get<CStringLength>();
2696 if (Entries.isEmpty())
2697 return;
2698
2699 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2700 for (auto [Reg, Len] : Entries) {
2701 if (SymbolRef Sym = Len.getAsSymbol()) {
2702 if (SR.isDead(Sym))
2703 Entries = F.remove(Entries, Reg);
2704 }
2705 }
2706
2707 state = state->set<CStringLength>(Entries);
2708 C.addTransition(state);
2709}
2710
2711void ento::registerCStringModeling(CheckerManager &Mgr) {
2712 Mgr.registerChecker<CStringChecker>();
2713}
2714
2715bool ento::shouldRegisterCStringModeling(const CheckerManager &mgr) {
2716 return true;
2717}
2718
2719#define REGISTER_CHECKER(name) \
2720 void ento::register##name(CheckerManager &mgr) { \
2721 CStringChecker *checker = mgr.getChecker<CStringChecker>(); \
2722 checker->Filter.Check##name = true; \
2723 checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \
2724 } \
2725 \
2726 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
2727
2728REGISTER_CHECKER(CStringNullArg)
2729REGISTER_CHECKER(CStringOutOfBounds)
2730REGISTER_CHECKER(CStringBufferOverlap)
2731REGISTER_CHECKER(CStringNotNullTerm)
2732REGISTER_CHECKER(CStringUninitializedRead)
#define V(N, I)
Definition: ASTContext.h:3285
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:86
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:940
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:1007
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:7453
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:7678
bool isPointerType() const
Definition: Type.h:7612
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:8020
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:1873
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