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