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