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