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