xref: /freebsd-src/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //= CStringChecker.cpp - Checks calls to C string functions --------*- C++ -*-//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This defines CStringChecker, which is an assortment of checks on calls
100b57cec5SDimitry Andric // to functions in <string.h>.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "InterCheckerAPI.h"
15*0fca6ea1SDimitry Andric #include "clang/AST/OperationKinds.h"
1606c3fb27SDimitry Andric #include "clang/Basic/Builtins.h"
170b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h"
185ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
190b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
210b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
22349cc55cSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
230b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
240b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
25fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h"
26*0fca6ea1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
270b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
28*0fca6ea1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
29*0fca6ea1SDimitry Andric #include "llvm/ADT/APSInt.h"
300b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
315ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h"
32*0fca6ea1SDimitry Andric #include "llvm/Support/Casting.h"
330b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
34972a253aSDimitry Andric #include <functional>
35bdd1243dSDimitry Andric #include <optional>
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric using namespace clang;
380b57cec5SDimitry Andric using namespace ento;
39972a253aSDimitry Andric using namespace std::placeholders;
400b57cec5SDimitry Andric 
410b57cec5SDimitry Andric namespace {
425ffd83dbSDimitry Andric struct AnyArgExpr {
435ffd83dbSDimitry Andric   const Expr *Expression;
445ffd83dbSDimitry Andric   unsigned ArgumentIndex;
455ffd83dbSDimitry Andric };
4606c3fb27SDimitry Andric struct SourceArgExpr : AnyArgExpr {};
4706c3fb27SDimitry Andric struct DestinationArgExpr : AnyArgExpr {};
4806c3fb27SDimitry Andric struct SizeArgExpr : AnyArgExpr {};
495ffd83dbSDimitry Andric 
505ffd83dbSDimitry Andric using ErrorMessage = SmallString<128>;
515ffd83dbSDimitry Andric enum class AccessKind { write, read };
525ffd83dbSDimitry Andric 
535ffd83dbSDimitry Andric static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
545ffd83dbSDimitry Andric                                              AccessKind Access) {
555ffd83dbSDimitry Andric   ErrorMessage Message;
565ffd83dbSDimitry Andric   llvm::raw_svector_ostream Os(Message);
575ffd83dbSDimitry Andric 
585ffd83dbSDimitry Andric   // Function classification like: Memory copy function
595ffd83dbSDimitry Andric   Os << toUppercase(FunctionDescription.front())
605ffd83dbSDimitry Andric      << &FunctionDescription.data()[1];
615ffd83dbSDimitry Andric 
625ffd83dbSDimitry Andric   if (Access == AccessKind::write) {
635ffd83dbSDimitry Andric     Os << " overflows the destination buffer";
645ffd83dbSDimitry Andric   } else { // read access
655ffd83dbSDimitry Andric     Os << " accesses out-of-bound array element";
665ffd83dbSDimitry Andric   }
675ffd83dbSDimitry Andric 
685ffd83dbSDimitry Andric   return Message;
695ffd83dbSDimitry Andric }
705ffd83dbSDimitry Andric 
71480093f4SDimitry Andric enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
72bdd1243dSDimitry Andric 
73bdd1243dSDimitry Andric enum class CharKind { Regular = 0, Wide };
74bdd1243dSDimitry Andric constexpr CharKind CK_Regular = CharKind::Regular;
75bdd1243dSDimitry Andric constexpr CharKind CK_Wide = CharKind::Wide;
76bdd1243dSDimitry Andric 
77bdd1243dSDimitry Andric static QualType getCharPtrType(ASTContext &Ctx, CharKind CK) {
78bdd1243dSDimitry Andric   return Ctx.getPointerType(CK == CharKind::Regular ? Ctx.CharTy
79bdd1243dSDimitry Andric                                                     : Ctx.WideCharTy);
80bdd1243dSDimitry Andric }
81bdd1243dSDimitry Andric 
820b57cec5SDimitry Andric class CStringChecker : public Checker< eval::Call,
830b57cec5SDimitry Andric                                          check::PreStmt<DeclStmt>,
840b57cec5SDimitry Andric                                          check::LiveSymbols,
850b57cec5SDimitry Andric                                          check::DeadSymbols,
860b57cec5SDimitry Andric                                          check::RegionChanges
870b57cec5SDimitry Andric                                          > {
880b57cec5SDimitry Andric   mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
8981ad6265SDimitry Andric       BT_NotCString, BT_AdditionOverflow, BT_UninitRead;
900b57cec5SDimitry Andric 
9106c3fb27SDimitry Andric   mutable const char *CurrentFunctionDescription = nullptr;
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric public:
940b57cec5SDimitry Andric   /// The filter is used to filter out the diagnostics which are not enabled by
950b57cec5SDimitry Andric   /// the user.
960b57cec5SDimitry Andric   struct CStringChecksFilter {
9781ad6265SDimitry Andric     bool CheckCStringNullArg = false;
9881ad6265SDimitry Andric     bool CheckCStringOutOfBounds = false;
9981ad6265SDimitry Andric     bool CheckCStringBufferOverlap = false;
10081ad6265SDimitry Andric     bool CheckCStringNotNullTerm = false;
10181ad6265SDimitry Andric     bool CheckCStringUninitializedRead = false;
1020b57cec5SDimitry Andric 
103a7dea167SDimitry Andric     CheckerNameRef CheckNameCStringNullArg;
104a7dea167SDimitry Andric     CheckerNameRef CheckNameCStringOutOfBounds;
105a7dea167SDimitry Andric     CheckerNameRef CheckNameCStringBufferOverlap;
106a7dea167SDimitry Andric     CheckerNameRef CheckNameCStringNotNullTerm;
10781ad6265SDimitry Andric     CheckerNameRef CheckNameCStringUninitializedRead;
1080b57cec5SDimitry Andric   };
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   CStringChecksFilter Filter;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   static void *getTag() { static int tag; return &tag; }
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   bool evalCall(const CallEvent &Call, CheckerContext &C) const;
1150b57cec5SDimitry Andric   void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const;
1160b57cec5SDimitry Andric   void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const;
1170b57cec5SDimitry Andric   void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   ProgramStateRef
1200b57cec5SDimitry Andric     checkRegionChanges(ProgramStateRef state,
1210b57cec5SDimitry Andric                        const InvalidatedSymbols *,
1220b57cec5SDimitry Andric                        ArrayRef<const MemRegion *> ExplicitRegions,
1230b57cec5SDimitry Andric                        ArrayRef<const MemRegion *> Regions,
1240b57cec5SDimitry Andric                        const LocationContext *LCtx,
1250b57cec5SDimitry Andric                        const CallEvent *Call) const;
1260b57cec5SDimitry Andric 
127972a253aSDimitry Andric   using FnCheck = std::function<void(const CStringChecker *, CheckerContext &,
128647cbc5dSDimitry Andric                                      const CallEvent &)>;
129972a253aSDimitry Andric 
1300b57cec5SDimitry Andric   CallDescriptionMap<FnCheck> Callbacks = {
131*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"memcpy"}, 3},
132bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Regular)},
133*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"wmemcpy"}, 3},
134bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMemcpy, _1, _2, _3, CK_Wide)},
135*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"mempcpy"}, 3},
136bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Regular)},
137*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"wmempcpy"}, 3},
138bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMempcpy, _1, _2, _3, CK_Wide)},
139*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"memcmp"}, 3},
140bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
141*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"wmemcmp"}, 3},
142bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Wide)},
143*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"memmove"}, 3},
144bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Regular)},
145*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"wmemmove"}, 3},
146bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMemmove, _1, _2, _3, CK_Wide)},
147*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"memset"}, 3},
148*0fca6ea1SDimitry Andric        &CStringChecker::evalMemset},
149*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"explicit_memset"}, 3}, &CStringChecker::evalMemset},
150*0fca6ea1SDimitry Andric       // FIXME: C23 introduces 'memset_explicit', maybe also model that
151*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"strcpy"}, 2},
152*0fca6ea1SDimitry Andric        &CStringChecker::evalStrcpy},
153*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"strncpy"}, 3},
154*0fca6ea1SDimitry Andric        &CStringChecker::evalStrncpy},
155*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"stpcpy"}, 2},
156*0fca6ea1SDimitry Andric        &CStringChecker::evalStpcpy},
157*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"strlcpy"}, 3},
158*0fca6ea1SDimitry Andric        &CStringChecker::evalStrlcpy},
159*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"strcat"}, 2},
160*0fca6ea1SDimitry Andric        &CStringChecker::evalStrcat},
161*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"strncat"}, 3},
162*0fca6ea1SDimitry Andric        &CStringChecker::evalStrncat},
163*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"strlcat"}, 3},
164*0fca6ea1SDimitry Andric        &CStringChecker::evalStrlcat},
165*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"strlen"}, 1},
166*0fca6ea1SDimitry Andric        &CStringChecker::evalstrLength},
167*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"wcslen"}, 1}, &CStringChecker::evalstrLength},
168*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"strnlen"}, 2},
169*0fca6ea1SDimitry Andric        &CStringChecker::evalstrnLength},
170*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
171*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"strcmp"}, 2}, &CStringChecker::evalStrcmp},
172*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"strncmp"}, 3}, &CStringChecker::evalStrncmp},
173*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
174*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
175*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"strsep"}, 2}, &CStringChecker::evalStrsep},
176*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"bcopy"}, 3}, &CStringChecker::evalBcopy},
177*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"bcmp"}, 3},
178bdd1243dSDimitry Andric        std::bind(&CStringChecker::evalMemcmp, _1, _2, _3, CK_Regular)},
179*0fca6ea1SDimitry Andric       {{CDM::CLibrary, {"bzero"}, 2}, &CStringChecker::evalBzero},
180*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"explicit_bzero"}, 2},
181*0fca6ea1SDimitry Andric        &CStringChecker::evalBzero},
182*0fca6ea1SDimitry Andric 
183*0fca6ea1SDimitry Andric       // When recognizing calls to the following variadic functions, we accept
184*0fca6ea1SDimitry Andric       // any number of arguments in the call (std::nullopt = accept any
185*0fca6ea1SDimitry Andric       // number), but check that in the declaration there are 2 and 3
186*0fca6ea1SDimitry Andric       // parameters respectively. (Note that the parameter count does not
187*0fca6ea1SDimitry Andric       // include the "...". Calls where the number of arguments is too small
188*0fca6ea1SDimitry Andric       // will be discarded by the callback.)
189*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"sprintf"}, std::nullopt, 2},
190*0fca6ea1SDimitry Andric        &CStringChecker::evalSprintf},
191*0fca6ea1SDimitry Andric       {{CDM::CLibraryMaybeHardened, {"snprintf"}, std::nullopt, 3},
192*0fca6ea1SDimitry Andric        &CStringChecker::evalSnprintf},
1930b57cec5SDimitry Andric   };
1940b57cec5SDimitry Andric 
1950b57cec5SDimitry Andric   // These require a bit of special handling.
196*0fca6ea1SDimitry Andric   CallDescription StdCopy{CDM::SimpleFunc, {"std", "copy"}, 3},
197*0fca6ea1SDimitry Andric       StdCopyBackward{CDM::SimpleFunc, {"std", "copy_backward"}, 3};
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const;
200647cbc5dSDimitry Andric   void evalMemcpy(CheckerContext &C, const CallEvent &Call, CharKind CK) const;
201647cbc5dSDimitry Andric   void evalMempcpy(CheckerContext &C, const CallEvent &Call, CharKind CK) const;
202647cbc5dSDimitry Andric   void evalMemmove(CheckerContext &C, const CallEvent &Call, CharKind CK) const;
203647cbc5dSDimitry Andric   void evalBcopy(CheckerContext &C, const CallEvent &Call) const;
204647cbc5dSDimitry Andric   void evalCopyCommon(CheckerContext &C, const CallEvent &Call,
2055ffd83dbSDimitry Andric                       ProgramStateRef state, SizeArgExpr Size,
2065ffd83dbSDimitry Andric                       DestinationArgExpr Dest, SourceArgExpr Source,
207bdd1243dSDimitry Andric                       bool Restricted, bool IsMempcpy, CharKind CK) const;
2080b57cec5SDimitry Andric 
209647cbc5dSDimitry Andric   void evalMemcmp(CheckerContext &C, const CallEvent &Call, CharKind CK) const;
2100b57cec5SDimitry Andric 
211647cbc5dSDimitry Andric   void evalstrLength(CheckerContext &C, const CallEvent &Call) const;
212647cbc5dSDimitry Andric   void evalstrnLength(CheckerContext &C, const CallEvent &Call) const;
213647cbc5dSDimitry Andric   void evalstrLengthCommon(CheckerContext &C, const CallEvent &Call,
2140b57cec5SDimitry Andric                            bool IsStrnlen = false) const;
2150b57cec5SDimitry Andric 
216647cbc5dSDimitry Andric   void evalStrcpy(CheckerContext &C, const CallEvent &Call) const;
217647cbc5dSDimitry Andric   void evalStrncpy(CheckerContext &C, const CallEvent &Call) const;
218647cbc5dSDimitry Andric   void evalStpcpy(CheckerContext &C, const CallEvent &Call) const;
219647cbc5dSDimitry Andric   void evalStrlcpy(CheckerContext &C, const CallEvent &Call) const;
220647cbc5dSDimitry Andric   void evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
221647cbc5dSDimitry Andric                         bool ReturnEnd, bool IsBounded, ConcatFnKind appendK,
2220b57cec5SDimitry Andric                         bool returnPtr = true) const;
2230b57cec5SDimitry Andric 
224647cbc5dSDimitry Andric   void evalStrcat(CheckerContext &C, const CallEvent &Call) const;
225647cbc5dSDimitry Andric   void evalStrncat(CheckerContext &C, const CallEvent &Call) const;
226647cbc5dSDimitry Andric   void evalStrlcat(CheckerContext &C, const CallEvent &Call) const;
2270b57cec5SDimitry Andric 
228647cbc5dSDimitry Andric   void evalStrcmp(CheckerContext &C, const CallEvent &Call) const;
229647cbc5dSDimitry Andric   void evalStrncmp(CheckerContext &C, const CallEvent &Call) const;
230647cbc5dSDimitry Andric   void evalStrcasecmp(CheckerContext &C, const CallEvent &Call) const;
231647cbc5dSDimitry Andric   void evalStrncasecmp(CheckerContext &C, const CallEvent &Call) const;
232647cbc5dSDimitry Andric   void evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
233647cbc5dSDimitry Andric                         bool IsBounded = false, bool IgnoreCase = false) const;
2340b57cec5SDimitry Andric 
235647cbc5dSDimitry Andric   void evalStrsep(CheckerContext &C, const CallEvent &Call) const;
2360b57cec5SDimitry Andric 
237647cbc5dSDimitry Andric   void evalStdCopy(CheckerContext &C, const CallEvent &Call) const;
238647cbc5dSDimitry Andric   void evalStdCopyBackward(CheckerContext &C, const CallEvent &Call) const;
239647cbc5dSDimitry Andric   void evalStdCopyCommon(CheckerContext &C, const CallEvent &Call) const;
240647cbc5dSDimitry Andric   void evalMemset(CheckerContext &C, const CallEvent &Call) const;
241647cbc5dSDimitry Andric   void evalBzero(CheckerContext &C, const CallEvent &Call) const;
2420b57cec5SDimitry Andric 
243647cbc5dSDimitry Andric   void evalSprintf(CheckerContext &C, const CallEvent &Call) const;
244647cbc5dSDimitry Andric   void evalSnprintf(CheckerContext &C, const CallEvent &Call) const;
245647cbc5dSDimitry Andric   void evalSprintfCommon(CheckerContext &C, const CallEvent &Call,
246*0fca6ea1SDimitry Andric                          bool IsBounded) const;
24706c3fb27SDimitry Andric 
2480b57cec5SDimitry Andric   // Utility methods
2490b57cec5SDimitry Andric   std::pair<ProgramStateRef , ProgramStateRef >
2500b57cec5SDimitry Andric   static assumeZero(CheckerContext &C,
2510b57cec5SDimitry Andric                     ProgramStateRef state, SVal V, QualType Ty);
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   static ProgramStateRef setCStringLength(ProgramStateRef state,
2540b57cec5SDimitry Andric                                               const MemRegion *MR,
2550b57cec5SDimitry Andric                                               SVal strLength);
2560b57cec5SDimitry Andric   static SVal getCStringLengthForRegion(CheckerContext &C,
2570b57cec5SDimitry Andric                                         ProgramStateRef &state,
2580b57cec5SDimitry Andric                                         const Expr *Ex,
2590b57cec5SDimitry Andric                                         const MemRegion *MR,
2600b57cec5SDimitry Andric                                         bool hypothetical);
2610b57cec5SDimitry Andric   SVal getCStringLength(CheckerContext &C,
2620b57cec5SDimitry Andric                         ProgramStateRef &state,
2630b57cec5SDimitry Andric                         const Expr *Ex,
2640b57cec5SDimitry Andric                         SVal Buf,
2650b57cec5SDimitry Andric                         bool hypothetical = false) const;
2660b57cec5SDimitry Andric 
2670b57cec5SDimitry Andric   const StringLiteral *getCStringLiteral(CheckerContext &C,
2680b57cec5SDimitry Andric                                          ProgramStateRef &state,
2690b57cec5SDimitry Andric                                          const Expr *expr,
2700b57cec5SDimitry Andric                                          SVal val) const;
2710b57cec5SDimitry Andric 
27206c3fb27SDimitry Andric   /// Invalidate the destination buffer determined by characters copied.
27306c3fb27SDimitry Andric   static ProgramStateRef
27406c3fb27SDimitry Andric   invalidateDestinationBufferBySize(CheckerContext &C, ProgramStateRef S,
27506c3fb27SDimitry Andric                                     const Expr *BufE, SVal BufV, SVal SizeV,
27606c3fb27SDimitry Andric                                     QualType SizeTy);
27706c3fb27SDimitry Andric 
27806c3fb27SDimitry Andric   /// Operation never overflows, do not invalidate the super region.
27906c3fb27SDimitry Andric   static ProgramStateRef invalidateDestinationBufferNeverOverflows(
28006c3fb27SDimitry Andric       CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV);
28106c3fb27SDimitry Andric 
28206c3fb27SDimitry Andric   /// We do not know whether the operation can overflow (e.g. size is unknown),
28306c3fb27SDimitry Andric   /// invalidate the super region and escape related pointers.
28406c3fb27SDimitry Andric   static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
28506c3fb27SDimitry Andric       CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV);
28606c3fb27SDimitry Andric 
28706c3fb27SDimitry Andric   /// Invalidate the source buffer for escaping pointers.
28806c3fb27SDimitry Andric   static ProgramStateRef invalidateSourceBuffer(CheckerContext &C,
28906c3fb27SDimitry Andric                                                 ProgramStateRef S,
29006c3fb27SDimitry Andric                                                 const Expr *BufE, SVal BufV);
29106c3fb27SDimitry Andric 
29206c3fb27SDimitry Andric   /// @param InvalidationTraitOperations Determine how to invlidate the
29306c3fb27SDimitry Andric   /// MemRegion by setting the invalidation traits. Return true to cause pointer
29406c3fb27SDimitry Andric   /// escape, or false otherwise.
29506c3fb27SDimitry Andric   static ProgramStateRef invalidateBufferAux(
29606c3fb27SDimitry Andric       CheckerContext &C, ProgramStateRef State, const Expr *Ex, SVal V,
29706c3fb27SDimitry Andric       llvm::function_ref<bool(RegionAndSymbolInvalidationTraits &,
29806c3fb27SDimitry Andric                               const MemRegion *)>
29906c3fb27SDimitry Andric           InvalidationTraitOperations);
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric   static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
3020b57cec5SDimitry Andric                               const MemRegion *MR);
3030b57cec5SDimitry Andric 
3040b57cec5SDimitry Andric   static bool memsetAux(const Expr *DstBuffer, SVal CharE,
3050b57cec5SDimitry Andric                         const Expr *Size, CheckerContext &C,
3060b57cec5SDimitry Andric                         ProgramStateRef &State);
3070b57cec5SDimitry Andric 
3080b57cec5SDimitry Andric   // Re-usable checks
3095ffd83dbSDimitry Andric   ProgramStateRef checkNonNull(CheckerContext &C, ProgramStateRef State,
3105ffd83dbSDimitry Andric                                AnyArgExpr Arg, SVal l) const;
311*0fca6ea1SDimitry Andric   // Check whether the origin region behind \p Element (like the actual array
312*0fca6ea1SDimitry Andric   // region \p Element is from) is initialized.
313*0fca6ea1SDimitry Andric   ProgramStateRef checkInit(CheckerContext &C, ProgramStateRef state,
314*0fca6ea1SDimitry Andric                             AnyArgExpr Buffer, SVal Element, SVal Size) const;
3155ffd83dbSDimitry Andric   ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state,
3165ffd83dbSDimitry Andric                                 AnyArgExpr Buffer, SVal Element,
317bdd1243dSDimitry Andric                                 AccessKind Access,
318bdd1243dSDimitry Andric                                 CharKind CK = CharKind::Regular) const;
3195ffd83dbSDimitry Andric   ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
3205ffd83dbSDimitry Andric                                     AnyArgExpr Buffer, SizeArgExpr Size,
321972a253aSDimitry Andric                                     AccessKind Access,
322bdd1243dSDimitry Andric                                     CharKind CK = CharKind::Regular) const;
3235ffd83dbSDimitry Andric   ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state,
3245ffd83dbSDimitry Andric                                SizeArgExpr Size, AnyArgExpr First,
325bdd1243dSDimitry Andric                                AnyArgExpr Second,
326bdd1243dSDimitry Andric                                CharKind CK = CharKind::Regular) const;
3270b57cec5SDimitry Andric   void emitOverlapBug(CheckerContext &C,
3280b57cec5SDimitry Andric                       ProgramStateRef state,
3290b57cec5SDimitry Andric                       const Stmt *First,
3300b57cec5SDimitry Andric                       const Stmt *Second) const;
3310b57cec5SDimitry Andric 
3320b57cec5SDimitry Andric   void emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S,
3330b57cec5SDimitry Andric                       StringRef WarningMsg) const;
3340b57cec5SDimitry Andric   void emitOutOfBoundsBug(CheckerContext &C, ProgramStateRef State,
3350b57cec5SDimitry Andric                           const Stmt *S, StringRef WarningMsg) const;
3360b57cec5SDimitry Andric   void emitNotCStringBug(CheckerContext &C, ProgramStateRef State,
3370b57cec5SDimitry Andric                          const Stmt *S, StringRef WarningMsg) const;
3380b57cec5SDimitry Andric   void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const;
33981ad6265SDimitry Andric   void emitUninitializedReadBug(CheckerContext &C, ProgramStateRef State,
340*0fca6ea1SDimitry Andric                                 const Expr *E, StringRef Msg) const;
3410b57cec5SDimitry Andric   ProgramStateRef checkAdditionOverflow(CheckerContext &C,
3420b57cec5SDimitry Andric                                             ProgramStateRef state,
3430b57cec5SDimitry Andric                                             NonLoc left,
3440b57cec5SDimitry Andric                                             NonLoc right) const;
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric   // Return true if the destination buffer of the copy function may be in bound.
3470b57cec5SDimitry Andric   // Expects SVal of Size to be positive and unsigned.
3480b57cec5SDimitry Andric   // Expects SVal of FirstBuf to be a FieldRegion.
34906c3fb27SDimitry Andric   static bool isFirstBufInBound(CheckerContext &C, ProgramStateRef State,
35006c3fb27SDimitry Andric                                 SVal BufVal, QualType BufTy, SVal LengthVal,
35106c3fb27SDimitry Andric                                 QualType LengthTy);
3520b57cec5SDimitry Andric };
3530b57cec5SDimitry Andric 
3540b57cec5SDimitry Andric } //end anonymous namespace
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal)
3570b57cec5SDimitry Andric 
3580b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3590b57cec5SDimitry Andric // Individual checks and utility methods.
3600b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric std::pair<ProgramStateRef, ProgramStateRef>
363*0fca6ea1SDimitry Andric CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef State, SVal V,
3640b57cec5SDimitry Andric                            QualType Ty) {
365bdd1243dSDimitry Andric   std::optional<DefinedSVal> val = V.getAs<DefinedSVal>();
3660b57cec5SDimitry Andric   if (!val)
367*0fca6ea1SDimitry Andric     return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   SValBuilder &svalBuilder = C.getSValBuilder();
3700b57cec5SDimitry Andric   DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
371*0fca6ea1SDimitry Andric   return State->assume(svalBuilder.evalEQ(State, *val, zero));
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C,
3755ffd83dbSDimitry Andric                                              ProgramStateRef State,
3765ffd83dbSDimitry Andric                                              AnyArgExpr Arg, SVal l) const {
3770b57cec5SDimitry Andric   // If a previous check has failed, propagate the failure.
3785ffd83dbSDimitry Andric   if (!State)
3790b57cec5SDimitry Andric     return nullptr;
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric   ProgramStateRef stateNull, stateNonNull;
3825ffd83dbSDimitry Andric   std::tie(stateNull, stateNonNull) =
3835ffd83dbSDimitry Andric       assumeZero(C, State, l, Arg.Expression->getType());
3840b57cec5SDimitry Andric 
3850b57cec5SDimitry Andric   if (stateNull && !stateNonNull) {
3860b57cec5SDimitry Andric     if (Filter.CheckCStringNullArg) {
3870b57cec5SDimitry Andric       SmallString<80> buf;
388a7dea167SDimitry Andric       llvm::raw_svector_ostream OS(buf);
3890b57cec5SDimitry Andric       assert(CurrentFunctionDescription);
3905ffd83dbSDimitry Andric       OS << "Null pointer passed as " << (Arg.ArgumentIndex + 1)
3915ffd83dbSDimitry Andric          << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) << " argument to "
392480093f4SDimitry Andric          << CurrentFunctionDescription;
3930b57cec5SDimitry Andric 
3945ffd83dbSDimitry Andric       emitNullArgBug(C, stateNull, Arg.Expression, OS.str());
3950b57cec5SDimitry Andric     }
3960b57cec5SDimitry Andric     return nullptr;
3970b57cec5SDimitry Andric   }
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric   // From here on, assume that the value is non-null.
4000b57cec5SDimitry Andric   assert(stateNonNull);
4010b57cec5SDimitry Andric   return stateNonNull;
4020b57cec5SDimitry Andric }
4030b57cec5SDimitry Andric 
404*0fca6ea1SDimitry Andric static std::optional<NonLoc> getIndex(ProgramStateRef State,
405*0fca6ea1SDimitry Andric                                       const ElementRegion *ER, CharKind CK) {
406*0fca6ea1SDimitry Andric   SValBuilder &SVB = State->getStateManager().getSValBuilder();
407*0fca6ea1SDimitry Andric   ASTContext &Ctx = SVB.getContext();
408*0fca6ea1SDimitry Andric 
409*0fca6ea1SDimitry Andric   if (CK == CharKind::Regular) {
410*0fca6ea1SDimitry Andric     if (ER->getValueType() != Ctx.CharTy)
411*0fca6ea1SDimitry Andric       return {};
412*0fca6ea1SDimitry Andric     return ER->getIndex();
413*0fca6ea1SDimitry Andric   }
414*0fca6ea1SDimitry Andric 
415*0fca6ea1SDimitry Andric   if (ER->getValueType() != Ctx.WideCharTy)
416*0fca6ea1SDimitry Andric     return {};
417*0fca6ea1SDimitry Andric 
418*0fca6ea1SDimitry Andric   QualType SizeTy = Ctx.getSizeType();
419*0fca6ea1SDimitry Andric   NonLoc WideSize =
420*0fca6ea1SDimitry Andric       SVB.makeIntVal(Ctx.getTypeSizeInChars(Ctx.WideCharTy).getQuantity(),
421*0fca6ea1SDimitry Andric                      SizeTy)
422*0fca6ea1SDimitry Andric           .castAs<NonLoc>();
423*0fca6ea1SDimitry Andric   SVal Offset =
424*0fca6ea1SDimitry Andric       SVB.evalBinOpNN(State, BO_Mul, ER->getIndex(), WideSize, SizeTy);
425*0fca6ea1SDimitry Andric   if (Offset.isUnknown())
426*0fca6ea1SDimitry Andric     return {};
427*0fca6ea1SDimitry Andric   return Offset.castAs<NonLoc>();
428*0fca6ea1SDimitry Andric }
429*0fca6ea1SDimitry Andric 
430*0fca6ea1SDimitry Andric // Basically 1 -> 1st, 12 -> 12th, etc.
431*0fca6ea1SDimitry Andric static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx) {
432*0fca6ea1SDimitry Andric   Os << Idx << llvm::getOrdinalSuffix(Idx);
433*0fca6ea1SDimitry Andric }
434*0fca6ea1SDimitry Andric 
435*0fca6ea1SDimitry Andric ProgramStateRef CStringChecker::checkInit(CheckerContext &C,
436*0fca6ea1SDimitry Andric                                           ProgramStateRef State,
437*0fca6ea1SDimitry Andric                                           AnyArgExpr Buffer, SVal Element,
438*0fca6ea1SDimitry Andric                                           SVal Size) const {
439*0fca6ea1SDimitry Andric 
440*0fca6ea1SDimitry Andric   // If a previous check has failed, propagate the failure.
441*0fca6ea1SDimitry Andric   if (!State)
442*0fca6ea1SDimitry Andric     return nullptr;
443*0fca6ea1SDimitry Andric 
444*0fca6ea1SDimitry Andric   const MemRegion *R = Element.getAsRegion();
445*0fca6ea1SDimitry Andric   const auto *ER = dyn_cast_or_null<ElementRegion>(R);
446*0fca6ea1SDimitry Andric   if (!ER)
447*0fca6ea1SDimitry Andric     return State;
448*0fca6ea1SDimitry Andric 
449*0fca6ea1SDimitry Andric   const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
450*0fca6ea1SDimitry Andric   if (!SuperR)
451*0fca6ea1SDimitry Andric     return State;
452*0fca6ea1SDimitry Andric 
453*0fca6ea1SDimitry Andric   // FIXME: We ought to able to check objects as well. Maybe
454*0fca6ea1SDimitry Andric   // UninitializedObjectChecker could help?
455*0fca6ea1SDimitry Andric   if (!SuperR->getValueType()->isArrayType())
456*0fca6ea1SDimitry Andric     return State;
457*0fca6ea1SDimitry Andric 
458*0fca6ea1SDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
459*0fca6ea1SDimitry Andric   ASTContext &Ctx = SVB.getContext();
460*0fca6ea1SDimitry Andric 
461*0fca6ea1SDimitry Andric   const QualType ElemTy = Ctx.getBaseElementType(SuperR->getValueType());
462*0fca6ea1SDimitry Andric   const NonLoc Zero = SVB.makeZeroArrayIndex();
463*0fca6ea1SDimitry Andric 
464*0fca6ea1SDimitry Andric   std::optional<Loc> FirstElementVal =
465*0fca6ea1SDimitry Andric       State->getLValue(ElemTy, Zero, loc::MemRegionVal(SuperR)).getAs<Loc>();
466*0fca6ea1SDimitry Andric   if (!FirstElementVal)
467*0fca6ea1SDimitry Andric     return State;
468*0fca6ea1SDimitry Andric 
469*0fca6ea1SDimitry Andric   // Ensure that we wouldn't read uninitialized value.
470*0fca6ea1SDimitry Andric   if (Filter.CheckCStringUninitializedRead &&
471*0fca6ea1SDimitry Andric       State->getSVal(*FirstElementVal).isUndef()) {
472*0fca6ea1SDimitry Andric     llvm::SmallString<258> Buf;
473*0fca6ea1SDimitry Andric     llvm::raw_svector_ostream OS(Buf);
474*0fca6ea1SDimitry Andric     OS << "The first element of the ";
475*0fca6ea1SDimitry Andric     printIdxWithOrdinalSuffix(OS, Buffer.ArgumentIndex + 1);
476*0fca6ea1SDimitry Andric     OS << " argument is undefined";
477*0fca6ea1SDimitry Andric     emitUninitializedReadBug(C, State, Buffer.Expression, OS.str());
478*0fca6ea1SDimitry Andric     return nullptr;
479*0fca6ea1SDimitry Andric   }
480*0fca6ea1SDimitry Andric 
481*0fca6ea1SDimitry Andric   // We won't check whether the entire region is fully initialized -- lets just
482*0fca6ea1SDimitry Andric   // check that the first and the last element is. So, onto checking the last
483*0fca6ea1SDimitry Andric   // element:
484*0fca6ea1SDimitry Andric   const QualType IdxTy = SVB.getArrayIndexType();
485*0fca6ea1SDimitry Andric 
486*0fca6ea1SDimitry Andric   NonLoc ElemSize =
487*0fca6ea1SDimitry Andric       SVB.makeIntVal(Ctx.getTypeSizeInChars(ElemTy).getQuantity(), IdxTy)
488*0fca6ea1SDimitry Andric           .castAs<NonLoc>();
489*0fca6ea1SDimitry Andric 
490*0fca6ea1SDimitry Andric   // FIXME: Check that the size arg to the cstring function is divisible by
491*0fca6ea1SDimitry Andric   // size of the actual element type?
492*0fca6ea1SDimitry Andric 
493*0fca6ea1SDimitry Andric   // The type of the argument to the cstring function is either char or wchar,
494*0fca6ea1SDimitry Andric   // but thats not the type of the original array (or memory region).
495*0fca6ea1SDimitry Andric   // Suppose the following:
496*0fca6ea1SDimitry Andric   //   int t[5];
497*0fca6ea1SDimitry Andric   //   memcpy(dst, t, sizeof(t) / sizeof(t[0]));
498*0fca6ea1SDimitry Andric   // When checking whether t is fully initialized, we see it as char array of
499*0fca6ea1SDimitry Andric   // size sizeof(int)*5. If we check the last element as a character, we read
500*0fca6ea1SDimitry Andric   // the last byte of an integer, which will be undefined. But just because
501*0fca6ea1SDimitry Andric   // that value is undefined, it doesn't mean that the element is uninitialized!
502*0fca6ea1SDimitry Andric   // For this reason, we need to retrieve the actual last element with the
503*0fca6ea1SDimitry Andric   // correct type.
504*0fca6ea1SDimitry Andric 
505*0fca6ea1SDimitry Andric   // Divide the size argument to the cstring function by the actual element
506*0fca6ea1SDimitry Andric   // type. This value will be size of the array, or the index to the
507*0fca6ea1SDimitry Andric   // past-the-end element.
508*0fca6ea1SDimitry Andric   std::optional<NonLoc> Offset =
509*0fca6ea1SDimitry Andric       SVB.evalBinOpNN(State, clang::BO_Div, Size.castAs<NonLoc>(), ElemSize,
510*0fca6ea1SDimitry Andric                       IdxTy)
511*0fca6ea1SDimitry Andric           .getAs<NonLoc>();
512*0fca6ea1SDimitry Andric 
513*0fca6ea1SDimitry Andric   // Retrieve the index of the last element.
514*0fca6ea1SDimitry Andric   const NonLoc One = SVB.makeIntVal(1, IdxTy).castAs<NonLoc>();
515*0fca6ea1SDimitry Andric   SVal LastIdx = SVB.evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);
516*0fca6ea1SDimitry Andric 
517*0fca6ea1SDimitry Andric   if (!Offset)
518*0fca6ea1SDimitry Andric     return State;
519*0fca6ea1SDimitry Andric 
520*0fca6ea1SDimitry Andric   SVal LastElementVal =
521*0fca6ea1SDimitry Andric       State->getLValue(ElemTy, LastIdx, loc::MemRegionVal(SuperR));
522*0fca6ea1SDimitry Andric   if (!isa<Loc>(LastElementVal))
523*0fca6ea1SDimitry Andric     return State;
524*0fca6ea1SDimitry Andric 
525*0fca6ea1SDimitry Andric   if (Filter.CheckCStringUninitializedRead &&
526*0fca6ea1SDimitry Andric       State->getSVal(LastElementVal.castAs<Loc>()).isUndef()) {
527*0fca6ea1SDimitry Andric     const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
528*0fca6ea1SDimitry Andric     // If we can't get emit a sensible last element index, just bail out --
529*0fca6ea1SDimitry Andric     // prefer to emit nothing in favour of emitting garbage quality reports.
530*0fca6ea1SDimitry Andric     if (!IdxInt) {
531*0fca6ea1SDimitry Andric       C.addSink();
532*0fca6ea1SDimitry Andric       return nullptr;
533*0fca6ea1SDimitry Andric     }
534*0fca6ea1SDimitry Andric     llvm::SmallString<258> Buf;
535*0fca6ea1SDimitry Andric     llvm::raw_svector_ostream OS(Buf);
536*0fca6ea1SDimitry Andric     OS << "The last accessed element (at index ";
537*0fca6ea1SDimitry Andric     OS << IdxInt->getExtValue();
538*0fca6ea1SDimitry Andric     OS << ") in the ";
539*0fca6ea1SDimitry Andric     printIdxWithOrdinalSuffix(OS, Buffer.ArgumentIndex + 1);
540*0fca6ea1SDimitry Andric     OS << " argument is undefined";
541*0fca6ea1SDimitry Andric     emitUninitializedReadBug(C, State, Buffer.Expression, OS.str());
542*0fca6ea1SDimitry Andric     return nullptr;
543*0fca6ea1SDimitry Andric   }
544*0fca6ea1SDimitry Andric   return State;
545*0fca6ea1SDimitry Andric }
546*0fca6ea1SDimitry Andric 
5470b57cec5SDimitry Andric // FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor?
5480b57cec5SDimitry Andric ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C,
5490b57cec5SDimitry Andric                                               ProgramStateRef state,
5505ffd83dbSDimitry Andric                                               AnyArgExpr Buffer, SVal Element,
551972a253aSDimitry Andric                                               AccessKind Access,
552bdd1243dSDimitry Andric                                               CharKind CK) const {
5535ffd83dbSDimitry Andric 
5540b57cec5SDimitry Andric   // If a previous check has failed, propagate the failure.
5550b57cec5SDimitry Andric   if (!state)
5560b57cec5SDimitry Andric     return nullptr;
5570b57cec5SDimitry Andric 
5580b57cec5SDimitry Andric   // Check for out of bound array element access.
5595ffd83dbSDimitry Andric   const MemRegion *R = Element.getAsRegion();
5600b57cec5SDimitry Andric   if (!R)
5610b57cec5SDimitry Andric     return state;
5620b57cec5SDimitry Andric 
5635ffd83dbSDimitry Andric   const auto *ER = dyn_cast<ElementRegion>(R);
5640b57cec5SDimitry Andric   if (!ER)
5650b57cec5SDimitry Andric     return state;
5660b57cec5SDimitry Andric 
567972a253aSDimitry Andric   // Get the index of the accessed element.
568*0fca6ea1SDimitry Andric   std::optional<NonLoc> Idx = getIndex(state, ER, CK);
569*0fca6ea1SDimitry Andric   if (!Idx)
5700b57cec5SDimitry Andric     return state;
5710b57cec5SDimitry Andric 
5720b57cec5SDimitry Andric   // Get the size of the array.
5735ffd83dbSDimitry Andric   const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
5745ffd83dbSDimitry Andric   DefinedOrUnknownSVal Size =
575fe6060f1SDimitry Andric       getDynamicExtent(state, superReg, C.getSValBuilder());
5760b57cec5SDimitry Andric 
577*0fca6ea1SDimitry Andric   auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
5780b57cec5SDimitry Andric   if (StOutBound && !StInBound) {
5790b57cec5SDimitry Andric     // These checks are either enabled by the CString out-of-bounds checker
5800b57cec5SDimitry Andric     // explicitly or implicitly by the Malloc checker.
5810b57cec5SDimitry Andric     // In the latter case we only do modeling but do not emit warning.
5820b57cec5SDimitry Andric     if (!Filter.CheckCStringOutOfBounds)
5830b57cec5SDimitry Andric       return nullptr;
5840b57cec5SDimitry Andric 
5855ffd83dbSDimitry Andric     // Emit a bug report.
5865ffd83dbSDimitry Andric     ErrorMessage Message =
5875ffd83dbSDimitry Andric         createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
5885ffd83dbSDimitry Andric     emitOutOfBoundsBug(C, StOutBound, Buffer.Expression, Message);
5890b57cec5SDimitry Andric     return nullptr;
5900b57cec5SDimitry Andric   }
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   // Array bound check succeeded.  From this point forward the array bound
5930b57cec5SDimitry Andric   // should always succeed.
5940b57cec5SDimitry Andric   return StInBound;
5950b57cec5SDimitry Andric }
5960b57cec5SDimitry Andric 
597972a253aSDimitry Andric ProgramStateRef
598972a253aSDimitry Andric CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
599972a253aSDimitry Andric                                   AnyArgExpr Buffer, SizeArgExpr Size,
600bdd1243dSDimitry Andric                                   AccessKind Access, CharKind CK) const {
6010b57cec5SDimitry Andric   // If a previous check has failed, propagate the failure.
6025ffd83dbSDimitry Andric   if (!State)
6030b57cec5SDimitry Andric     return nullptr;
6040b57cec5SDimitry Andric 
6050b57cec5SDimitry Andric   SValBuilder &svalBuilder = C.getSValBuilder();
6060b57cec5SDimitry Andric   ASTContext &Ctx = svalBuilder.getContext();
6070b57cec5SDimitry Andric 
6085ffd83dbSDimitry Andric   QualType SizeTy = Size.Expression->getType();
609bdd1243dSDimitry Andric   QualType PtrTy = getCharPtrType(Ctx, CK);
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   // Check that the first buffer is non-null.
6125ffd83dbSDimitry Andric   SVal BufVal = C.getSVal(Buffer.Expression);
6135ffd83dbSDimitry Andric   State = checkNonNull(C, State, Buffer, BufVal);
6145ffd83dbSDimitry Andric   if (!State)
6150b57cec5SDimitry Andric     return nullptr;
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric   // If out-of-bounds checking is turned off, skip the rest.
6180b57cec5SDimitry Andric   if (!Filter.CheckCStringOutOfBounds)
6195ffd83dbSDimitry Andric     return State;
6200b57cec5SDimitry Andric 
6215f757f3fSDimitry Andric   SVal BufStart =
6225f757f3fSDimitry Andric       svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
6235f757f3fSDimitry Andric 
6245f757f3fSDimitry Andric   // Check if the first byte of the buffer is accessible.
6255f757f3fSDimitry Andric   State = CheckLocation(C, State, Buffer, BufStart, Access, CK);
626*0fca6ea1SDimitry Andric 
6275f757f3fSDimitry Andric   if (!State)
6285f757f3fSDimitry Andric     return nullptr;
6295f757f3fSDimitry Andric 
6300b57cec5SDimitry Andric   // Get the access length and make sure it is known.
6310b57cec5SDimitry Andric   // FIXME: This assumes the caller has already checked that the access length
6320b57cec5SDimitry Andric   // is positive. And that it's unsigned.
6335ffd83dbSDimitry Andric   SVal LengthVal = C.getSVal(Size.Expression);
634bdd1243dSDimitry Andric   std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
6350b57cec5SDimitry Andric   if (!Length)
6365ffd83dbSDimitry Andric     return State;
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric   // Compute the offset of the last element to be accessed: size-1.
6395ffd83dbSDimitry Andric   NonLoc One = svalBuilder.makeIntVal(1, SizeTy).castAs<NonLoc>();
6405ffd83dbSDimitry Andric   SVal Offset = svalBuilder.evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
6410b57cec5SDimitry Andric   if (Offset.isUnknown())
6420b57cec5SDimitry Andric     return nullptr;
6430b57cec5SDimitry Andric   NonLoc LastOffset = Offset.castAs<NonLoc>();
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric   // Check that the first buffer is sufficiently long.
646bdd1243dSDimitry Andric   if (std::optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
6470b57cec5SDimitry Andric 
6485ffd83dbSDimitry Andric     SVal BufEnd =
6495ffd83dbSDimitry Andric         svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
650bdd1243dSDimitry Andric     State = CheckLocation(C, State, Buffer, BufEnd, Access, CK);
651*0fca6ea1SDimitry Andric     if (Access == AccessKind::read)
652*0fca6ea1SDimitry Andric       State = checkInit(C, State, Buffer, BufEnd, *Length);
6530b57cec5SDimitry Andric 
6540b57cec5SDimitry Andric     // If the buffer isn't large enough, abort.
6555ffd83dbSDimitry Andric     if (!State)
6560b57cec5SDimitry Andric       return nullptr;
6570b57cec5SDimitry Andric   }
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric   // Large enough or not, return this state!
6605ffd83dbSDimitry Andric   return State;
6610b57cec5SDimitry Andric }
6620b57cec5SDimitry Andric 
6630b57cec5SDimitry Andric ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C,
6640b57cec5SDimitry Andric                                              ProgramStateRef state,
6655ffd83dbSDimitry Andric                                              SizeArgExpr Size, AnyArgExpr First,
666972a253aSDimitry Andric                                              AnyArgExpr Second,
667bdd1243dSDimitry Andric                                              CharKind CK) const {
6680b57cec5SDimitry Andric   if (!Filter.CheckCStringBufferOverlap)
6690b57cec5SDimitry Andric     return state;
6700b57cec5SDimitry Andric 
6710b57cec5SDimitry Andric   // Do a simple check for overlap: if the two arguments are from the same
6720b57cec5SDimitry Andric   // buffer, see if the end of the first is greater than the start of the second
6730b57cec5SDimitry Andric   // or vice versa.
6740b57cec5SDimitry Andric 
6750b57cec5SDimitry Andric   // If a previous check has failed, propagate the failure.
6760b57cec5SDimitry Andric   if (!state)
6770b57cec5SDimitry Andric     return nullptr;
6780b57cec5SDimitry Andric 
6790b57cec5SDimitry Andric   ProgramStateRef stateTrue, stateFalse;
6800b57cec5SDimitry Andric 
68181ad6265SDimitry Andric   // Assume different address spaces cannot overlap.
68281ad6265SDimitry Andric   if (First.Expression->getType()->getPointeeType().getAddressSpace() !=
68381ad6265SDimitry Andric       Second.Expression->getType()->getPointeeType().getAddressSpace())
68481ad6265SDimitry Andric     return state;
68581ad6265SDimitry Andric 
6860b57cec5SDimitry Andric   // Get the buffer values and make sure they're known locations.
6870b57cec5SDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
6885ffd83dbSDimitry Andric   SVal firstVal = state->getSVal(First.Expression, LCtx);
6895ffd83dbSDimitry Andric   SVal secondVal = state->getSVal(Second.Expression, LCtx);
6900b57cec5SDimitry Andric 
691bdd1243dSDimitry Andric   std::optional<Loc> firstLoc = firstVal.getAs<Loc>();
6920b57cec5SDimitry Andric   if (!firstLoc)
6930b57cec5SDimitry Andric     return state;
6940b57cec5SDimitry Andric 
695bdd1243dSDimitry Andric   std::optional<Loc> secondLoc = secondVal.getAs<Loc>();
6960b57cec5SDimitry Andric   if (!secondLoc)
6970b57cec5SDimitry Andric     return state;
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric   // Are the two values the same?
7000b57cec5SDimitry Andric   SValBuilder &svalBuilder = C.getSValBuilder();
7010b57cec5SDimitry Andric   std::tie(stateTrue, stateFalse) =
7020b57cec5SDimitry Andric       state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc));
7030b57cec5SDimitry Andric 
7040b57cec5SDimitry Andric   if (stateTrue && !stateFalse) {
7050b57cec5SDimitry Andric     // If the values are known to be equal, that's automatically an overlap.
7065ffd83dbSDimitry Andric     emitOverlapBug(C, stateTrue, First.Expression, Second.Expression);
7070b57cec5SDimitry Andric     return nullptr;
7080b57cec5SDimitry Andric   }
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric   // assume the two expressions are not equal.
7110b57cec5SDimitry Andric   assert(stateFalse);
7120b57cec5SDimitry Andric   state = stateFalse;
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric   // Which value comes first?
7150b57cec5SDimitry Andric   QualType cmpTy = svalBuilder.getConditionType();
7165ffd83dbSDimitry Andric   SVal reverse =
7175ffd83dbSDimitry Andric       svalBuilder.evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
718bdd1243dSDimitry Andric   std::optional<DefinedOrUnknownSVal> reverseTest =
7190b57cec5SDimitry Andric       reverse.getAs<DefinedOrUnknownSVal>();
7200b57cec5SDimitry Andric   if (!reverseTest)
7210b57cec5SDimitry Andric     return state;
7220b57cec5SDimitry Andric 
7230b57cec5SDimitry Andric   std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
7240b57cec5SDimitry Andric   if (stateTrue) {
7250b57cec5SDimitry Andric     if (stateFalse) {
7260b57cec5SDimitry Andric       // If we don't know which one comes first, we can't perform this test.
7270b57cec5SDimitry Andric       return state;
7280b57cec5SDimitry Andric     } else {
7290b57cec5SDimitry Andric       // Switch the values so that firstVal is before secondVal.
7300b57cec5SDimitry Andric       std::swap(firstLoc, secondLoc);
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric       // Switch the Exprs as well, so that they still correspond.
7330b57cec5SDimitry Andric       std::swap(First, Second);
7340b57cec5SDimitry Andric     }
7350b57cec5SDimitry Andric   }
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   // Get the length, and make sure it too is known.
7385ffd83dbSDimitry Andric   SVal LengthVal = state->getSVal(Size.Expression, LCtx);
739bdd1243dSDimitry Andric   std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
7400b57cec5SDimitry Andric   if (!Length)
7410b57cec5SDimitry Andric     return state;
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric   // Convert the first buffer's start address to char*.
7440b57cec5SDimitry Andric   // Bail out if the cast fails.
7450b57cec5SDimitry Andric   ASTContext &Ctx = svalBuilder.getContext();
746bdd1243dSDimitry Andric   QualType CharPtrTy = getCharPtrType(Ctx, CK);
7475ffd83dbSDimitry Andric   SVal FirstStart =
7485ffd83dbSDimitry Andric       svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType());
749bdd1243dSDimitry Andric   std::optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>();
7500b57cec5SDimitry Andric   if (!FirstStartLoc)
7510b57cec5SDimitry Andric     return state;
7520b57cec5SDimitry Andric 
7530b57cec5SDimitry Andric   // Compute the end of the first buffer. Bail out if THAT fails.
7545ffd83dbSDimitry Andric   SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, *FirstStartLoc,
7555ffd83dbSDimitry Andric                                           *Length, CharPtrTy);
756bdd1243dSDimitry Andric   std::optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>();
7570b57cec5SDimitry Andric   if (!FirstEndLoc)
7580b57cec5SDimitry Andric     return state;
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric   // Is the end of the first buffer past the start of the second buffer?
7615ffd83dbSDimitry Andric   SVal Overlap =
7625ffd83dbSDimitry Andric       svalBuilder.evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
763bdd1243dSDimitry Andric   std::optional<DefinedOrUnknownSVal> OverlapTest =
7640b57cec5SDimitry Andric       Overlap.getAs<DefinedOrUnknownSVal>();
7650b57cec5SDimitry Andric   if (!OverlapTest)
7660b57cec5SDimitry Andric     return state;
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric   std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
7690b57cec5SDimitry Andric 
7700b57cec5SDimitry Andric   if (stateTrue && !stateFalse) {
7710b57cec5SDimitry Andric     // Overlap!
7725ffd83dbSDimitry Andric     emitOverlapBug(C, stateTrue, First.Expression, Second.Expression);
7730b57cec5SDimitry Andric     return nullptr;
7740b57cec5SDimitry Andric   }
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   // assume the two expressions don't overlap.
7770b57cec5SDimitry Andric   assert(stateFalse);
7780b57cec5SDimitry Andric   return stateFalse;
7790b57cec5SDimitry Andric }
7800b57cec5SDimitry Andric 
7810b57cec5SDimitry Andric void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state,
7820b57cec5SDimitry Andric                                   const Stmt *First, const Stmt *Second) const {
7830b57cec5SDimitry Andric   ExplodedNode *N = C.generateErrorNode(state);
7840b57cec5SDimitry Andric   if (!N)
7850b57cec5SDimitry Andric     return;
7860b57cec5SDimitry Andric 
7870b57cec5SDimitry Andric   if (!BT_Overlap)
7880b57cec5SDimitry Andric     BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap,
7890b57cec5SDimitry Andric                                  categories::UnixAPI, "Improper arguments"));
7900b57cec5SDimitry Andric 
7910b57cec5SDimitry Andric   // Generate a report for this bug.
792a7dea167SDimitry Andric   auto report = std::make_unique<PathSensitiveBugReport>(
7930b57cec5SDimitry Andric       *BT_Overlap, "Arguments must not be overlapping buffers", N);
7940b57cec5SDimitry Andric   report->addRange(First->getSourceRange());
7950b57cec5SDimitry Andric   report->addRange(Second->getSourceRange());
7960b57cec5SDimitry Andric 
7970b57cec5SDimitry Andric   C.emitReport(std::move(report));
7980b57cec5SDimitry Andric }
7990b57cec5SDimitry Andric 
8000b57cec5SDimitry Andric void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State,
8010b57cec5SDimitry Andric                                     const Stmt *S, StringRef WarningMsg) const {
8020b57cec5SDimitry Andric   if (ExplodedNode *N = C.generateErrorNode(State)) {
8035f757f3fSDimitry Andric     if (!BT_Null) {
8045f757f3fSDimitry Andric       // FIXME: This call uses the string constant 'categories::UnixAPI' as the
8055f757f3fSDimitry Andric       // description of the bug; it should be replaced by a real description.
8065f757f3fSDimitry Andric       BT_Null.reset(
8075f757f3fSDimitry Andric           new BugType(Filter.CheckNameCStringNullArg, categories::UnixAPI));
8085f757f3fSDimitry Andric     }
8090b57cec5SDimitry Andric 
8105f757f3fSDimitry Andric     auto Report =
8115f757f3fSDimitry Andric         std::make_unique<PathSensitiveBugReport>(*BT_Null, WarningMsg, N);
8120b57cec5SDimitry Andric     Report->addRange(S->getSourceRange());
8130b57cec5SDimitry Andric     if (const auto *Ex = dyn_cast<Expr>(S))
8140b57cec5SDimitry Andric       bugreporter::trackExpressionValue(N, Ex, *Report);
8150b57cec5SDimitry Andric     C.emitReport(std::move(Report));
8160b57cec5SDimitry Andric   }
8170b57cec5SDimitry Andric }
8180b57cec5SDimitry Andric 
81981ad6265SDimitry Andric void CStringChecker::emitUninitializedReadBug(CheckerContext &C,
82081ad6265SDimitry Andric                                               ProgramStateRef State,
821*0fca6ea1SDimitry Andric                                               const Expr *E,
822*0fca6ea1SDimitry Andric                                               StringRef Msg) const {
82381ad6265SDimitry Andric   if (ExplodedNode *N = C.generateErrorNode(State)) {
82481ad6265SDimitry Andric     if (!BT_UninitRead)
8255f757f3fSDimitry Andric       BT_UninitRead.reset(new BugType(Filter.CheckNameCStringUninitializedRead,
8265f757f3fSDimitry Andric                                       "Accessing unitialized/garbage values"));
82781ad6265SDimitry Andric 
8285f757f3fSDimitry Andric     auto Report =
8295f757f3fSDimitry Andric         std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N);
830*0fca6ea1SDimitry Andric     Report->addNote("Other elements might also be undefined",
831*0fca6ea1SDimitry Andric                     Report->getLocation());
83281ad6265SDimitry Andric     Report->addRange(E->getSourceRange());
83381ad6265SDimitry Andric     bugreporter::trackExpressionValue(N, E, *Report);
83481ad6265SDimitry Andric     C.emitReport(std::move(Report));
83581ad6265SDimitry Andric   }
83681ad6265SDimitry Andric }
83781ad6265SDimitry Andric 
8380b57cec5SDimitry Andric void CStringChecker::emitOutOfBoundsBug(CheckerContext &C,
8390b57cec5SDimitry Andric                                         ProgramStateRef State, const Stmt *S,
8400b57cec5SDimitry Andric                                         StringRef WarningMsg) const {
8410b57cec5SDimitry Andric   if (ExplodedNode *N = C.generateErrorNode(State)) {
8420b57cec5SDimitry Andric     if (!BT_Bounds)
8435f757f3fSDimitry Andric       BT_Bounds.reset(new BugType(Filter.CheckCStringOutOfBounds
8445f757f3fSDimitry Andric                                       ? Filter.CheckNameCStringOutOfBounds
8450b57cec5SDimitry Andric                                       : Filter.CheckNameCStringNullArg,
8465f757f3fSDimitry Andric                                   "Out-of-bound array access"));
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric     // FIXME: It would be nice to eventually make this diagnostic more clear,
8490b57cec5SDimitry Andric     // e.g., by referencing the original declaration or by saying *why* this
8500b57cec5SDimitry Andric     // reference is outside the range.
8515f757f3fSDimitry Andric     auto Report =
8525f757f3fSDimitry Andric         std::make_unique<PathSensitiveBugReport>(*BT_Bounds, WarningMsg, N);
8530b57cec5SDimitry Andric     Report->addRange(S->getSourceRange());
8540b57cec5SDimitry Andric     C.emitReport(std::move(Report));
8550b57cec5SDimitry Andric   }
8560b57cec5SDimitry Andric }
8570b57cec5SDimitry Andric 
8580b57cec5SDimitry Andric void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State,
8590b57cec5SDimitry Andric                                        const Stmt *S,
8600b57cec5SDimitry Andric                                        StringRef WarningMsg) const {
8610b57cec5SDimitry Andric   if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) {
8625f757f3fSDimitry Andric     if (!BT_NotCString) {
8635f757f3fSDimitry Andric       // FIXME: This call uses the string constant 'categories::UnixAPI' as the
8645f757f3fSDimitry Andric       // description of the bug; it should be replaced by a real description.
8655f757f3fSDimitry Andric       BT_NotCString.reset(
8665f757f3fSDimitry Andric           new BugType(Filter.CheckNameCStringNotNullTerm, categories::UnixAPI));
8675f757f3fSDimitry Andric     }
8680b57cec5SDimitry Andric 
869a7dea167SDimitry Andric     auto Report =
870a7dea167SDimitry Andric         std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric     Report->addRange(S->getSourceRange());
8730b57cec5SDimitry Andric     C.emitReport(std::move(Report));
8740b57cec5SDimitry Andric   }
8750b57cec5SDimitry Andric }
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric void CStringChecker::emitAdditionOverflowBug(CheckerContext &C,
8780b57cec5SDimitry Andric                                              ProgramStateRef State) const {
8790b57cec5SDimitry Andric   if (ExplodedNode *N = C.generateErrorNode(State)) {
8805f757f3fSDimitry Andric     if (!BT_AdditionOverflow) {
8815f757f3fSDimitry Andric       // FIXME: This call uses the word "API" as the description of the bug;
8825f757f3fSDimitry Andric       // it should be replaced by a better error message (if this unlikely
8835f757f3fSDimitry Andric       // situation continues to exist as a separate bug type).
88481ad6265SDimitry Andric       BT_AdditionOverflow.reset(
8855f757f3fSDimitry Andric           new BugType(Filter.CheckNameCStringOutOfBounds, "API"));
8865f757f3fSDimitry Andric     }
8870b57cec5SDimitry Andric 
8880b57cec5SDimitry Andric     // This isn't a great error message, but this should never occur in real
8890b57cec5SDimitry Andric     // code anyway -- you'd have to create a buffer longer than a size_t can
8900b57cec5SDimitry Andric     // represent, which is sort of a contradiction.
8910b57cec5SDimitry Andric     const char *WarningMsg =
8920b57cec5SDimitry Andric         "This expression will create a string whose length is too big to "
8930b57cec5SDimitry Andric         "be represented as a size_t";
8940b57cec5SDimitry Andric 
89581ad6265SDimitry Andric     auto Report = std::make_unique<PathSensitiveBugReport>(*BT_AdditionOverflow,
89681ad6265SDimitry Andric                                                            WarningMsg, N);
8970b57cec5SDimitry Andric     C.emitReport(std::move(Report));
8980b57cec5SDimitry Andric   }
8990b57cec5SDimitry Andric }
9000b57cec5SDimitry Andric 
9010b57cec5SDimitry Andric ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
9020b57cec5SDimitry Andric                                                      ProgramStateRef state,
9030b57cec5SDimitry Andric                                                      NonLoc left,
9040b57cec5SDimitry Andric                                                      NonLoc right) const {
9050b57cec5SDimitry Andric   // If out-of-bounds checking is turned off, skip the rest.
9060b57cec5SDimitry Andric   if (!Filter.CheckCStringOutOfBounds)
9070b57cec5SDimitry Andric     return state;
9080b57cec5SDimitry Andric 
9090b57cec5SDimitry Andric   // If a previous check has failed, propagate the failure.
9100b57cec5SDimitry Andric   if (!state)
9110b57cec5SDimitry Andric     return nullptr;
9120b57cec5SDimitry Andric 
9130b57cec5SDimitry Andric   SValBuilder &svalBuilder = C.getSValBuilder();
9140b57cec5SDimitry Andric   BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric   QualType sizeTy = svalBuilder.getContext().getSizeType();
9170b57cec5SDimitry Andric   const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
9180b57cec5SDimitry Andric   NonLoc maxVal = svalBuilder.makeIntVal(maxValInt);
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric   SVal maxMinusRight;
92181ad6265SDimitry Andric   if (isa<nonloc::ConcreteInt>(right)) {
9220b57cec5SDimitry Andric     maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right,
9230b57cec5SDimitry Andric                                                  sizeTy);
9240b57cec5SDimitry Andric   } else {
9250b57cec5SDimitry Andric     // Try switching the operands. (The order of these two assignments is
9260b57cec5SDimitry Andric     // important!)
9270b57cec5SDimitry Andric     maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left,
9280b57cec5SDimitry Andric                                             sizeTy);
9290b57cec5SDimitry Andric     left = right;
9300b57cec5SDimitry Andric   }
9310b57cec5SDimitry Andric 
932bdd1243dSDimitry Andric   if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) {
9330b57cec5SDimitry Andric     QualType cmpTy = svalBuilder.getConditionType();
9340b57cec5SDimitry Andric     // If left > max - right, we have an overflow.
9350b57cec5SDimitry Andric     SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left,
9360b57cec5SDimitry Andric                                                 *maxMinusRightNL, cmpTy);
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric     ProgramStateRef stateOverflow, stateOkay;
9390b57cec5SDimitry Andric     std::tie(stateOverflow, stateOkay) =
9400b57cec5SDimitry Andric       state->assume(willOverflow.castAs<DefinedOrUnknownSVal>());
9410b57cec5SDimitry Andric 
9420b57cec5SDimitry Andric     if (stateOverflow && !stateOkay) {
9430b57cec5SDimitry Andric       // We have an overflow. Emit a bug report.
9440b57cec5SDimitry Andric       emitAdditionOverflowBug(C, stateOverflow);
9450b57cec5SDimitry Andric       return nullptr;
9460b57cec5SDimitry Andric     }
9470b57cec5SDimitry Andric 
9480b57cec5SDimitry Andric     // From now on, assume an overflow didn't occur.
9490b57cec5SDimitry Andric     assert(stateOkay);
9500b57cec5SDimitry Andric     state = stateOkay;
9510b57cec5SDimitry Andric   }
9520b57cec5SDimitry Andric 
9530b57cec5SDimitry Andric   return state;
9540b57cec5SDimitry Andric }
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric ProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state,
9570b57cec5SDimitry Andric                                                 const MemRegion *MR,
9580b57cec5SDimitry Andric                                                 SVal strLength) {
9590b57cec5SDimitry Andric   assert(!strLength.isUndef() && "Attempt to set an undefined string length");
9600b57cec5SDimitry Andric 
9610b57cec5SDimitry Andric   MR = MR->StripCasts();
9620b57cec5SDimitry Andric 
9630b57cec5SDimitry Andric   switch (MR->getKind()) {
9640b57cec5SDimitry Andric   case MemRegion::StringRegionKind:
9650b57cec5SDimitry Andric     // FIXME: This can happen if we strcpy() into a string region. This is
9660b57cec5SDimitry Andric     // undefined [C99 6.4.5p6], but we should still warn about it.
9670b57cec5SDimitry Andric     return state;
9680b57cec5SDimitry Andric 
9690b57cec5SDimitry Andric   case MemRegion::SymbolicRegionKind:
9700b57cec5SDimitry Andric   case MemRegion::AllocaRegionKind:
9715ffd83dbSDimitry Andric   case MemRegion::NonParamVarRegionKind:
9725ffd83dbSDimitry Andric   case MemRegion::ParamVarRegionKind:
9730b57cec5SDimitry Andric   case MemRegion::FieldRegionKind:
9740b57cec5SDimitry Andric   case MemRegion::ObjCIvarRegionKind:
9750b57cec5SDimitry Andric     // These are the types we can currently track string lengths for.
9760b57cec5SDimitry Andric     break;
9770b57cec5SDimitry Andric 
9780b57cec5SDimitry Andric   case MemRegion::ElementRegionKind:
9790b57cec5SDimitry Andric     // FIXME: Handle element regions by upper-bounding the parent region's
9800b57cec5SDimitry Andric     // string length.
9810b57cec5SDimitry Andric     return state;
9820b57cec5SDimitry Andric 
9830b57cec5SDimitry Andric   default:
9840b57cec5SDimitry Andric     // Other regions (mostly non-data) can't have a reliable C string length.
9850b57cec5SDimitry Andric     // For now, just ignore the change.
9860b57cec5SDimitry Andric     // FIXME: These are rare but not impossible. We should output some kind of
9870b57cec5SDimitry Andric     // warning for things like strcpy((char[]){'a', 0}, "b");
9880b57cec5SDimitry Andric     return state;
9890b57cec5SDimitry Andric   }
9900b57cec5SDimitry Andric 
9910b57cec5SDimitry Andric   if (strLength.isUnknown())
9920b57cec5SDimitry Andric     return state->remove<CStringLength>(MR);
9930b57cec5SDimitry Andric 
9940b57cec5SDimitry Andric   return state->set<CStringLength>(MR, strLength);
9950b57cec5SDimitry Andric }
9960b57cec5SDimitry Andric 
9970b57cec5SDimitry Andric SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
9980b57cec5SDimitry Andric                                                ProgramStateRef &state,
9990b57cec5SDimitry Andric                                                const Expr *Ex,
10000b57cec5SDimitry Andric                                                const MemRegion *MR,
10010b57cec5SDimitry Andric                                                bool hypothetical) {
10020b57cec5SDimitry Andric   if (!hypothetical) {
10030b57cec5SDimitry Andric     // If there's a recorded length, go ahead and return it.
10040b57cec5SDimitry Andric     const SVal *Recorded = state->get<CStringLength>(MR);
10050b57cec5SDimitry Andric     if (Recorded)
10060b57cec5SDimitry Andric       return *Recorded;
10070b57cec5SDimitry Andric   }
10080b57cec5SDimitry Andric 
10090b57cec5SDimitry Andric   // Otherwise, get a new symbol and update the state.
10100b57cec5SDimitry Andric   SValBuilder &svalBuilder = C.getSValBuilder();
10110b57cec5SDimitry Andric   QualType sizeTy = svalBuilder.getContext().getSizeType();
10120b57cec5SDimitry Andric   SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
10130b57cec5SDimitry Andric                                                     MR, Ex, sizeTy,
10140b57cec5SDimitry Andric                                                     C.getLocationContext(),
10150b57cec5SDimitry Andric                                                     C.blockCount());
10160b57cec5SDimitry Andric 
10170b57cec5SDimitry Andric   if (!hypothetical) {
1018bdd1243dSDimitry Andric     if (std::optional<NonLoc> strLn = strLength.getAs<NonLoc>()) {
10190b57cec5SDimitry Andric       // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4
10200b57cec5SDimitry Andric       BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
10210b57cec5SDimitry Andric       const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
10220b57cec5SDimitry Andric       llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
10230b57cec5SDimitry Andric       const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt,
10240b57cec5SDimitry Andric                                                         fourInt);
10250b57cec5SDimitry Andric       NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt);
10265f757f3fSDimitry Andric       SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, maxLength,
10275f757f3fSDimitry Andric                                                 svalBuilder.getConditionType());
10280b57cec5SDimitry Andric       state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true);
10290b57cec5SDimitry Andric     }
10300b57cec5SDimitry Andric     state = state->set<CStringLength>(MR, strLength);
10310b57cec5SDimitry Andric   }
10320b57cec5SDimitry Andric 
10330b57cec5SDimitry Andric   return strLength;
10340b57cec5SDimitry Andric }
10350b57cec5SDimitry Andric 
10360b57cec5SDimitry Andric SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state,
10370b57cec5SDimitry Andric                                       const Expr *Ex, SVal Buf,
10380b57cec5SDimitry Andric                                       bool hypothetical) const {
10390b57cec5SDimitry Andric   const MemRegion *MR = Buf.getAsRegion();
10400b57cec5SDimitry Andric   if (!MR) {
10410b57cec5SDimitry Andric     // If we can't get a region, see if it's something we /know/ isn't a
10420b57cec5SDimitry Andric     // C string. In the context of locations, the only time we can issue such
10430b57cec5SDimitry Andric     // a warning is for labels.
1044bdd1243dSDimitry Andric     if (std::optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) {
10450b57cec5SDimitry Andric       if (Filter.CheckCStringNotNullTerm) {
10460b57cec5SDimitry Andric         SmallString<120> buf;
10470b57cec5SDimitry Andric         llvm::raw_svector_ostream os(buf);
10480b57cec5SDimitry Andric         assert(CurrentFunctionDescription);
10490b57cec5SDimitry Andric         os << "Argument to " << CurrentFunctionDescription
10500b57cec5SDimitry Andric            << " is the address of the label '" << Label->getLabel()->getName()
10510b57cec5SDimitry Andric            << "', which is not a null-terminated string";
10520b57cec5SDimitry Andric 
10530b57cec5SDimitry Andric         emitNotCStringBug(C, state, Ex, os.str());
10540b57cec5SDimitry Andric       }
10550b57cec5SDimitry Andric       return UndefinedVal();
10560b57cec5SDimitry Andric     }
10570b57cec5SDimitry Andric 
10580b57cec5SDimitry Andric     // If it's not a region and not a label, give up.
10590b57cec5SDimitry Andric     return UnknownVal();
10600b57cec5SDimitry Andric   }
10610b57cec5SDimitry Andric 
10620b57cec5SDimitry Andric   // If we have a region, strip casts from it and see if we can figure out
10630b57cec5SDimitry Andric   // its length. For anything we can't figure out, just return UnknownVal.
10640b57cec5SDimitry Andric   MR = MR->StripCasts();
10650b57cec5SDimitry Andric 
10660b57cec5SDimitry Andric   switch (MR->getKind()) {
10670b57cec5SDimitry Andric   case MemRegion::StringRegionKind: {
10680b57cec5SDimitry Andric     // Modifying the contents of string regions is undefined [C99 6.4.5p6],
10690b57cec5SDimitry Andric     // so we can assume that the byte length is the correct C string length.
10700b57cec5SDimitry Andric     SValBuilder &svalBuilder = C.getSValBuilder();
10710b57cec5SDimitry Andric     QualType sizeTy = svalBuilder.getContext().getSizeType();
10720b57cec5SDimitry Andric     const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
1073753f127fSDimitry Andric     return svalBuilder.makeIntVal(strLit->getLength(), sizeTy);
10740b57cec5SDimitry Andric   }
10755f757f3fSDimitry Andric   case MemRegion::NonParamVarRegionKind: {
10765f757f3fSDimitry Andric     // If we have a global constant with a string literal initializer,
10775f757f3fSDimitry Andric     // compute the initializer's length.
10785f757f3fSDimitry Andric     const VarDecl *Decl = cast<NonParamVarRegion>(MR)->getDecl();
10795f757f3fSDimitry Andric     if (Decl->getType().isConstQualified() && Decl->hasGlobalStorage()) {
10805f757f3fSDimitry Andric       if (const Expr *Init = Decl->getInit()) {
10815f757f3fSDimitry Andric         if (auto *StrLit = dyn_cast<StringLiteral>(Init)) {
10825f757f3fSDimitry Andric           SValBuilder &SvalBuilder = C.getSValBuilder();
10835f757f3fSDimitry Andric           QualType SizeTy = SvalBuilder.getContext().getSizeType();
10845f757f3fSDimitry Andric           return SvalBuilder.makeIntVal(StrLit->getLength(), SizeTy);
10855f757f3fSDimitry Andric         }
10865f757f3fSDimitry Andric       }
10875f757f3fSDimitry Andric     }
10885f757f3fSDimitry Andric     [[fallthrough]];
10895f757f3fSDimitry Andric   }
10900b57cec5SDimitry Andric   case MemRegion::SymbolicRegionKind:
10910b57cec5SDimitry Andric   case MemRegion::AllocaRegionKind:
10925ffd83dbSDimitry Andric   case MemRegion::ParamVarRegionKind:
10930b57cec5SDimitry Andric   case MemRegion::FieldRegionKind:
10940b57cec5SDimitry Andric   case MemRegion::ObjCIvarRegionKind:
10950b57cec5SDimitry Andric     return getCStringLengthForRegion(C, state, Ex, MR, hypothetical);
10960b57cec5SDimitry Andric   case MemRegion::CompoundLiteralRegionKind:
10970b57cec5SDimitry Andric     // FIXME: Can we track this? Is it necessary?
10980b57cec5SDimitry Andric     return UnknownVal();
10990b57cec5SDimitry Andric   case MemRegion::ElementRegionKind:
11000b57cec5SDimitry Andric     // FIXME: How can we handle this? It's not good enough to subtract the
11010b57cec5SDimitry Andric     // offset from the base string length; consider "123\x00567" and &a[5].
11020b57cec5SDimitry Andric     return UnknownVal();
11030b57cec5SDimitry Andric   default:
11040b57cec5SDimitry Andric     // Other regions (mostly non-data) can't have a reliable C string length.
11050b57cec5SDimitry Andric     // In this case, an error is emitted and UndefinedVal is returned.
11060b57cec5SDimitry Andric     // The caller should always be prepared to handle this case.
11070b57cec5SDimitry Andric     if (Filter.CheckCStringNotNullTerm) {
11080b57cec5SDimitry Andric       SmallString<120> buf;
11090b57cec5SDimitry Andric       llvm::raw_svector_ostream os(buf);
11100b57cec5SDimitry Andric 
11110b57cec5SDimitry Andric       assert(CurrentFunctionDescription);
11120b57cec5SDimitry Andric       os << "Argument to " << CurrentFunctionDescription << " is ";
11130b57cec5SDimitry Andric 
11140b57cec5SDimitry Andric       if (SummarizeRegion(os, C.getASTContext(), MR))
11150b57cec5SDimitry Andric         os << ", which is not a null-terminated string";
11160b57cec5SDimitry Andric       else
11170b57cec5SDimitry Andric         os << "not a null-terminated string";
11180b57cec5SDimitry Andric 
11190b57cec5SDimitry Andric       emitNotCStringBug(C, state, Ex, os.str());
11200b57cec5SDimitry Andric     }
11210b57cec5SDimitry Andric     return UndefinedVal();
11220b57cec5SDimitry Andric   }
11230b57cec5SDimitry Andric }
11240b57cec5SDimitry Andric 
11250b57cec5SDimitry Andric const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
11260b57cec5SDimitry Andric   ProgramStateRef &state, const Expr *expr, SVal val) const {
11270b57cec5SDimitry Andric 
11280b57cec5SDimitry Andric   // Get the memory region pointed to by the val.
11290b57cec5SDimitry Andric   const MemRegion *bufRegion = val.getAsRegion();
11300b57cec5SDimitry Andric   if (!bufRegion)
11310b57cec5SDimitry Andric     return nullptr;
11320b57cec5SDimitry Andric 
11330b57cec5SDimitry Andric   // Strip casts off the memory region.
11340b57cec5SDimitry Andric   bufRegion = bufRegion->StripCasts();
11350b57cec5SDimitry Andric 
11360b57cec5SDimitry Andric   // Cast the memory region to a string region.
11370b57cec5SDimitry Andric   const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
11380b57cec5SDimitry Andric   if (!strRegion)
11390b57cec5SDimitry Andric     return nullptr;
11400b57cec5SDimitry Andric 
11410b57cec5SDimitry Andric   // Return the actual string in the string region.
11420b57cec5SDimitry Andric   return strRegion->getStringLiteral();
11430b57cec5SDimitry Andric }
11440b57cec5SDimitry Andric 
114506c3fb27SDimitry Andric bool CStringChecker::isFirstBufInBound(CheckerContext &C, ProgramStateRef State,
114606c3fb27SDimitry Andric                                        SVal BufVal, QualType BufTy,
114706c3fb27SDimitry Andric                                        SVal LengthVal, QualType LengthTy) {
11480b57cec5SDimitry Andric   // If we do not know that the buffer is long enough we return 'true'.
11490b57cec5SDimitry Andric   // Otherwise the parent region of this field region would also get
11500b57cec5SDimitry Andric   // invalidated, which would lead to warnings based on an unknown state.
11510b57cec5SDimitry Andric 
115206c3fb27SDimitry Andric   if (LengthVal.isUnknown())
115306c3fb27SDimitry Andric     return false;
115406c3fb27SDimitry Andric 
11550b57cec5SDimitry Andric   // Originally copied from CheckBufferAccess and CheckLocation.
115606c3fb27SDimitry Andric   SValBuilder &SB = C.getSValBuilder();
115706c3fb27SDimitry Andric   ASTContext &Ctx = C.getASTContext();
11580b57cec5SDimitry Andric 
11590b57cec5SDimitry Andric   QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
11600b57cec5SDimitry Andric 
1161bdd1243dSDimitry Andric   std::optional<NonLoc> Length = LengthVal.getAs<NonLoc>();
11620b57cec5SDimitry Andric   if (!Length)
11630b57cec5SDimitry Andric     return true; // cf top comment.
11640b57cec5SDimitry Andric 
11650b57cec5SDimitry Andric   // Compute the offset of the last element to be accessed: size-1.
116606c3fb27SDimitry Andric   NonLoc One = SB.makeIntVal(1, LengthTy).castAs<NonLoc>();
116706c3fb27SDimitry Andric   SVal Offset = SB.evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
11680b57cec5SDimitry Andric   if (Offset.isUnknown())
11690b57cec5SDimitry Andric     return true; // cf top comment
11700b57cec5SDimitry Andric   NonLoc LastOffset = Offset.castAs<NonLoc>();
11710b57cec5SDimitry Andric 
11720b57cec5SDimitry Andric   // Check that the first buffer is sufficiently long.
117306c3fb27SDimitry Andric   SVal BufStart = SB.evalCast(BufVal, PtrTy, BufTy);
1174bdd1243dSDimitry Andric   std::optional<Loc> BufLoc = BufStart.getAs<Loc>();
11750b57cec5SDimitry Andric   if (!BufLoc)
11760b57cec5SDimitry Andric     return true; // cf top comment.
11770b57cec5SDimitry Andric 
117806c3fb27SDimitry Andric   SVal BufEnd = SB.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
11790b57cec5SDimitry Andric 
11800b57cec5SDimitry Andric   // Check for out of bound array element access.
11810b57cec5SDimitry Andric   const MemRegion *R = BufEnd.getAsRegion();
11820b57cec5SDimitry Andric   if (!R)
11830b57cec5SDimitry Andric     return true; // cf top comment.
11840b57cec5SDimitry Andric 
11850b57cec5SDimitry Andric   const ElementRegion *ER = dyn_cast<ElementRegion>(R);
11860b57cec5SDimitry Andric   if (!ER)
11870b57cec5SDimitry Andric     return true; // cf top comment.
11880b57cec5SDimitry Andric 
11890b57cec5SDimitry Andric   // FIXME: Does this crash when a non-standard definition
11900b57cec5SDimitry Andric   // of a library function is encountered?
11910b57cec5SDimitry Andric   assert(ER->getValueType() == C.getASTContext().CharTy &&
119206c3fb27SDimitry Andric          "isFirstBufInBound should only be called with char* ElementRegions");
11930b57cec5SDimitry Andric 
11940b57cec5SDimitry Andric   // Get the size of the array.
11950b57cec5SDimitry Andric   const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
119606c3fb27SDimitry Andric   DefinedOrUnknownSVal SizeDV = getDynamicExtent(State, superReg, SB);
11970b57cec5SDimitry Andric 
11980b57cec5SDimitry Andric   // Get the index of the accessed element.
11990b57cec5SDimitry Andric   DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
12000b57cec5SDimitry Andric 
120106c3fb27SDimitry Andric   ProgramStateRef StInBound = State->assumeInBound(Idx, SizeDV, true);
12020b57cec5SDimitry Andric 
12030b57cec5SDimitry Andric   return static_cast<bool>(StInBound);
12040b57cec5SDimitry Andric }
12050b57cec5SDimitry Andric 
120606c3fb27SDimitry Andric ProgramStateRef CStringChecker::invalidateDestinationBufferBySize(
120706c3fb27SDimitry Andric     CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV,
120806c3fb27SDimitry Andric     SVal SizeV, QualType SizeTy) {
120906c3fb27SDimitry Andric   auto InvalidationTraitOperations =
121006c3fb27SDimitry Andric       [&C, S, BufTy = BufE->getType(), BufV, SizeV,
121106c3fb27SDimitry Andric        SizeTy](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) {
121206c3fb27SDimitry Andric         // If destination buffer is a field region and access is in bound, do
121306c3fb27SDimitry Andric         // not invalidate its super region.
121406c3fb27SDimitry Andric         if (MemRegion::FieldRegionKind == R->getKind() &&
121506c3fb27SDimitry Andric             isFirstBufInBound(C, S, BufV, BufTy, SizeV, SizeTy)) {
121606c3fb27SDimitry Andric           ITraits.setTrait(
121706c3fb27SDimitry Andric               R,
121806c3fb27SDimitry Andric               RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
121906c3fb27SDimitry Andric         }
122006c3fb27SDimitry Andric         return false;
122106c3fb27SDimitry Andric       };
122206c3fb27SDimitry Andric 
122306c3fb27SDimitry Andric   return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
122406c3fb27SDimitry Andric }
122506c3fb27SDimitry Andric 
122606c3fb27SDimitry Andric ProgramStateRef
122706c3fb27SDimitry Andric CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
122806c3fb27SDimitry Andric     CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) {
122906c3fb27SDimitry Andric   auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
123006c3fb27SDimitry Andric                                         const MemRegion *R) {
123106c3fb27SDimitry Andric     return isa<FieldRegion>(R);
123206c3fb27SDimitry Andric   };
123306c3fb27SDimitry Andric 
123406c3fb27SDimitry Andric   return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
123506c3fb27SDimitry Andric }
123606c3fb27SDimitry Andric 
123706c3fb27SDimitry Andric ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
123806c3fb27SDimitry Andric     CheckerContext &C, ProgramStateRef S, const Expr *BufE, SVal BufV) {
123906c3fb27SDimitry Andric   auto InvalidationTraitOperations =
124006c3fb27SDimitry Andric       [](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) {
124106c3fb27SDimitry Andric         if (MemRegion::FieldRegionKind == R->getKind())
124206c3fb27SDimitry Andric           ITraits.setTrait(
124306c3fb27SDimitry Andric               R,
124406c3fb27SDimitry Andric               RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
124506c3fb27SDimitry Andric         return false;
124606c3fb27SDimitry Andric       };
124706c3fb27SDimitry Andric 
124806c3fb27SDimitry Andric   return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
124906c3fb27SDimitry Andric }
125006c3fb27SDimitry Andric 
125106c3fb27SDimitry Andric ProgramStateRef CStringChecker::invalidateSourceBuffer(CheckerContext &C,
125206c3fb27SDimitry Andric                                                        ProgramStateRef S,
125306c3fb27SDimitry Andric                                                        const Expr *BufE,
125406c3fb27SDimitry Andric                                                        SVal BufV) {
125506c3fb27SDimitry Andric   auto InvalidationTraitOperations =
125606c3fb27SDimitry Andric       [](RegionAndSymbolInvalidationTraits &ITraits, const MemRegion *R) {
125706c3fb27SDimitry Andric         ITraits.setTrait(
125806c3fb27SDimitry Andric             R->getBaseRegion(),
125906c3fb27SDimitry Andric             RegionAndSymbolInvalidationTraits::TK_PreserveContents);
126006c3fb27SDimitry Andric         ITraits.setTrait(R,
126106c3fb27SDimitry Andric                          RegionAndSymbolInvalidationTraits::TK_SuppressEscape);
126206c3fb27SDimitry Andric         return true;
126306c3fb27SDimitry Andric       };
126406c3fb27SDimitry Andric 
126506c3fb27SDimitry Andric   return invalidateBufferAux(C, S, BufE, BufV, InvalidationTraitOperations);
126606c3fb27SDimitry Andric }
126706c3fb27SDimitry Andric 
126806c3fb27SDimitry Andric ProgramStateRef CStringChecker::invalidateBufferAux(
126906c3fb27SDimitry Andric     CheckerContext &C, ProgramStateRef State, const Expr *E, SVal V,
127006c3fb27SDimitry Andric     llvm::function_ref<bool(RegionAndSymbolInvalidationTraits &,
127106c3fb27SDimitry Andric                             const MemRegion *)>
127206c3fb27SDimitry Andric         InvalidationTraitOperations) {
1273bdd1243dSDimitry Andric   std::optional<Loc> L = V.getAs<Loc>();
12740b57cec5SDimitry Andric   if (!L)
127506c3fb27SDimitry Andric     return State;
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric   // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes
12780b57cec5SDimitry Andric   // some assumptions about the value that CFRefCount can't. Even so, it should
12790b57cec5SDimitry Andric   // probably be refactored.
1280bdd1243dSDimitry Andric   if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
12810b57cec5SDimitry Andric     const MemRegion *R = MR->getRegion()->StripCasts();
12820b57cec5SDimitry Andric 
12830b57cec5SDimitry Andric     // Are we dealing with an ElementRegion?  If so, we should be invalidating
12840b57cec5SDimitry Andric     // the super-region.
12850b57cec5SDimitry Andric     if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
12860b57cec5SDimitry Andric       R = ER->getSuperRegion();
12870b57cec5SDimitry Andric       // FIXME: What about layers of ElementRegions?
12880b57cec5SDimitry Andric     }
12890b57cec5SDimitry Andric 
12900b57cec5SDimitry Andric     // Invalidate this region.
12910b57cec5SDimitry Andric     const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
12920b57cec5SDimitry Andric     RegionAndSymbolInvalidationTraits ITraits;
129306c3fb27SDimitry Andric     bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
12940b57cec5SDimitry Andric 
129506c3fb27SDimitry Andric     return State->invalidateRegions(R, E, C.blockCount(), LCtx,
12960b57cec5SDimitry Andric                                     CausesPointerEscape, nullptr, nullptr,
12970b57cec5SDimitry Andric                                     &ITraits);
12980b57cec5SDimitry Andric   }
12990b57cec5SDimitry Andric 
13000b57cec5SDimitry Andric   // If we have a non-region value by chance, just remove the binding.
13010b57cec5SDimitry Andric   // FIXME: is this necessary or correct? This handles the non-Region
13020b57cec5SDimitry Andric   //  cases.  Is it ever valid to store to these?
130306c3fb27SDimitry Andric   return State->killBinding(*L);
13040b57cec5SDimitry Andric }
13050b57cec5SDimitry Andric 
13060b57cec5SDimitry Andric bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
13070b57cec5SDimitry Andric                                      const MemRegion *MR) {
13080b57cec5SDimitry Andric   switch (MR->getKind()) {
13090b57cec5SDimitry Andric   case MemRegion::FunctionCodeRegionKind: {
1310480093f4SDimitry Andric     if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
13110b57cec5SDimitry Andric       os << "the address of the function '" << *FD << '\'';
13120b57cec5SDimitry Andric     else
13130b57cec5SDimitry Andric       os << "the address of a function";
13140b57cec5SDimitry Andric     return true;
13150b57cec5SDimitry Andric   }
13160b57cec5SDimitry Andric   case MemRegion::BlockCodeRegionKind:
13170b57cec5SDimitry Andric     os << "block text";
13180b57cec5SDimitry Andric     return true;
13190b57cec5SDimitry Andric   case MemRegion::BlockDataRegionKind:
13200b57cec5SDimitry Andric     os << "a block";
13210b57cec5SDimitry Andric     return true;
13220b57cec5SDimitry Andric   case MemRegion::CXXThisRegionKind:
13230b57cec5SDimitry Andric   case MemRegion::CXXTempObjectRegionKind:
1324480093f4SDimitry Andric     os << "a C++ temp object of type "
132581ad6265SDimitry Andric        << cast<TypedValueRegion>(MR)->getValueType();
13260b57cec5SDimitry Andric     return true;
13275ffd83dbSDimitry Andric   case MemRegion::NonParamVarRegionKind:
132881ad6265SDimitry Andric     os << "a variable of type" << cast<TypedValueRegion>(MR)->getValueType();
13290b57cec5SDimitry Andric     return true;
13305ffd83dbSDimitry Andric   case MemRegion::ParamVarRegionKind:
133181ad6265SDimitry Andric     os << "a parameter of type" << cast<TypedValueRegion>(MR)->getValueType();
13325ffd83dbSDimitry Andric     return true;
13330b57cec5SDimitry Andric   case MemRegion::FieldRegionKind:
133481ad6265SDimitry Andric     os << "a field of type " << cast<TypedValueRegion>(MR)->getValueType();
13350b57cec5SDimitry Andric     return true;
13360b57cec5SDimitry Andric   case MemRegion::ObjCIvarRegionKind:
1337480093f4SDimitry Andric     os << "an instance variable of type "
133881ad6265SDimitry Andric        << cast<TypedValueRegion>(MR)->getValueType();
13390b57cec5SDimitry Andric     return true;
13400b57cec5SDimitry Andric   default:
13410b57cec5SDimitry Andric     return false;
13420b57cec5SDimitry Andric   }
13430b57cec5SDimitry Andric }
13440b57cec5SDimitry Andric 
13450b57cec5SDimitry Andric bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal,
13460b57cec5SDimitry Andric                                const Expr *Size, CheckerContext &C,
13470b57cec5SDimitry Andric                                ProgramStateRef &State) {
13480b57cec5SDimitry Andric   SVal MemVal = C.getSVal(DstBuffer);
13490b57cec5SDimitry Andric   SVal SizeVal = C.getSVal(Size);
13500b57cec5SDimitry Andric   const MemRegion *MR = MemVal.getAsRegion();
13510b57cec5SDimitry Andric   if (!MR)
13520b57cec5SDimitry Andric     return false;
13530b57cec5SDimitry Andric 
13540b57cec5SDimitry Andric   // We're about to model memset by producing a "default binding" in the Store.
13550b57cec5SDimitry Andric   // Our current implementation - RegionStore - doesn't support default bindings
13560b57cec5SDimitry Andric   // that don't cover the whole base region. So we should first get the offset
13570b57cec5SDimitry Andric   // and the base region to figure out whether the offset of buffer is 0.
13580b57cec5SDimitry Andric   RegionOffset Offset = MR->getAsOffset();
13590b57cec5SDimitry Andric   const MemRegion *BR = Offset.getRegion();
13600b57cec5SDimitry Andric 
1361bdd1243dSDimitry Andric   std::optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>();
13620b57cec5SDimitry Andric   if (!SizeNL)
13630b57cec5SDimitry Andric     return false;
13640b57cec5SDimitry Andric 
13650b57cec5SDimitry Andric   SValBuilder &svalBuilder = C.getSValBuilder();
13660b57cec5SDimitry Andric   ASTContext &Ctx = C.getASTContext();
13670b57cec5SDimitry Andric 
13680b57cec5SDimitry Andric   // void *memset(void *dest, int ch, size_t count);
13690b57cec5SDimitry Andric   // For now we can only handle the case of offset is 0 and concrete char value.
13700b57cec5SDimitry Andric   if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
13710b57cec5SDimitry Andric       Offset.getOffset() == 0) {
13725ffd83dbSDimitry Andric     // Get the base region's size.
1373fe6060f1SDimitry Andric     DefinedOrUnknownSVal SizeDV = getDynamicExtent(State, BR, svalBuilder);
13740b57cec5SDimitry Andric 
13750b57cec5SDimitry Andric     ProgramStateRef StateWholeReg, StateNotWholeReg;
13760b57cec5SDimitry Andric     std::tie(StateWholeReg, StateNotWholeReg) =
13775ffd83dbSDimitry Andric         State->assume(svalBuilder.evalEQ(State, SizeDV, *SizeNL));
13780b57cec5SDimitry Andric 
13790b57cec5SDimitry Andric     // With the semantic of 'memset()', we should convert the CharVal to
13800b57cec5SDimitry Andric     // unsigned char.
13810b57cec5SDimitry Andric     CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy);
13820b57cec5SDimitry Andric 
13830b57cec5SDimitry Andric     ProgramStateRef StateNullChar, StateNonNullChar;
13840b57cec5SDimitry Andric     std::tie(StateNullChar, StateNonNullChar) =
13850b57cec5SDimitry Andric         assumeZero(C, State, CharVal, Ctx.UnsignedCharTy);
13860b57cec5SDimitry Andric 
13870b57cec5SDimitry Andric     if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
13880b57cec5SDimitry Andric         !StateNonNullChar) {
13890b57cec5SDimitry Andric       // If the 'memset()' acts on the whole region of destination buffer and
13900b57cec5SDimitry Andric       // the value of the second argument of 'memset()' is zero, bind the second
13910b57cec5SDimitry Andric       // argument's value to the destination buffer with 'default binding'.
13920b57cec5SDimitry Andric       // FIXME: Since there is no perfect way to bind the non-zero character, we
13930b57cec5SDimitry Andric       // can only deal with zero value here. In the future, we need to deal with
13940b57cec5SDimitry Andric       // the binding of non-zero value in the case of whole region.
13950b57cec5SDimitry Andric       State = State->bindDefaultZero(svalBuilder.makeLoc(BR),
13960b57cec5SDimitry Andric                                      C.getLocationContext());
13970b57cec5SDimitry Andric     } else {
13980b57cec5SDimitry Andric       // If the destination buffer's extent is not equal to the value of
13990b57cec5SDimitry Andric       // third argument, just invalidate buffer.
140006c3fb27SDimitry Andric       State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal,
140106c3fb27SDimitry Andric                                                 SizeVal, Size->getType());
14020b57cec5SDimitry Andric     }
14030b57cec5SDimitry Andric 
14040b57cec5SDimitry Andric     if (StateNullChar && !StateNonNullChar) {
14050b57cec5SDimitry Andric       // If the value of the second argument of 'memset()' is zero, set the
14060b57cec5SDimitry Andric       // string length of destination buffer to 0 directly.
14070b57cec5SDimitry Andric       State = setCStringLength(State, MR,
14080b57cec5SDimitry Andric                                svalBuilder.makeZeroVal(Ctx.getSizeType()));
14090b57cec5SDimitry Andric     } else if (!StateNullChar && StateNonNullChar) {
14100b57cec5SDimitry Andric       SVal NewStrLen = svalBuilder.getMetadataSymbolVal(
14110b57cec5SDimitry Andric           CStringChecker::getTag(), MR, DstBuffer, Ctx.getSizeType(),
14120b57cec5SDimitry Andric           C.getLocationContext(), C.blockCount());
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric       // If the value of second argument is not zero, then the string length
14150b57cec5SDimitry Andric       // is at least the size argument.
14160b57cec5SDimitry Andric       SVal NewStrLenGESize = svalBuilder.evalBinOp(
14170b57cec5SDimitry Andric           State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType());
14180b57cec5SDimitry Andric 
14190b57cec5SDimitry Andric       State = setCStringLength(
14200b57cec5SDimitry Andric           State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(), true),
14210b57cec5SDimitry Andric           MR, NewStrLen);
14220b57cec5SDimitry Andric     }
14230b57cec5SDimitry Andric   } else {
14240b57cec5SDimitry Andric     // If the offset is not zero and char value is not concrete, we can do
14250b57cec5SDimitry Andric     // nothing but invalidate the buffer.
142606c3fb27SDimitry Andric     State = invalidateDestinationBufferBySize(C, State, DstBuffer, MemVal,
142706c3fb27SDimitry Andric                                               SizeVal, Size->getType());
14280b57cec5SDimitry Andric   }
14290b57cec5SDimitry Andric   return true;
14300b57cec5SDimitry Andric }
14310b57cec5SDimitry Andric 
14320b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14330b57cec5SDimitry Andric // evaluation of individual function calls.
14340b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14350b57cec5SDimitry Andric 
1436647cbc5dSDimitry Andric void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
14375ffd83dbSDimitry Andric                                     ProgramStateRef state, SizeArgExpr Size,
14385ffd83dbSDimitry Andric                                     DestinationArgExpr Dest,
14395ffd83dbSDimitry Andric                                     SourceArgExpr Source, bool Restricted,
1440bdd1243dSDimitry Andric                                     bool IsMempcpy, CharKind CK) const {
14410b57cec5SDimitry Andric   CurrentFunctionDescription = "memory copy function";
14420b57cec5SDimitry Andric 
14430b57cec5SDimitry Andric   // See if the size argument is zero.
14440b57cec5SDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
14455ffd83dbSDimitry Andric   SVal sizeVal = state->getSVal(Size.Expression, LCtx);
14465ffd83dbSDimitry Andric   QualType sizeTy = Size.Expression->getType();
14470b57cec5SDimitry Andric 
14480b57cec5SDimitry Andric   ProgramStateRef stateZeroSize, stateNonZeroSize;
14490b57cec5SDimitry Andric   std::tie(stateZeroSize, stateNonZeroSize) =
14500b57cec5SDimitry Andric       assumeZero(C, state, sizeVal, sizeTy);
14510b57cec5SDimitry Andric 
14520b57cec5SDimitry Andric   // Get the value of the Dest.
14535ffd83dbSDimitry Andric   SVal destVal = state->getSVal(Dest.Expression, LCtx);
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric   // If the size is zero, there won't be any actual memory access, so
14560b57cec5SDimitry Andric   // just bind the return value to the destination buffer and return.
14570b57cec5SDimitry Andric   if (stateZeroSize && !stateNonZeroSize) {
1458647cbc5dSDimitry Andric     stateZeroSize =
1459647cbc5dSDimitry Andric         stateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, destVal);
14600b57cec5SDimitry Andric     C.addTransition(stateZeroSize);
14610b57cec5SDimitry Andric     return;
14620b57cec5SDimitry Andric   }
14630b57cec5SDimitry Andric 
14640b57cec5SDimitry Andric   // If the size can be nonzero, we have to check the other arguments.
14650b57cec5SDimitry Andric   if (stateNonZeroSize) {
1466*0fca6ea1SDimitry Andric     // TODO: If Size is tainted and we cannot prove that it is smaller or equal
1467*0fca6ea1SDimitry Andric     // to the size of the destination buffer, then emit a warning
1468*0fca6ea1SDimitry Andric     // that an attacker may provoke a buffer overflow error.
14690b57cec5SDimitry Andric     state = stateNonZeroSize;
14700b57cec5SDimitry Andric 
14710b57cec5SDimitry Andric     // Ensure the destination is not null. If it is NULL there will be a
14720b57cec5SDimitry Andric     // NULL pointer dereference.
14735ffd83dbSDimitry Andric     state = checkNonNull(C, state, Dest, destVal);
14740b57cec5SDimitry Andric     if (!state)
14750b57cec5SDimitry Andric       return;
14760b57cec5SDimitry Andric 
14770b57cec5SDimitry Andric     // Get the value of the Src.
14785ffd83dbSDimitry Andric     SVal srcVal = state->getSVal(Source.Expression, LCtx);
14790b57cec5SDimitry Andric 
14800b57cec5SDimitry Andric     // Ensure the source is not null. If it is NULL there will be a
14810b57cec5SDimitry Andric     // NULL pointer dereference.
14825ffd83dbSDimitry Andric     state = checkNonNull(C, state, Source, srcVal);
14830b57cec5SDimitry Andric     if (!state)
14840b57cec5SDimitry Andric       return;
14850b57cec5SDimitry Andric 
14860b57cec5SDimitry Andric     // Ensure the accesses are valid and that the buffers do not overlap.
1487bdd1243dSDimitry Andric     state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write, CK);
1488bdd1243dSDimitry Andric     state = CheckBufferAccess(C, state, Source, Size, AccessKind::read, CK);
14895ffd83dbSDimitry Andric 
14900b57cec5SDimitry Andric     if (Restricted)
1491bdd1243dSDimitry Andric       state = CheckOverlap(C, state, Size, Dest, Source, CK);
14920b57cec5SDimitry Andric 
14930b57cec5SDimitry Andric     if (!state)
14940b57cec5SDimitry Andric       return;
14950b57cec5SDimitry Andric 
14960b57cec5SDimitry Andric     // If this is mempcpy, get the byte after the last byte copied and
14970b57cec5SDimitry Andric     // bind the expr.
14980b57cec5SDimitry Andric     if (IsMempcpy) {
14990b57cec5SDimitry Andric       // Get the byte after the last byte copied.
15000b57cec5SDimitry Andric       SValBuilder &SvalBuilder = C.getSValBuilder();
15010b57cec5SDimitry Andric       ASTContext &Ctx = SvalBuilder.getContext();
1502bdd1243dSDimitry Andric       QualType CharPtrTy = getCharPtrType(Ctx, CK);
15030b57cec5SDimitry Andric       SVal DestRegCharVal =
15045ffd83dbSDimitry Andric           SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType());
15050b57cec5SDimitry Andric       SVal lastElement = C.getSValBuilder().evalBinOp(
15065ffd83dbSDimitry Andric           state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
15070b57cec5SDimitry Andric       // If we don't know how much we copied, we can at least
15080b57cec5SDimitry Andric       // conjure a return value for later.
15090b57cec5SDimitry Andric       if (lastElement.isUnknown())
1510647cbc5dSDimitry Andric         lastElement = C.getSValBuilder().conjureSymbolVal(
1511647cbc5dSDimitry Andric             nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
15120b57cec5SDimitry Andric 
15130b57cec5SDimitry Andric       // The byte after the last byte copied is the return value.
1514647cbc5dSDimitry Andric       state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement);
15150b57cec5SDimitry Andric     } else {
15160b57cec5SDimitry Andric       // All other copies return the destination buffer.
15170b57cec5SDimitry Andric       // (Well, bcopy() has a void return type, but this won't hurt.)
1518647cbc5dSDimitry Andric       state = state->BindExpr(Call.getOriginExpr(), LCtx, destVal);
15190b57cec5SDimitry Andric     }
15200b57cec5SDimitry Andric 
15210b57cec5SDimitry Andric     // Invalidate the destination (regular invalidation without pointer-escaping
15220b57cec5SDimitry Andric     // the address of the top-level region).
15230b57cec5SDimitry Andric     // FIXME: Even if we can't perfectly model the copy, we should see if we
15240b57cec5SDimitry Andric     // can use LazyCompoundVals to copy the source values into the destination.
15250b57cec5SDimitry Andric     // This would probably remove any existing bindings past the end of the
15260b57cec5SDimitry Andric     // copied region, but that's still an improvement over blank invalidation.
152706c3fb27SDimitry Andric     state = invalidateDestinationBufferBySize(
152806c3fb27SDimitry Andric         C, state, Dest.Expression, C.getSVal(Dest.Expression), sizeVal,
152906c3fb27SDimitry Andric         Size.Expression->getType());
15300b57cec5SDimitry Andric 
15310b57cec5SDimitry Andric     // Invalidate the source (const-invalidation without const-pointer-escaping
15320b57cec5SDimitry Andric     // the address of the top-level region).
153306c3fb27SDimitry Andric     state = invalidateSourceBuffer(C, state, Source.Expression,
153406c3fb27SDimitry Andric                                    C.getSVal(Source.Expression));
15350b57cec5SDimitry Andric 
15360b57cec5SDimitry Andric     C.addTransition(state);
15370b57cec5SDimitry Andric   }
15380b57cec5SDimitry Andric }
15390b57cec5SDimitry Andric 
1540647cbc5dSDimitry Andric void CStringChecker::evalMemcpy(CheckerContext &C, const CallEvent &Call,
1541bdd1243dSDimitry Andric                                 CharKind CK) const {
15420b57cec5SDimitry Andric   // void *memcpy(void *restrict dst, const void *restrict src, size_t n);
15430b57cec5SDimitry Andric   // The return value is the address of the destination buffer.
1544647cbc5dSDimitry Andric   DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
1545647cbc5dSDimitry Andric   SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
1546647cbc5dSDimitry Andric   SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
15470b57cec5SDimitry Andric 
15485ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
15495ffd83dbSDimitry Andric 
15505ffd83dbSDimitry Andric   constexpr bool IsRestricted = true;
15515ffd83dbSDimitry Andric   constexpr bool IsMempcpy = false;
1552647cbc5dSDimitry Andric   evalCopyCommon(C, Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
15530b57cec5SDimitry Andric }
15540b57cec5SDimitry Andric 
1555647cbc5dSDimitry Andric void CStringChecker::evalMempcpy(CheckerContext &C, const CallEvent &Call,
1556bdd1243dSDimitry Andric                                  CharKind CK) const {
15570b57cec5SDimitry Andric   // void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
15580b57cec5SDimitry Andric   // The return value is a pointer to the byte following the last written byte.
1559647cbc5dSDimitry Andric   DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
1560647cbc5dSDimitry Andric   SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
1561647cbc5dSDimitry Andric   SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
15620b57cec5SDimitry Andric 
15635ffd83dbSDimitry Andric   constexpr bool IsRestricted = true;
15645ffd83dbSDimitry Andric   constexpr bool IsMempcpy = true;
1565647cbc5dSDimitry Andric   evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
1566647cbc5dSDimitry Andric                  IsMempcpy, CK);
15670b57cec5SDimitry Andric }
15680b57cec5SDimitry Andric 
1569647cbc5dSDimitry Andric void CStringChecker::evalMemmove(CheckerContext &C, const CallEvent &Call,
1570bdd1243dSDimitry Andric                                  CharKind CK) const {
15710b57cec5SDimitry Andric   // void *memmove(void *dst, const void *src, size_t n);
15720b57cec5SDimitry Andric   // The return value is the address of the destination buffer.
1573647cbc5dSDimitry Andric   DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
1574647cbc5dSDimitry Andric   SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
1575647cbc5dSDimitry Andric   SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
15760b57cec5SDimitry Andric 
15775ffd83dbSDimitry Andric   constexpr bool IsRestricted = false;
15785ffd83dbSDimitry Andric   constexpr bool IsMempcpy = false;
1579647cbc5dSDimitry Andric   evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
1580647cbc5dSDimitry Andric                  IsMempcpy, CK);
15810b57cec5SDimitry Andric }
15820b57cec5SDimitry Andric 
1583647cbc5dSDimitry Andric void CStringChecker::evalBcopy(CheckerContext &C, const CallEvent &Call) const {
15840b57cec5SDimitry Andric   // void bcopy(const void *src, void *dst, size_t n);
1585647cbc5dSDimitry Andric   SourceArgExpr Src{{Call.getArgExpr(0), 0}};
1586647cbc5dSDimitry Andric   DestinationArgExpr Dest = {{Call.getArgExpr(1), 1}};
1587647cbc5dSDimitry Andric   SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
15885ffd83dbSDimitry Andric 
15895ffd83dbSDimitry Andric   constexpr bool IsRestricted = false;
15905ffd83dbSDimitry Andric   constexpr bool IsMempcpy = false;
1591647cbc5dSDimitry Andric   evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
1592647cbc5dSDimitry Andric                  IsMempcpy, CharKind::Regular);
15930b57cec5SDimitry Andric }
15940b57cec5SDimitry Andric 
1595647cbc5dSDimitry Andric void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
1596bdd1243dSDimitry Andric                                 CharKind CK) const {
15970b57cec5SDimitry Andric   // int memcmp(const void *s1, const void *s2, size_t n);
15980b57cec5SDimitry Andric   CurrentFunctionDescription = "memory comparison function";
15990b57cec5SDimitry Andric 
1600647cbc5dSDimitry Andric   AnyArgExpr Left = {Call.getArgExpr(0), 0};
1601647cbc5dSDimitry Andric   AnyArgExpr Right = {Call.getArgExpr(1), 1};
1602647cbc5dSDimitry Andric   SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
16030b57cec5SDimitry Andric 
16045ffd83dbSDimitry Andric   ProgramStateRef State = C.getState();
16055ffd83dbSDimitry Andric   SValBuilder &Builder = C.getSValBuilder();
16065ffd83dbSDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
16070b57cec5SDimitry Andric 
16080b57cec5SDimitry Andric   // See if the size argument is zero.
16095ffd83dbSDimitry Andric   SVal sizeVal = State->getSVal(Size.Expression, LCtx);
16105ffd83dbSDimitry Andric   QualType sizeTy = Size.Expression->getType();
16110b57cec5SDimitry Andric 
16120b57cec5SDimitry Andric   ProgramStateRef stateZeroSize, stateNonZeroSize;
16130b57cec5SDimitry Andric   std::tie(stateZeroSize, stateNonZeroSize) =
16145ffd83dbSDimitry Andric       assumeZero(C, State, sizeVal, sizeTy);
16150b57cec5SDimitry Andric 
16160b57cec5SDimitry Andric   // If the size can be zero, the result will be 0 in that case, and we don't
16170b57cec5SDimitry Andric   // have to check either of the buffers.
16180b57cec5SDimitry Andric   if (stateZeroSize) {
16195ffd83dbSDimitry Andric     State = stateZeroSize;
1620647cbc5dSDimitry Andric     State = State->BindExpr(Call.getOriginExpr(), LCtx,
1621647cbc5dSDimitry Andric                             Builder.makeZeroVal(Call.getResultType()));
16225ffd83dbSDimitry Andric     C.addTransition(State);
16230b57cec5SDimitry Andric   }
16240b57cec5SDimitry Andric 
16250b57cec5SDimitry Andric   // If the size can be nonzero, we have to check the other arguments.
16260b57cec5SDimitry Andric   if (stateNonZeroSize) {
16275ffd83dbSDimitry Andric     State = stateNonZeroSize;
16280b57cec5SDimitry Andric     // If we know the two buffers are the same, we know the result is 0.
16290b57cec5SDimitry Andric     // First, get the two buffers' addresses. Another checker will have already
16300b57cec5SDimitry Andric     // made sure they're not undefined.
16310b57cec5SDimitry Andric     DefinedOrUnknownSVal LV =
16325ffd83dbSDimitry Andric         State->getSVal(Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
16330b57cec5SDimitry Andric     DefinedOrUnknownSVal RV =
16345ffd83dbSDimitry Andric         State->getSVal(Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
16350b57cec5SDimitry Andric 
16360b57cec5SDimitry Andric     // See if they are the same.
16375ffd83dbSDimitry Andric     ProgramStateRef SameBuffer, NotSameBuffer;
16385ffd83dbSDimitry Andric     std::tie(SameBuffer, NotSameBuffer) =
16395ffd83dbSDimitry Andric         State->assume(Builder.evalEQ(State, LV, RV));
16400b57cec5SDimitry Andric 
1641480093f4SDimitry Andric     // If the two arguments are the same buffer, we know the result is 0,
16420b57cec5SDimitry Andric     // and we only need to check one size.
16435ffd83dbSDimitry Andric     if (SameBuffer && !NotSameBuffer) {
16445ffd83dbSDimitry Andric       State = SameBuffer;
16455ffd83dbSDimitry Andric       State = CheckBufferAccess(C, State, Left, Size, AccessKind::read);
16465ffd83dbSDimitry Andric       if (State) {
1647647cbc5dSDimitry Andric         State = SameBuffer->BindExpr(Call.getOriginExpr(), LCtx,
1648647cbc5dSDimitry Andric                                      Builder.makeZeroVal(Call.getResultType()));
16495ffd83dbSDimitry Andric         C.addTransition(State);
16500b57cec5SDimitry Andric       }
1651480093f4SDimitry Andric       return;
16520b57cec5SDimitry Andric     }
16530b57cec5SDimitry Andric 
1654480093f4SDimitry Andric     // If the two arguments might be different buffers, we have to check
1655480093f4SDimitry Andric     // the size of both of them.
16565ffd83dbSDimitry Andric     assert(NotSameBuffer);
1657bdd1243dSDimitry Andric     State = CheckBufferAccess(C, State, Right, Size, AccessKind::read, CK);
1658bdd1243dSDimitry Andric     State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
16595ffd83dbSDimitry Andric     if (State) {
16600b57cec5SDimitry Andric       // The return value is the comparison result, which we don't know.
1661647cbc5dSDimitry Andric       SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
1662647cbc5dSDimitry Andric                                            C.blockCount());
1663647cbc5dSDimitry Andric       State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
16645ffd83dbSDimitry Andric       C.addTransition(State);
16650b57cec5SDimitry Andric     }
16660b57cec5SDimitry Andric   }
16670b57cec5SDimitry Andric }
16680b57cec5SDimitry Andric 
16690b57cec5SDimitry Andric void CStringChecker::evalstrLength(CheckerContext &C,
1670647cbc5dSDimitry Andric                                    const CallEvent &Call) const {
16710b57cec5SDimitry Andric   // size_t strlen(const char *s);
1672647cbc5dSDimitry Andric   evalstrLengthCommon(C, Call, /* IsStrnlen = */ false);
16730b57cec5SDimitry Andric }
16740b57cec5SDimitry Andric 
16750b57cec5SDimitry Andric void CStringChecker::evalstrnLength(CheckerContext &C,
1676647cbc5dSDimitry Andric                                     const CallEvent &Call) const {
16770b57cec5SDimitry Andric   // size_t strnlen(const char *s, size_t maxlen);
1678647cbc5dSDimitry Andric   evalstrLengthCommon(C, Call, /* IsStrnlen = */ true);
16790b57cec5SDimitry Andric }
16800b57cec5SDimitry Andric 
1681647cbc5dSDimitry Andric void CStringChecker::evalstrLengthCommon(CheckerContext &C,
1682647cbc5dSDimitry Andric                                          const CallEvent &Call,
16830b57cec5SDimitry Andric                                          bool IsStrnlen) const {
16840b57cec5SDimitry Andric   CurrentFunctionDescription = "string length function";
16850b57cec5SDimitry Andric   ProgramStateRef state = C.getState();
16860b57cec5SDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
16870b57cec5SDimitry Andric 
16880b57cec5SDimitry Andric   if (IsStrnlen) {
1689647cbc5dSDimitry Andric     const Expr *maxlenExpr = Call.getArgExpr(1);
16900b57cec5SDimitry Andric     SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
16910b57cec5SDimitry Andric 
16920b57cec5SDimitry Andric     ProgramStateRef stateZeroSize, stateNonZeroSize;
16930b57cec5SDimitry Andric     std::tie(stateZeroSize, stateNonZeroSize) =
16940b57cec5SDimitry Andric       assumeZero(C, state, maxlenVal, maxlenExpr->getType());
16950b57cec5SDimitry Andric 
16960b57cec5SDimitry Andric     // If the size can be zero, the result will be 0 in that case, and we don't
16970b57cec5SDimitry Andric     // have to check the string itself.
16980b57cec5SDimitry Andric     if (stateZeroSize) {
1699647cbc5dSDimitry Andric       SVal zero = C.getSValBuilder().makeZeroVal(Call.getResultType());
1700647cbc5dSDimitry Andric       stateZeroSize = stateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, zero);
17010b57cec5SDimitry Andric       C.addTransition(stateZeroSize);
17020b57cec5SDimitry Andric     }
17030b57cec5SDimitry Andric 
17040b57cec5SDimitry Andric     // If the size is GUARANTEED to be zero, we're done!
17050b57cec5SDimitry Andric     if (!stateNonZeroSize)
17060b57cec5SDimitry Andric       return;
17070b57cec5SDimitry Andric 
17080b57cec5SDimitry Andric     // Otherwise, record the assumption that the size is nonzero.
17090b57cec5SDimitry Andric     state = stateNonZeroSize;
17100b57cec5SDimitry Andric   }
17110b57cec5SDimitry Andric 
17120b57cec5SDimitry Andric   // Check that the string argument is non-null.
1713647cbc5dSDimitry Andric   AnyArgExpr Arg = {Call.getArgExpr(0), 0};
17145ffd83dbSDimitry Andric   SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
17155ffd83dbSDimitry Andric   state = checkNonNull(C, state, Arg, ArgVal);
17160b57cec5SDimitry Andric 
17170b57cec5SDimitry Andric   if (!state)
17180b57cec5SDimitry Andric     return;
17190b57cec5SDimitry Andric 
17205ffd83dbSDimitry Andric   SVal strLength = getCStringLength(C, state, Arg.Expression, ArgVal);
17210b57cec5SDimitry Andric 
17220b57cec5SDimitry Andric   // If the argument isn't a valid C string, there's no valid state to
17230b57cec5SDimitry Andric   // transition to.
17240b57cec5SDimitry Andric   if (strLength.isUndef())
17250b57cec5SDimitry Andric     return;
17260b57cec5SDimitry Andric 
17270b57cec5SDimitry Andric   DefinedOrUnknownSVal result = UnknownVal();
17280b57cec5SDimitry Andric 
17290b57cec5SDimitry Andric   // If the check is for strnlen() then bind the return value to no more than
17300b57cec5SDimitry Andric   // the maxlen value.
17310b57cec5SDimitry Andric   if (IsStrnlen) {
17320b57cec5SDimitry Andric     QualType cmpTy = C.getSValBuilder().getConditionType();
17330b57cec5SDimitry Andric 
17340b57cec5SDimitry Andric     // It's a little unfortunate to be getting this again,
17350b57cec5SDimitry Andric     // but it's not that expensive...
1736647cbc5dSDimitry Andric     const Expr *maxlenExpr = Call.getArgExpr(1);
17370b57cec5SDimitry Andric     SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
17380b57cec5SDimitry Andric 
1739bdd1243dSDimitry Andric     std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
1740bdd1243dSDimitry Andric     std::optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>();
17410b57cec5SDimitry Andric 
17420b57cec5SDimitry Andric     if (strLengthNL && maxlenValNL) {
17430b57cec5SDimitry Andric       ProgramStateRef stateStringTooLong, stateStringNotTooLong;
17440b57cec5SDimitry Andric 
17450b57cec5SDimitry Andric       // Check if the strLength is greater than the maxlen.
17460b57cec5SDimitry Andric       std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
17470b57cec5SDimitry Andric           C.getSValBuilder()
17480b57cec5SDimitry Andric               .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
17490b57cec5SDimitry Andric               .castAs<DefinedOrUnknownSVal>());
17500b57cec5SDimitry Andric 
17510b57cec5SDimitry Andric       if (stateStringTooLong && !stateStringNotTooLong) {
17520b57cec5SDimitry Andric         // If the string is longer than maxlen, return maxlen.
17530b57cec5SDimitry Andric         result = *maxlenValNL;
17540b57cec5SDimitry Andric       } else if (stateStringNotTooLong && !stateStringTooLong) {
17550b57cec5SDimitry Andric         // If the string is shorter than maxlen, return its length.
17560b57cec5SDimitry Andric         result = *strLengthNL;
17570b57cec5SDimitry Andric       }
17580b57cec5SDimitry Andric     }
17590b57cec5SDimitry Andric 
17600b57cec5SDimitry Andric     if (result.isUnknown()) {
17610b57cec5SDimitry Andric       // If we don't have enough information for a comparison, there's
17620b57cec5SDimitry Andric       // no guarantee the full string length will actually be returned.
17630b57cec5SDimitry Andric       // All we know is the return value is the min of the string length
17640b57cec5SDimitry Andric       // and the limit. This is better than nothing.
1765647cbc5dSDimitry Andric       result = C.getSValBuilder().conjureSymbolVal(
1766647cbc5dSDimitry Andric           nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
17670b57cec5SDimitry Andric       NonLoc resultNL = result.castAs<NonLoc>();
17680b57cec5SDimitry Andric 
17690b57cec5SDimitry Andric       if (strLengthNL) {
17700b57cec5SDimitry Andric         state = state->assume(C.getSValBuilder().evalBinOpNN(
17710b57cec5SDimitry Andric                                   state, BO_LE, resultNL, *strLengthNL, cmpTy)
17720b57cec5SDimitry Andric                                   .castAs<DefinedOrUnknownSVal>(), true);
17730b57cec5SDimitry Andric       }
17740b57cec5SDimitry Andric 
17750b57cec5SDimitry Andric       if (maxlenValNL) {
17760b57cec5SDimitry Andric         state = state->assume(C.getSValBuilder().evalBinOpNN(
17770b57cec5SDimitry Andric                                   state, BO_LE, resultNL, *maxlenValNL, cmpTy)
17780b57cec5SDimitry Andric                                   .castAs<DefinedOrUnknownSVal>(), true);
17790b57cec5SDimitry Andric       }
17800b57cec5SDimitry Andric     }
17810b57cec5SDimitry Andric 
17820b57cec5SDimitry Andric   } else {
17830b57cec5SDimitry Andric     // This is a plain strlen(), not strnlen().
17840b57cec5SDimitry Andric     result = strLength.castAs<DefinedOrUnknownSVal>();
17850b57cec5SDimitry Andric 
17860b57cec5SDimitry Andric     // If we don't know the length of the string, conjure a return
17870b57cec5SDimitry Andric     // value, so it can be used in constraints, at least.
17880b57cec5SDimitry Andric     if (result.isUnknown()) {
1789647cbc5dSDimitry Andric       result = C.getSValBuilder().conjureSymbolVal(
1790647cbc5dSDimitry Andric           nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
17910b57cec5SDimitry Andric     }
17920b57cec5SDimitry Andric   }
17930b57cec5SDimitry Andric 
17940b57cec5SDimitry Andric   // Bind the return value.
17950b57cec5SDimitry Andric   assert(!result.isUnknown() && "Should have conjured a value by now");
1796647cbc5dSDimitry Andric   state = state->BindExpr(Call.getOriginExpr(), LCtx, result);
17970b57cec5SDimitry Andric   C.addTransition(state);
17980b57cec5SDimitry Andric }
17990b57cec5SDimitry Andric 
1800647cbc5dSDimitry Andric void CStringChecker::evalStrcpy(CheckerContext &C,
1801647cbc5dSDimitry Andric                                 const CallEvent &Call) const {
18020b57cec5SDimitry Andric   // char *strcpy(char *restrict dst, const char *restrict src);
1803647cbc5dSDimitry Andric   evalStrcpyCommon(C, Call,
1804480093f4SDimitry Andric                    /* ReturnEnd = */ false,
1805480093f4SDimitry Andric                    /* IsBounded = */ false,
1806480093f4SDimitry Andric                    /* appendK = */ ConcatFnKind::none);
18070b57cec5SDimitry Andric }
18080b57cec5SDimitry Andric 
1809647cbc5dSDimitry Andric void CStringChecker::evalStrncpy(CheckerContext &C,
1810647cbc5dSDimitry Andric                                  const CallEvent &Call) const {
18110b57cec5SDimitry Andric   // char *strncpy(char *restrict dst, const char *restrict src, size_t n);
1812647cbc5dSDimitry Andric   evalStrcpyCommon(C, Call,
1813480093f4SDimitry Andric                    /* ReturnEnd = */ false,
1814480093f4SDimitry Andric                    /* IsBounded = */ true,
1815480093f4SDimitry Andric                    /* appendK = */ ConcatFnKind::none);
18160b57cec5SDimitry Andric }
18170b57cec5SDimitry Andric 
1818647cbc5dSDimitry Andric void CStringChecker::evalStpcpy(CheckerContext &C,
1819647cbc5dSDimitry Andric                                 const CallEvent &Call) const {
18200b57cec5SDimitry Andric   // char *stpcpy(char *restrict dst, const char *restrict src);
1821647cbc5dSDimitry Andric   evalStrcpyCommon(C, Call,
1822480093f4SDimitry Andric                    /* ReturnEnd = */ true,
1823480093f4SDimitry Andric                    /* IsBounded = */ false,
1824480093f4SDimitry Andric                    /* appendK = */ ConcatFnKind::none);
18250b57cec5SDimitry Andric }
18260b57cec5SDimitry Andric 
1827647cbc5dSDimitry Andric void CStringChecker::evalStrlcpy(CheckerContext &C,
1828647cbc5dSDimitry Andric                                  const CallEvent &Call) const {
1829480093f4SDimitry Andric   // size_t strlcpy(char *dest, const char *src, size_t size);
1830647cbc5dSDimitry Andric   evalStrcpyCommon(C, Call,
1831480093f4SDimitry Andric                    /* ReturnEnd = */ true,
1832480093f4SDimitry Andric                    /* IsBounded = */ true,
1833480093f4SDimitry Andric                    /* appendK = */ ConcatFnKind::none,
18340b57cec5SDimitry Andric                    /* returnPtr = */ false);
18350b57cec5SDimitry Andric }
18360b57cec5SDimitry Andric 
1837647cbc5dSDimitry Andric void CStringChecker::evalStrcat(CheckerContext &C,
1838647cbc5dSDimitry Andric                                 const CallEvent &Call) const {
18390b57cec5SDimitry Andric   // char *strcat(char *restrict s1, const char *restrict s2);
1840647cbc5dSDimitry Andric   evalStrcpyCommon(C, Call,
1841480093f4SDimitry Andric                    /* ReturnEnd = */ false,
1842480093f4SDimitry Andric                    /* IsBounded = */ false,
1843480093f4SDimitry Andric                    /* appendK = */ ConcatFnKind::strcat);
18440b57cec5SDimitry Andric }
18450b57cec5SDimitry Andric 
1846647cbc5dSDimitry Andric void CStringChecker::evalStrncat(CheckerContext &C,
1847647cbc5dSDimitry Andric                                  const CallEvent &Call) const {
18480b57cec5SDimitry Andric   // char *strncat(char *restrict s1, const char *restrict s2, size_t n);
1849647cbc5dSDimitry Andric   evalStrcpyCommon(C, Call,
1850480093f4SDimitry Andric                    /* ReturnEnd = */ false,
1851480093f4SDimitry Andric                    /* IsBounded = */ true,
1852480093f4SDimitry Andric                    /* appendK = */ ConcatFnKind::strcat);
18530b57cec5SDimitry Andric }
18540b57cec5SDimitry Andric 
1855647cbc5dSDimitry Andric void CStringChecker::evalStrlcat(CheckerContext &C,
1856647cbc5dSDimitry Andric                                  const CallEvent &Call) const {
1857480093f4SDimitry Andric   // size_t strlcat(char *dst, const char *src, size_t size);
1858480093f4SDimitry Andric   // It will append at most size - strlen(dst) - 1 bytes,
1859480093f4SDimitry Andric   // NULL-terminating the result.
1860647cbc5dSDimitry Andric   evalStrcpyCommon(C, Call,
1861480093f4SDimitry Andric                    /* ReturnEnd = */ false,
1862480093f4SDimitry Andric                    /* IsBounded = */ true,
1863480093f4SDimitry Andric                    /* appendK = */ ConcatFnKind::strlcat,
18640b57cec5SDimitry Andric                    /* returnPtr = */ false);
18650b57cec5SDimitry Andric }
18660b57cec5SDimitry Andric 
1867647cbc5dSDimitry Andric void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
1868480093f4SDimitry Andric                                       bool ReturnEnd, bool IsBounded,
1869480093f4SDimitry Andric                                       ConcatFnKind appendK,
1870480093f4SDimitry Andric                                       bool returnPtr) const {
1871480093f4SDimitry Andric   if (appendK == ConcatFnKind::none)
18720b57cec5SDimitry Andric     CurrentFunctionDescription = "string copy function";
1873480093f4SDimitry Andric   else
1874480093f4SDimitry Andric     CurrentFunctionDescription = "string concatenation function";
18755ffd83dbSDimitry Andric 
18760b57cec5SDimitry Andric   ProgramStateRef state = C.getState();
18770b57cec5SDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
18780b57cec5SDimitry Andric 
18790b57cec5SDimitry Andric   // Check that the destination is non-null.
1880647cbc5dSDimitry Andric   DestinationArgExpr Dst = {{Call.getArgExpr(0), 0}};
18815ffd83dbSDimitry Andric   SVal DstVal = state->getSVal(Dst.Expression, LCtx);
18825ffd83dbSDimitry Andric   state = checkNonNull(C, state, Dst, DstVal);
18830b57cec5SDimitry Andric   if (!state)
18840b57cec5SDimitry Andric     return;
18850b57cec5SDimitry Andric 
18860b57cec5SDimitry Andric   // Check that the source is non-null.
1887647cbc5dSDimitry Andric   SourceArgExpr srcExpr = {{Call.getArgExpr(1), 1}};
18885ffd83dbSDimitry Andric   SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
18895ffd83dbSDimitry Andric   state = checkNonNull(C, state, srcExpr, srcVal);
18900b57cec5SDimitry Andric   if (!state)
18910b57cec5SDimitry Andric     return;
18920b57cec5SDimitry Andric 
18930b57cec5SDimitry Andric   // Get the string length of the source.
18945ffd83dbSDimitry Andric   SVal strLength = getCStringLength(C, state, srcExpr.Expression, srcVal);
1895bdd1243dSDimitry Andric   std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
1896480093f4SDimitry Andric 
1897480093f4SDimitry Andric   // Get the string length of the destination buffer.
18985ffd83dbSDimitry Andric   SVal dstStrLength = getCStringLength(C, state, Dst.Expression, DstVal);
1899bdd1243dSDimitry Andric   std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
19000b57cec5SDimitry Andric 
19010b57cec5SDimitry Andric   // If the source isn't a valid C string, give up.
19020b57cec5SDimitry Andric   if (strLength.isUndef())
19030b57cec5SDimitry Andric     return;
19040b57cec5SDimitry Andric 
19050b57cec5SDimitry Andric   SValBuilder &svalBuilder = C.getSValBuilder();
19060b57cec5SDimitry Andric   QualType cmpTy = svalBuilder.getConditionType();
19070b57cec5SDimitry Andric   QualType sizeTy = svalBuilder.getContext().getSizeType();
19080b57cec5SDimitry Andric 
19090b57cec5SDimitry Andric   // These two values allow checking two kinds of errors:
19100b57cec5SDimitry Andric   // - actual overflows caused by a source that doesn't fit in the destination
19110b57cec5SDimitry Andric   // - potential overflows caused by a bound that could exceed the destination
19120b57cec5SDimitry Andric   SVal amountCopied = UnknownVal();
19130b57cec5SDimitry Andric   SVal maxLastElementIndex = UnknownVal();
19140b57cec5SDimitry Andric   const char *boundWarning = nullptr;
19150b57cec5SDimitry Andric 
19165ffd83dbSDimitry Andric   // FIXME: Why do we choose the srcExpr if the access has no size?
19175ffd83dbSDimitry Andric   //  Note that the 3rd argument of the call would be the size parameter.
191806c3fb27SDimitry Andric   SizeArgExpr SrcExprAsSizeDummy = {
191906c3fb27SDimitry Andric       {srcExpr.Expression, srcExpr.ArgumentIndex}};
19205ffd83dbSDimitry Andric   state = CheckOverlap(
19215ffd83dbSDimitry Andric       C, state,
1922647cbc5dSDimitry Andric       (IsBounded ? SizeArgExpr{{Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1923647cbc5dSDimitry Andric       Dst, srcExpr);
19240b57cec5SDimitry Andric 
19250b57cec5SDimitry Andric   if (!state)
19260b57cec5SDimitry Andric     return;
19270b57cec5SDimitry Andric 
19280b57cec5SDimitry Andric   // If the function is strncpy, strncat, etc... it is bounded.
1929480093f4SDimitry Andric   if (IsBounded) {
19300b57cec5SDimitry Andric     // Get the max number of characters to copy.
1931647cbc5dSDimitry Andric     SizeArgExpr lenExpr = {{Call.getArgExpr(2), 2}};
19325ffd83dbSDimitry Andric     SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
19330b57cec5SDimitry Andric 
19340b57cec5SDimitry Andric     // Protect against misdeclared strncpy().
19355ffd83dbSDimitry Andric     lenVal =
19365ffd83dbSDimitry Andric         svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
19370b57cec5SDimitry Andric 
1938bdd1243dSDimitry Andric     std::optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>();
19390b57cec5SDimitry Andric 
19400b57cec5SDimitry Andric     // If we know both values, we might be able to figure out how much
19410b57cec5SDimitry Andric     // we're copying.
19420b57cec5SDimitry Andric     if (strLengthNL && lenValNL) {
1943480093f4SDimitry Andric       switch (appendK) {
1944480093f4SDimitry Andric       case ConcatFnKind::none:
1945480093f4SDimitry Andric       case ConcatFnKind::strcat: {
19460b57cec5SDimitry Andric         ProgramStateRef stateSourceTooLong, stateSourceNotTooLong;
19470b57cec5SDimitry Andric         // Check if the max number to copy is less than the length of the src.
19480b57cec5SDimitry Andric         // If the bound is equal to the source length, strncpy won't null-
19490b57cec5SDimitry Andric         // terminate the result!
19500b57cec5SDimitry Andric         std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1951480093f4SDimitry Andric             svalBuilder
1952480093f4SDimitry Andric                 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
19530b57cec5SDimitry Andric                 .castAs<DefinedOrUnknownSVal>());
19540b57cec5SDimitry Andric 
19550b57cec5SDimitry Andric         if (stateSourceTooLong && !stateSourceNotTooLong) {
1956480093f4SDimitry Andric           // Max number to copy is less than the length of the src, so the
1957480093f4SDimitry Andric           // actual strLength copied is the max number arg.
19580b57cec5SDimitry Andric           state = stateSourceTooLong;
19590b57cec5SDimitry Andric           amountCopied = lenVal;
19600b57cec5SDimitry Andric 
19610b57cec5SDimitry Andric         } else if (!stateSourceTooLong && stateSourceNotTooLong) {
19620b57cec5SDimitry Andric           // The source buffer entirely fits in the bound.
19630b57cec5SDimitry Andric           state = stateSourceNotTooLong;
19640b57cec5SDimitry Andric           amountCopied = strLength;
19650b57cec5SDimitry Andric         }
1966480093f4SDimitry Andric         break;
1967480093f4SDimitry Andric       }
1968480093f4SDimitry Andric       case ConcatFnKind::strlcat:
1969480093f4SDimitry Andric         if (!dstStrLengthNL)
1970480093f4SDimitry Andric           return;
1971480093f4SDimitry Andric 
1972480093f4SDimitry Andric         // amountCopied = min (size - dstLen - 1 , srcLen)
1973480093f4SDimitry Andric         SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
1974480093f4SDimitry Andric                                                  *dstStrLengthNL, sizeTy);
197581ad6265SDimitry Andric         if (!isa<NonLoc>(freeSpace))
1976480093f4SDimitry Andric           return;
1977480093f4SDimitry Andric         freeSpace =
1978480093f4SDimitry Andric             svalBuilder.evalBinOp(state, BO_Sub, freeSpace,
1979480093f4SDimitry Andric                                   svalBuilder.makeIntVal(1, sizeTy), sizeTy);
1980bdd1243dSDimitry Andric         std::optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>();
1981480093f4SDimitry Andric 
1982480093f4SDimitry Andric         // While unlikely, it is possible that the subtraction is
1983480093f4SDimitry Andric         // too complex to compute, let's check whether it succeeded.
1984480093f4SDimitry Andric         if (!freeSpaceNL)
1985480093f4SDimitry Andric           return;
1986480093f4SDimitry Andric         SVal hasEnoughSpace = svalBuilder.evalBinOpNN(
1987480093f4SDimitry Andric             state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1988480093f4SDimitry Andric 
1989480093f4SDimitry Andric         ProgramStateRef TrueState, FalseState;
1990480093f4SDimitry Andric         std::tie(TrueState, FalseState) =
1991480093f4SDimitry Andric             state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>());
1992480093f4SDimitry Andric 
1993480093f4SDimitry Andric         // srcStrLength <= size - dstStrLength -1
1994480093f4SDimitry Andric         if (TrueState && !FalseState) {
1995480093f4SDimitry Andric           amountCopied = strLength;
19960b57cec5SDimitry Andric         }
19970b57cec5SDimitry Andric 
1998480093f4SDimitry Andric         // srcStrLength > size - dstStrLength -1
1999480093f4SDimitry Andric         if (!TrueState && FalseState) {
2000480093f4SDimitry Andric           amountCopied = freeSpace;
2001480093f4SDimitry Andric         }
2002480093f4SDimitry Andric 
2003480093f4SDimitry Andric         if (TrueState && FalseState)
2004480093f4SDimitry Andric           amountCopied = UnknownVal();
2005480093f4SDimitry Andric         break;
2006480093f4SDimitry Andric       }
2007480093f4SDimitry Andric     }
20080b57cec5SDimitry Andric     // We still want to know if the bound is known to be too large.
20090b57cec5SDimitry Andric     if (lenValNL) {
2010480093f4SDimitry Andric       switch (appendK) {
2011480093f4SDimitry Andric       case ConcatFnKind::strcat:
20120b57cec5SDimitry Andric         // For strncat, the check is strlen(dst) + lenVal < sizeof(dst)
20130b57cec5SDimitry Andric 
20140b57cec5SDimitry Andric         // Get the string length of the destination. If the destination is
20150b57cec5SDimitry Andric         // memory that can't have a string length, we shouldn't be copying
20160b57cec5SDimitry Andric         // into it anyway.
20170b57cec5SDimitry Andric         if (dstStrLength.isUndef())
20180b57cec5SDimitry Andric           return;
20190b57cec5SDimitry Andric 
2020480093f4SDimitry Andric         if (dstStrLengthNL) {
2021480093f4SDimitry Andric           maxLastElementIndex = svalBuilder.evalBinOpNN(
2022480093f4SDimitry Andric               state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2023480093f4SDimitry Andric 
20240b57cec5SDimitry Andric           boundWarning = "Size argument is greater than the free space in the "
20250b57cec5SDimitry Andric                          "destination buffer";
20260b57cec5SDimitry Andric         }
2027480093f4SDimitry Andric         break;
2028480093f4SDimitry Andric       case ConcatFnKind::none:
2029480093f4SDimitry Andric       case ConcatFnKind::strlcat:
2030480093f4SDimitry Andric         // For strncpy and strlcat, this is just checking
2031480093f4SDimitry Andric         //  that lenVal <= sizeof(dst).
20320b57cec5SDimitry Andric         // (Yes, strncpy and strncat differ in how they treat termination.
20330b57cec5SDimitry Andric         // strncat ALWAYS terminates, but strncpy doesn't.)
20340b57cec5SDimitry Andric 
20350b57cec5SDimitry Andric         // We need a special case for when the copy size is zero, in which
20360b57cec5SDimitry Andric         // case strncpy will do no work at all. Our bounds check uses n-1
20370b57cec5SDimitry Andric         // as the last element accessed, so n == 0 is problematic.
20380b57cec5SDimitry Andric         ProgramStateRef StateZeroSize, StateNonZeroSize;
20390b57cec5SDimitry Andric         std::tie(StateZeroSize, StateNonZeroSize) =
20400b57cec5SDimitry Andric             assumeZero(C, state, *lenValNL, sizeTy);
20410b57cec5SDimitry Andric 
20420b57cec5SDimitry Andric         // If the size is known to be zero, we're done.
20430b57cec5SDimitry Andric         if (StateZeroSize && !StateNonZeroSize) {
20440b57cec5SDimitry Andric           if (returnPtr) {
2045647cbc5dSDimitry Andric             StateZeroSize =
2046647cbc5dSDimitry Andric                 StateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, DstVal);
20470b57cec5SDimitry Andric           } else {
2048480093f4SDimitry Andric             if (appendK == ConcatFnKind::none) {
2049480093f4SDimitry Andric               // strlcpy returns strlen(src)
2050647cbc5dSDimitry Andric               StateZeroSize = StateZeroSize->BindExpr(Call.getOriginExpr(),
2051647cbc5dSDimitry Andric                                                       LCtx, strLength);
2052480093f4SDimitry Andric             } else {
2053480093f4SDimitry Andric               // strlcat returns strlen(src) + strlen(dst)
2054480093f4SDimitry Andric               SVal retSize = svalBuilder.evalBinOp(
2055480093f4SDimitry Andric                   state, BO_Add, strLength, dstStrLength, sizeTy);
2056647cbc5dSDimitry Andric               StateZeroSize =
2057647cbc5dSDimitry Andric                   StateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, retSize);
2058480093f4SDimitry Andric             }
20590b57cec5SDimitry Andric           }
20600b57cec5SDimitry Andric           C.addTransition(StateZeroSize);
20610b57cec5SDimitry Andric           return;
20620b57cec5SDimitry Andric         }
20630b57cec5SDimitry Andric 
20640b57cec5SDimitry Andric         // Otherwise, go ahead and figure out the last element we'll touch.
20650b57cec5SDimitry Andric         // We don't record the non-zero assumption here because we can't
20660b57cec5SDimitry Andric         // be sure. We won't warn on a possible zero.
20670b57cec5SDimitry Andric         NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
2068480093f4SDimitry Andric         maxLastElementIndex =
2069480093f4SDimitry Andric             svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
20700b57cec5SDimitry Andric         boundWarning = "Size argument is greater than the length of the "
20710b57cec5SDimitry Andric                        "destination buffer";
2072480093f4SDimitry Andric         break;
20730b57cec5SDimitry Andric       }
20740b57cec5SDimitry Andric     }
20750b57cec5SDimitry Andric   } else {
20760b57cec5SDimitry Andric     // The function isn't bounded. The amount copied should match the length
20770b57cec5SDimitry Andric     // of the source buffer.
20780b57cec5SDimitry Andric     amountCopied = strLength;
20790b57cec5SDimitry Andric   }
20800b57cec5SDimitry Andric 
20810b57cec5SDimitry Andric   assert(state);
20820b57cec5SDimitry Andric 
20830b57cec5SDimitry Andric   // This represents the number of characters copied into the destination
20840b57cec5SDimitry Andric   // buffer. (It may not actually be the strlen if the destination buffer
20850b57cec5SDimitry Andric   // is not terminated.)
20860b57cec5SDimitry Andric   SVal finalStrLength = UnknownVal();
2087480093f4SDimitry Andric   SVal strlRetVal = UnknownVal();
2088480093f4SDimitry Andric 
2089480093f4SDimitry Andric   if (appendK == ConcatFnKind::none && !returnPtr) {
2090480093f4SDimitry Andric     // strlcpy returns the sizeof(src)
2091480093f4SDimitry Andric     strlRetVal = strLength;
2092480093f4SDimitry Andric   }
20930b57cec5SDimitry Andric 
20940b57cec5SDimitry Andric   // If this is an appending function (strcat, strncat...) then set the
20950b57cec5SDimitry Andric   // string length to strlen(src) + strlen(dst) since the buffer will
20960b57cec5SDimitry Andric   // ultimately contain both.
2097480093f4SDimitry Andric   if (appendK != ConcatFnKind::none) {
20980b57cec5SDimitry Andric     // Get the string length of the destination. If the destination is memory
20990b57cec5SDimitry Andric     // that can't have a string length, we shouldn't be copying into it anyway.
21000b57cec5SDimitry Andric     if (dstStrLength.isUndef())
21010b57cec5SDimitry Andric       return;
21020b57cec5SDimitry Andric 
2103480093f4SDimitry Andric     if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2104480093f4SDimitry Andric       strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL,
2105480093f4SDimitry Andric                                            *dstStrLengthNL, sizeTy);
2106480093f4SDimitry Andric     }
2107480093f4SDimitry Andric 
2108bdd1243dSDimitry Andric     std::optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>();
21090b57cec5SDimitry Andric 
21100b57cec5SDimitry Andric     // If we know both string lengths, we might know the final string length.
2111480093f4SDimitry Andric     if (amountCopiedNL && dstStrLengthNL) {
21120b57cec5SDimitry Andric       // Make sure the two lengths together don't overflow a size_t.
2113480093f4SDimitry Andric       state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL);
21140b57cec5SDimitry Andric       if (!state)
21150b57cec5SDimitry Andric         return;
21160b57cec5SDimitry Andric 
2117480093f4SDimitry Andric       finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL,
21180b57cec5SDimitry Andric                                                *dstStrLengthNL, sizeTy);
21190b57cec5SDimitry Andric     }
21200b57cec5SDimitry Andric 
21210b57cec5SDimitry Andric     // If we couldn't get a single value for the final string length,
21220b57cec5SDimitry Andric     // we can at least bound it by the individual lengths.
21230b57cec5SDimitry Andric     if (finalStrLength.isUnknown()) {
21240b57cec5SDimitry Andric       // Try to get a "hypothetical" string length symbol, which we can later
21250b57cec5SDimitry Andric       // set as a real value if that turns out to be the case.
2126647cbc5dSDimitry Andric       finalStrLength =
2127647cbc5dSDimitry Andric           getCStringLength(C, state, Call.getOriginExpr(), DstVal, true);
21280b57cec5SDimitry Andric       assert(!finalStrLength.isUndef());
21290b57cec5SDimitry Andric 
2130bdd1243dSDimitry Andric       if (std::optional<NonLoc> finalStrLengthNL =
2131bdd1243dSDimitry Andric               finalStrLength.getAs<NonLoc>()) {
2132480093f4SDimitry Andric         if (amountCopiedNL && appendK == ConcatFnKind::none) {
2133480093f4SDimitry Andric           // we overwrite dst string with the src
21340b57cec5SDimitry Andric           // finalStrLength >= srcStrLength
2135480093f4SDimitry Andric           SVal sourceInResult = svalBuilder.evalBinOpNN(
2136480093f4SDimitry Andric               state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
21370b57cec5SDimitry Andric           state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(),
21380b57cec5SDimitry Andric                                 true);
21390b57cec5SDimitry Andric           if (!state)
21400b57cec5SDimitry Andric             return;
21410b57cec5SDimitry Andric         }
21420b57cec5SDimitry Andric 
2143480093f4SDimitry Andric         if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2144480093f4SDimitry Andric           // we extend the dst string with the src
21450b57cec5SDimitry Andric           // finalStrLength >= dstStrLength
21460b57cec5SDimitry Andric           SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE,
21470b57cec5SDimitry Andric                                                       *finalStrLengthNL,
21480b57cec5SDimitry Andric                                                       *dstStrLengthNL,
21490b57cec5SDimitry Andric                                                       cmpTy);
21500b57cec5SDimitry Andric           state =
21510b57cec5SDimitry Andric               state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true);
21520b57cec5SDimitry Andric           if (!state)
21530b57cec5SDimitry Andric             return;
21540b57cec5SDimitry Andric         }
21550b57cec5SDimitry Andric       }
21560b57cec5SDimitry Andric     }
21570b57cec5SDimitry Andric 
21580b57cec5SDimitry Andric   } else {
21590b57cec5SDimitry Andric     // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and
21600b57cec5SDimitry Andric     // the final string length will match the input string length.
21610b57cec5SDimitry Andric     finalStrLength = amountCopied;
21620b57cec5SDimitry Andric   }
21630b57cec5SDimitry Andric 
21640b57cec5SDimitry Andric   SVal Result;
21650b57cec5SDimitry Andric 
21660b57cec5SDimitry Andric   if (returnPtr) {
21670b57cec5SDimitry Andric     // The final result of the function will either be a pointer past the last
21680b57cec5SDimitry Andric     // copied element, or a pointer to the start of the destination buffer.
2169480093f4SDimitry Andric     Result = (ReturnEnd ? UnknownVal() : DstVal);
21700b57cec5SDimitry Andric   } else {
2171480093f4SDimitry Andric     if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2172480093f4SDimitry Andric       //strlcpy, strlcat
2173480093f4SDimitry Andric       Result = strlRetVal;
2174480093f4SDimitry Andric     else
21750b57cec5SDimitry Andric       Result = finalStrLength;
21760b57cec5SDimitry Andric   }
21770b57cec5SDimitry Andric 
21780b57cec5SDimitry Andric   assert(state);
21790b57cec5SDimitry Andric 
21800b57cec5SDimitry Andric   // If the destination is a MemRegion, try to check for a buffer overflow and
21810b57cec5SDimitry Andric   // record the new string length.
2182bdd1243dSDimitry Andric   if (std::optional<loc::MemRegionVal> dstRegVal =
21830b57cec5SDimitry Andric           DstVal.getAs<loc::MemRegionVal>()) {
21845ffd83dbSDimitry Andric     QualType ptrTy = Dst.Expression->getType();
21850b57cec5SDimitry Andric 
21860b57cec5SDimitry Andric     // If we have an exact value on a bounded copy, use that to check for
21870b57cec5SDimitry Andric     // overflows, rather than our estimate about how much is actually copied.
2188bdd1243dSDimitry Andric     if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) {
21895ffd83dbSDimitry Andric       SVal maxLastElement =
21905ffd83dbSDimitry Andric           svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
21915ffd83dbSDimitry Andric 
21925f757f3fSDimitry Andric       // Check if the first byte of the destination is writable.
21935f757f3fSDimitry Andric       state = CheckLocation(C, state, Dst, DstVal, AccessKind::write);
21945f757f3fSDimitry Andric       if (!state)
21955f757f3fSDimitry Andric         return;
21965f757f3fSDimitry Andric       // Check if the last byte of the destination is writable.
21975ffd83dbSDimitry Andric       state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write);
21980b57cec5SDimitry Andric       if (!state)
21990b57cec5SDimitry Andric         return;
22000b57cec5SDimitry Andric     }
22010b57cec5SDimitry Andric 
22020b57cec5SDimitry Andric     // Then, if the final length is known...
2203bdd1243dSDimitry Andric     if (std::optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) {
22040b57cec5SDimitry Andric       SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
22050b57cec5SDimitry Andric           *knownStrLength, ptrTy);
22060b57cec5SDimitry Andric 
22070b57cec5SDimitry Andric       // ...and we haven't checked the bound, we'll check the actual copy.
22080b57cec5SDimitry Andric       if (!boundWarning) {
22095f757f3fSDimitry Andric         // Check if the first byte of the destination is writable.
22105f757f3fSDimitry Andric         state = CheckLocation(C, state, Dst, DstVal, AccessKind::write);
22115f757f3fSDimitry Andric         if (!state)
22125f757f3fSDimitry Andric           return;
22135f757f3fSDimitry Andric         // Check if the last byte of the destination is writable.
22145ffd83dbSDimitry Andric         state = CheckLocation(C, state, Dst, lastElement, AccessKind::write);
22150b57cec5SDimitry Andric         if (!state)
22160b57cec5SDimitry Andric           return;
22170b57cec5SDimitry Andric       }
22180b57cec5SDimitry Andric 
22190b57cec5SDimitry Andric       // If this is a stpcpy-style copy, the last element is the return value.
2220480093f4SDimitry Andric       if (returnPtr && ReturnEnd)
22210b57cec5SDimitry Andric         Result = lastElement;
22220b57cec5SDimitry Andric     }
22230b57cec5SDimitry Andric 
22240b57cec5SDimitry Andric     // Invalidate the destination (regular invalidation without pointer-escaping
22250b57cec5SDimitry Andric     // the address of the top-level region). This must happen before we set the
22260b57cec5SDimitry Andric     // C string length because invalidation will clear the length.
22270b57cec5SDimitry Andric     // FIXME: Even if we can't perfectly model the copy, we should see if we
22280b57cec5SDimitry Andric     // can use LazyCompoundVals to copy the source values into the destination.
22290b57cec5SDimitry Andric     // This would probably remove any existing bindings past the end of the
22300b57cec5SDimitry Andric     // string, but that's still an improvement over blank invalidation.
223106c3fb27SDimitry Andric     state = invalidateDestinationBufferBySize(C, state, Dst.Expression,
223206c3fb27SDimitry Andric                                               *dstRegVal, amountCopied,
223306c3fb27SDimitry Andric                                               C.getASTContext().getSizeType());
22340b57cec5SDimitry Andric 
22350b57cec5SDimitry Andric     // Invalidate the source (const-invalidation without const-pointer-escaping
22360b57cec5SDimitry Andric     // the address of the top-level region).
223706c3fb27SDimitry Andric     state = invalidateSourceBuffer(C, state, srcExpr.Expression, srcVal);
22380b57cec5SDimitry Andric 
22390b57cec5SDimitry Andric     // Set the C string length of the destination, if we know it.
2240480093f4SDimitry Andric     if (IsBounded && (appendK == ConcatFnKind::none)) {
22410b57cec5SDimitry Andric       // strncpy is annoying in that it doesn't guarantee to null-terminate
22420b57cec5SDimitry Andric       // the result string. If the original string didn't fit entirely inside
22430b57cec5SDimitry Andric       // the bound (including the null-terminator), we don't know how long the
22440b57cec5SDimitry Andric       // result is.
22450b57cec5SDimitry Andric       if (amountCopied != strLength)
22460b57cec5SDimitry Andric         finalStrLength = UnknownVal();
22470b57cec5SDimitry Andric     }
22480b57cec5SDimitry Andric     state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
22490b57cec5SDimitry Andric   }
22500b57cec5SDimitry Andric 
22510b57cec5SDimitry Andric   assert(state);
22520b57cec5SDimitry Andric 
22530b57cec5SDimitry Andric   if (returnPtr) {
22540b57cec5SDimitry Andric     // If this is a stpcpy-style copy, but we were unable to check for a buffer
22550b57cec5SDimitry Andric     // overflow, we still need a result. Conjure a return value.
2256480093f4SDimitry Andric     if (ReturnEnd && Result.isUnknown()) {
2257647cbc5dSDimitry Andric       Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
2258647cbc5dSDimitry Andric                                             C.blockCount());
22590b57cec5SDimitry Andric     }
22600b57cec5SDimitry Andric   }
22610b57cec5SDimitry Andric   // Set the return value.
2262647cbc5dSDimitry Andric   state = state->BindExpr(Call.getOriginExpr(), LCtx, Result);
22630b57cec5SDimitry Andric   C.addTransition(state);
22640b57cec5SDimitry Andric }
22650b57cec5SDimitry Andric 
2266647cbc5dSDimitry Andric void CStringChecker::evalStrcmp(CheckerContext &C,
2267647cbc5dSDimitry Andric                                 const CallEvent &Call) const {
22680b57cec5SDimitry Andric   //int strcmp(const char *s1, const char *s2);
2269647cbc5dSDimitry Andric   evalStrcmpCommon(C, Call, /* IsBounded = */ false, /* IgnoreCase = */ false);
22700b57cec5SDimitry Andric }
22710b57cec5SDimitry Andric 
2272647cbc5dSDimitry Andric void CStringChecker::evalStrncmp(CheckerContext &C,
2273647cbc5dSDimitry Andric                                  const CallEvent &Call) const {
22740b57cec5SDimitry Andric   //int strncmp(const char *s1, const char *s2, size_t n);
2275647cbc5dSDimitry Andric   evalStrcmpCommon(C, Call, /* IsBounded = */ true, /* IgnoreCase = */ false);
22760b57cec5SDimitry Andric }
22770b57cec5SDimitry Andric 
22780b57cec5SDimitry Andric void CStringChecker::evalStrcasecmp(CheckerContext &C,
2279647cbc5dSDimitry Andric                                     const CallEvent &Call) const {
22800b57cec5SDimitry Andric   //int strcasecmp(const char *s1, const char *s2);
2281647cbc5dSDimitry Andric   evalStrcmpCommon(C, Call, /* IsBounded = */ false, /* IgnoreCase = */ true);
22820b57cec5SDimitry Andric }
22830b57cec5SDimitry Andric 
22840b57cec5SDimitry Andric void CStringChecker::evalStrncasecmp(CheckerContext &C,
2285647cbc5dSDimitry Andric                                      const CallEvent &Call) const {
22860b57cec5SDimitry Andric   //int strncasecmp(const char *s1, const char *s2, size_t n);
2287647cbc5dSDimitry Andric   evalStrcmpCommon(C, Call, /* IsBounded = */ true, /* IgnoreCase = */ true);
22880b57cec5SDimitry Andric }
22890b57cec5SDimitry Andric 
2290647cbc5dSDimitry Andric void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
2291480093f4SDimitry Andric                                       bool IsBounded, bool IgnoreCase) const {
22920b57cec5SDimitry Andric   CurrentFunctionDescription = "string comparison function";
22930b57cec5SDimitry Andric   ProgramStateRef state = C.getState();
22940b57cec5SDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
22950b57cec5SDimitry Andric 
22960b57cec5SDimitry Andric   // Check that the first string is non-null
2297647cbc5dSDimitry Andric   AnyArgExpr Left = {Call.getArgExpr(0), 0};
22985ffd83dbSDimitry Andric   SVal LeftVal = state->getSVal(Left.Expression, LCtx);
22995ffd83dbSDimitry Andric   state = checkNonNull(C, state, Left, LeftVal);
23000b57cec5SDimitry Andric   if (!state)
23010b57cec5SDimitry Andric     return;
23020b57cec5SDimitry Andric 
23030b57cec5SDimitry Andric   // Check that the second string is non-null.
2304647cbc5dSDimitry Andric   AnyArgExpr Right = {Call.getArgExpr(1), 1};
23055ffd83dbSDimitry Andric   SVal RightVal = state->getSVal(Right.Expression, LCtx);
23065ffd83dbSDimitry Andric   state = checkNonNull(C, state, Right, RightVal);
23070b57cec5SDimitry Andric   if (!state)
23080b57cec5SDimitry Andric     return;
23090b57cec5SDimitry Andric 
23100b57cec5SDimitry Andric   // Get the string length of the first string or give up.
23115ffd83dbSDimitry Andric   SVal LeftLength = getCStringLength(C, state, Left.Expression, LeftVal);
23125ffd83dbSDimitry Andric   if (LeftLength.isUndef())
23130b57cec5SDimitry Andric     return;
23140b57cec5SDimitry Andric 
23150b57cec5SDimitry Andric   // Get the string length of the second string or give up.
23165ffd83dbSDimitry Andric   SVal RightLength = getCStringLength(C, state, Right.Expression, RightVal);
23175ffd83dbSDimitry Andric   if (RightLength.isUndef())
23180b57cec5SDimitry Andric     return;
23190b57cec5SDimitry Andric 
23200b57cec5SDimitry Andric   // If we know the two buffers are the same, we know the result is 0.
23210b57cec5SDimitry Andric   // First, get the two buffers' addresses. Another checker will have already
23220b57cec5SDimitry Andric   // made sure they're not undefined.
23235ffd83dbSDimitry Andric   DefinedOrUnknownSVal LV = LeftVal.castAs<DefinedOrUnknownSVal>();
23245ffd83dbSDimitry Andric   DefinedOrUnknownSVal RV = RightVal.castAs<DefinedOrUnknownSVal>();
23250b57cec5SDimitry Andric 
23260b57cec5SDimitry Andric   // See if they are the same.
23270b57cec5SDimitry Andric   SValBuilder &svalBuilder = C.getSValBuilder();
23280b57cec5SDimitry Andric   DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
23290b57cec5SDimitry Andric   ProgramStateRef StSameBuf, StNotSameBuf;
23300b57cec5SDimitry Andric   std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
23310b57cec5SDimitry Andric 
23320b57cec5SDimitry Andric   // If the two arguments might be the same buffer, we know the result is 0,
23330b57cec5SDimitry Andric   // and we only need to check one size.
23340b57cec5SDimitry Andric   if (StSameBuf) {
2335647cbc5dSDimitry Andric     StSameBuf =
2336647cbc5dSDimitry Andric         StSameBuf->BindExpr(Call.getOriginExpr(), LCtx,
2337647cbc5dSDimitry Andric                             svalBuilder.makeZeroVal(Call.getResultType()));
23380b57cec5SDimitry Andric     C.addTransition(StSameBuf);
23390b57cec5SDimitry Andric 
23400b57cec5SDimitry Andric     // If the two arguments are GUARANTEED to be the same, we're done!
23410b57cec5SDimitry Andric     if (!StNotSameBuf)
23420b57cec5SDimitry Andric       return;
23430b57cec5SDimitry Andric   }
23440b57cec5SDimitry Andric 
23450b57cec5SDimitry Andric   assert(StNotSameBuf);
23460b57cec5SDimitry Andric   state = StNotSameBuf;
23470b57cec5SDimitry Andric 
23480b57cec5SDimitry Andric   // At this point we can go about comparing the two buffers.
23490b57cec5SDimitry Andric   // For now, we only do this if they're both known string literals.
23500b57cec5SDimitry Andric 
23510b57cec5SDimitry Andric   // Attempt to extract string literals from both expressions.
23525ffd83dbSDimitry Andric   const StringLiteral *LeftStrLiteral =
23535ffd83dbSDimitry Andric       getCStringLiteral(C, state, Left.Expression, LeftVal);
23545ffd83dbSDimitry Andric   const StringLiteral *RightStrLiteral =
23555ffd83dbSDimitry Andric       getCStringLiteral(C, state, Right.Expression, RightVal);
23560b57cec5SDimitry Andric   bool canComputeResult = false;
2357647cbc5dSDimitry Andric   SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
2358647cbc5dSDimitry Andric                                                 LCtx, C.blockCount());
23590b57cec5SDimitry Andric 
23605ffd83dbSDimitry Andric   if (LeftStrLiteral && RightStrLiteral) {
23615ffd83dbSDimitry Andric     StringRef LeftStrRef = LeftStrLiteral->getString();
23625ffd83dbSDimitry Andric     StringRef RightStrRef = RightStrLiteral->getString();
23630b57cec5SDimitry Andric 
2364480093f4SDimitry Andric     if (IsBounded) {
23650b57cec5SDimitry Andric       // Get the max number of characters to compare.
2366647cbc5dSDimitry Andric       const Expr *lenExpr = Call.getArgExpr(2);
23670b57cec5SDimitry Andric       SVal lenVal = state->getSVal(lenExpr, LCtx);
23680b57cec5SDimitry Andric 
23690b57cec5SDimitry Andric       // If the length is known, we can get the right substrings.
23700b57cec5SDimitry Andric       if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
23710b57cec5SDimitry Andric         // Create substrings of each to compare the prefix.
23725ffd83dbSDimitry Andric         LeftStrRef = LeftStrRef.substr(0, (size_t)len->getZExtValue());
23735ffd83dbSDimitry Andric         RightStrRef = RightStrRef.substr(0, (size_t)len->getZExtValue());
23740b57cec5SDimitry Andric         canComputeResult = true;
23750b57cec5SDimitry Andric       }
23760b57cec5SDimitry Andric     } else {
23770b57cec5SDimitry Andric       // This is a normal, unbounded strcmp.
23780b57cec5SDimitry Andric       canComputeResult = true;
23790b57cec5SDimitry Andric     }
23800b57cec5SDimitry Andric 
23810b57cec5SDimitry Andric     if (canComputeResult) {
23820b57cec5SDimitry Andric       // Real strcmp stops at null characters.
23835ffd83dbSDimitry Andric       size_t s1Term = LeftStrRef.find('\0');
23840b57cec5SDimitry Andric       if (s1Term != StringRef::npos)
23855ffd83dbSDimitry Andric         LeftStrRef = LeftStrRef.substr(0, s1Term);
23860b57cec5SDimitry Andric 
23875ffd83dbSDimitry Andric       size_t s2Term = RightStrRef.find('\0');
23880b57cec5SDimitry Andric       if (s2Term != StringRef::npos)
23895ffd83dbSDimitry Andric         RightStrRef = RightStrRef.substr(0, s2Term);
23900b57cec5SDimitry Andric 
23910b57cec5SDimitry Andric       // Use StringRef's comparison methods to compute the actual result.
2392fe6060f1SDimitry Andric       int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
23935ffd83dbSDimitry Andric                                   : LeftStrRef.compare(RightStrRef);
23940b57cec5SDimitry Andric 
23950b57cec5SDimitry Andric       // The strcmp function returns an integer greater than, equal to, or less
23960b57cec5SDimitry Andric       // than zero, [c11, p7.24.4.2].
23970b57cec5SDimitry Andric       if (compareRes == 0) {
2398647cbc5dSDimitry Andric         resultVal = svalBuilder.makeIntVal(compareRes, Call.getResultType());
23990b57cec5SDimitry Andric       }
24000b57cec5SDimitry Andric       else {
2401647cbc5dSDimitry Andric         DefinedSVal zeroVal = svalBuilder.makeIntVal(0, Call.getResultType());
24020b57cec5SDimitry Andric         // Constrain strcmp's result range based on the result of StringRef's
24030b57cec5SDimitry Andric         // comparison methods.
2404bdd1243dSDimitry Andric         BinaryOperatorKind op = (compareRes > 0) ? BO_GT : BO_LT;
24050b57cec5SDimitry Andric         SVal compareWithZero =
24060b57cec5SDimitry Andric           svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
24070b57cec5SDimitry Andric               svalBuilder.getConditionType());
24080b57cec5SDimitry Andric         DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>();
24090b57cec5SDimitry Andric         state = state->assume(compareWithZeroVal, true);
24100b57cec5SDimitry Andric       }
24110b57cec5SDimitry Andric     }
24120b57cec5SDimitry Andric   }
24130b57cec5SDimitry Andric 
2414647cbc5dSDimitry Andric   state = state->BindExpr(Call.getOriginExpr(), LCtx, resultVal);
24150b57cec5SDimitry Andric 
24160b57cec5SDimitry Andric   // Record this as a possible path.
24170b57cec5SDimitry Andric   C.addTransition(state);
24180b57cec5SDimitry Andric }
24190b57cec5SDimitry Andric 
2420647cbc5dSDimitry Andric void CStringChecker::evalStrsep(CheckerContext &C,
2421647cbc5dSDimitry Andric                                 const CallEvent &Call) const {
24220b57cec5SDimitry Andric   // char *strsep(char **stringp, const char *delim);
24235e801ac6SDimitry Andric   // Verify whether the search string parameter matches the return type.
2424647cbc5dSDimitry Andric   SourceArgExpr SearchStrPtr = {{Call.getArgExpr(0), 0}};
24255ffd83dbSDimitry Andric 
24265ffd83dbSDimitry Andric   QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2427647cbc5dSDimitry Andric   if (CharPtrTy.isNull() || Call.getResultType().getUnqualifiedType() !=
2428647cbc5dSDimitry Andric                                 CharPtrTy.getUnqualifiedType())
24290b57cec5SDimitry Andric     return;
24300b57cec5SDimitry Andric 
24310b57cec5SDimitry Andric   CurrentFunctionDescription = "strsep()";
24320b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
24330b57cec5SDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
24340b57cec5SDimitry Andric 
24350b57cec5SDimitry Andric   // Check that the search string pointer is non-null (though it may point to
24360b57cec5SDimitry Andric   // a null string).
24375ffd83dbSDimitry Andric   SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
24385ffd83dbSDimitry Andric   State = checkNonNull(C, State, SearchStrPtr, SearchStrVal);
24390b57cec5SDimitry Andric   if (!State)
24400b57cec5SDimitry Andric     return;
24410b57cec5SDimitry Andric 
24420b57cec5SDimitry Andric   // Check that the delimiter string is non-null.
2443647cbc5dSDimitry Andric   AnyArgExpr DelimStr = {Call.getArgExpr(1), 1};
24445ffd83dbSDimitry Andric   SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
24455ffd83dbSDimitry Andric   State = checkNonNull(C, State, DelimStr, DelimStrVal);
24460b57cec5SDimitry Andric   if (!State)
24470b57cec5SDimitry Andric     return;
24480b57cec5SDimitry Andric 
24490b57cec5SDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
24500b57cec5SDimitry Andric   SVal Result;
2451bdd1243dSDimitry Andric   if (std::optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
24520b57cec5SDimitry Andric     // Get the current value of the search string pointer, as a char*.
24530b57cec5SDimitry Andric     Result = State->getSVal(*SearchStrLoc, CharPtrTy);
24540b57cec5SDimitry Andric 
24550b57cec5SDimitry Andric     // Invalidate the search string, representing the change of one delimiter
24560b57cec5SDimitry Andric     // character to NUL.
245706c3fb27SDimitry Andric     // As the replacement never overflows, do not invalidate its super region.
245806c3fb27SDimitry Andric     State = invalidateDestinationBufferNeverOverflows(
245906c3fb27SDimitry Andric         C, State, SearchStrPtr.Expression, Result);
24600b57cec5SDimitry Andric 
24610b57cec5SDimitry Andric     // Overwrite the search string pointer. The new value is either an address
24620b57cec5SDimitry Andric     // further along in the same string, or NULL if there are no more tokens.
2463647cbc5dSDimitry Andric     State =
2464647cbc5dSDimitry Andric         State->bindLoc(*SearchStrLoc,
2465647cbc5dSDimitry Andric                        SVB.conjureSymbolVal(getTag(), Call.getOriginExpr(),
2466647cbc5dSDimitry Andric                                             LCtx, CharPtrTy, C.blockCount()),
24670b57cec5SDimitry Andric                        LCtx);
24680b57cec5SDimitry Andric   } else {
24690b57cec5SDimitry Andric     assert(SearchStrVal.isUnknown());
24700b57cec5SDimitry Andric     // Conjure a symbolic value. It's the best we can do.
2471647cbc5dSDimitry Andric     Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
2472647cbc5dSDimitry Andric                                   C.blockCount());
24730b57cec5SDimitry Andric   }
24740b57cec5SDimitry Andric 
24750b57cec5SDimitry Andric   // Set the return value, and finish.
2476647cbc5dSDimitry Andric   State = State->BindExpr(Call.getOriginExpr(), LCtx, Result);
24770b57cec5SDimitry Andric   C.addTransition(State);
24780b57cec5SDimitry Andric }
24790b57cec5SDimitry Andric 
24800b57cec5SDimitry Andric // These should probably be moved into a C++ standard library checker.
2481647cbc5dSDimitry Andric void CStringChecker::evalStdCopy(CheckerContext &C,
2482647cbc5dSDimitry Andric                                  const CallEvent &Call) const {
2483647cbc5dSDimitry Andric   evalStdCopyCommon(C, Call);
24840b57cec5SDimitry Andric }
24850b57cec5SDimitry Andric 
24860b57cec5SDimitry Andric void CStringChecker::evalStdCopyBackward(CheckerContext &C,
2487647cbc5dSDimitry Andric                                          const CallEvent &Call) const {
2488647cbc5dSDimitry Andric   evalStdCopyCommon(C, Call);
24890b57cec5SDimitry Andric }
24900b57cec5SDimitry Andric 
24910b57cec5SDimitry Andric void CStringChecker::evalStdCopyCommon(CheckerContext &C,
2492647cbc5dSDimitry Andric                                        const CallEvent &Call) const {
2493647cbc5dSDimitry Andric   if (!Call.getArgExpr(2)->getType()->isPointerType())
24940b57cec5SDimitry Andric     return;
24950b57cec5SDimitry Andric 
24960b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
24970b57cec5SDimitry Andric 
24980b57cec5SDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
24990b57cec5SDimitry Andric 
25000b57cec5SDimitry Andric   // template <class _InputIterator, class _OutputIterator>
25010b57cec5SDimitry Andric   // _OutputIterator
25020b57cec5SDimitry Andric   // copy(_InputIterator __first, _InputIterator __last,
25030b57cec5SDimitry Andric   //        _OutputIterator __result)
25040b57cec5SDimitry Andric 
25050b57cec5SDimitry Andric   // Invalidate the destination buffer
2506647cbc5dSDimitry Andric   const Expr *Dst = Call.getArgExpr(2);
25070b57cec5SDimitry Andric   SVal DstVal = State->getSVal(Dst, LCtx);
250806c3fb27SDimitry Andric   // FIXME: As we do not know how many items are copied, we also invalidate the
250906c3fb27SDimitry Andric   // super region containing the target location.
251006c3fb27SDimitry Andric   State =
251106c3fb27SDimitry Andric       invalidateDestinationBufferAlwaysEscapeSuperRegion(C, State, Dst, DstVal);
25120b57cec5SDimitry Andric 
25130b57cec5SDimitry Andric   SValBuilder &SVB = C.getSValBuilder();
25140b57cec5SDimitry Andric 
2515647cbc5dSDimitry Andric   SVal ResultVal =
2516647cbc5dSDimitry Andric       SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
2517647cbc5dSDimitry Andric   State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);
25180b57cec5SDimitry Andric 
25190b57cec5SDimitry Andric   C.addTransition(State);
25200b57cec5SDimitry Andric }
25210b57cec5SDimitry Andric 
2522647cbc5dSDimitry Andric void CStringChecker::evalMemset(CheckerContext &C,
2523647cbc5dSDimitry Andric                                 const CallEvent &Call) const {
25245ffd83dbSDimitry Andric   // void *memset(void *s, int c, size_t n);
25250b57cec5SDimitry Andric   CurrentFunctionDescription = "memory set function";
25260b57cec5SDimitry Andric 
2527647cbc5dSDimitry Andric   DestinationArgExpr Buffer = {{Call.getArgExpr(0), 0}};
2528647cbc5dSDimitry Andric   AnyArgExpr CharE = {Call.getArgExpr(1), 1};
2529647cbc5dSDimitry Andric   SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
25305ffd83dbSDimitry Andric 
25310b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
25320b57cec5SDimitry Andric 
25330b57cec5SDimitry Andric   // See if the size argument is zero.
25340b57cec5SDimitry Andric   const LocationContext *LCtx = C.getLocationContext();
25355ffd83dbSDimitry Andric   SVal SizeVal = C.getSVal(Size.Expression);
25365ffd83dbSDimitry Andric   QualType SizeTy = Size.Expression->getType();
25370b57cec5SDimitry Andric 
25385ffd83dbSDimitry Andric   ProgramStateRef ZeroSize, NonZeroSize;
25395ffd83dbSDimitry Andric   std::tie(ZeroSize, NonZeroSize) = assumeZero(C, State, SizeVal, SizeTy);
25400b57cec5SDimitry Andric 
25410b57cec5SDimitry Andric   // Get the value of the memory area.
25425ffd83dbSDimitry Andric   SVal BufferPtrVal = C.getSVal(Buffer.Expression);
25430b57cec5SDimitry Andric 
25440b57cec5SDimitry Andric   // If the size is zero, there won't be any actual memory access, so
25455ffd83dbSDimitry Andric   // just bind the return value to the buffer and return.
25465ffd83dbSDimitry Andric   if (ZeroSize && !NonZeroSize) {
2547647cbc5dSDimitry Andric     ZeroSize = ZeroSize->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
25485ffd83dbSDimitry Andric     C.addTransition(ZeroSize);
25490b57cec5SDimitry Andric     return;
25500b57cec5SDimitry Andric   }
25510b57cec5SDimitry Andric 
25520b57cec5SDimitry Andric   // Ensure the memory area is not null.
25530b57cec5SDimitry Andric   // If it is NULL there will be a NULL pointer dereference.
25545ffd83dbSDimitry Andric   State = checkNonNull(C, NonZeroSize, Buffer, BufferPtrVal);
25550b57cec5SDimitry Andric   if (!State)
25560b57cec5SDimitry Andric     return;
25570b57cec5SDimitry Andric 
25585ffd83dbSDimitry Andric   State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write);
25590b57cec5SDimitry Andric   if (!State)
25600b57cec5SDimitry Andric     return;
25610b57cec5SDimitry Andric 
25620b57cec5SDimitry Andric   // According to the values of the arguments, bind the value of the second
25630b57cec5SDimitry Andric   // argument to the destination buffer and set string length, or just
25640b57cec5SDimitry Andric   // invalidate the destination buffer.
25655ffd83dbSDimitry Andric   if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression),
25665ffd83dbSDimitry Andric                  Size.Expression, C, State))
25670b57cec5SDimitry Andric     return;
25680b57cec5SDimitry Andric 
2569647cbc5dSDimitry Andric   State = State->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
25700b57cec5SDimitry Andric   C.addTransition(State);
25710b57cec5SDimitry Andric }
25720b57cec5SDimitry Andric 
2573647cbc5dSDimitry Andric void CStringChecker::evalBzero(CheckerContext &C, const CallEvent &Call) const {
25740b57cec5SDimitry Andric   CurrentFunctionDescription = "memory clearance function";
25750b57cec5SDimitry Andric 
2576647cbc5dSDimitry Andric   DestinationArgExpr Buffer = {{Call.getArgExpr(0), 0}};
2577647cbc5dSDimitry Andric   SizeArgExpr Size = {{Call.getArgExpr(1), 1}};
25780b57cec5SDimitry Andric   SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy);
25790b57cec5SDimitry Andric 
25800b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
25810b57cec5SDimitry Andric 
25820b57cec5SDimitry Andric   // See if the size argument is zero.
25835ffd83dbSDimitry Andric   SVal SizeVal = C.getSVal(Size.Expression);
25845ffd83dbSDimitry Andric   QualType SizeTy = Size.Expression->getType();
25850b57cec5SDimitry Andric 
25860b57cec5SDimitry Andric   ProgramStateRef StateZeroSize, StateNonZeroSize;
25870b57cec5SDimitry Andric   std::tie(StateZeroSize, StateNonZeroSize) =
25880b57cec5SDimitry Andric     assumeZero(C, State, SizeVal, SizeTy);
25890b57cec5SDimitry Andric 
25900b57cec5SDimitry Andric   // If the size is zero, there won't be any actual memory access,
25910b57cec5SDimitry Andric   // In this case we just return.
25920b57cec5SDimitry Andric   if (StateZeroSize && !StateNonZeroSize) {
25930b57cec5SDimitry Andric     C.addTransition(StateZeroSize);
25940b57cec5SDimitry Andric     return;
25950b57cec5SDimitry Andric   }
25960b57cec5SDimitry Andric 
25970b57cec5SDimitry Andric   // Get the value of the memory area.
25985ffd83dbSDimitry Andric   SVal MemVal = C.getSVal(Buffer.Expression);
25990b57cec5SDimitry Andric 
26000b57cec5SDimitry Andric   // Ensure the memory area is not null.
26010b57cec5SDimitry Andric   // If it is NULL there will be a NULL pointer dereference.
26025ffd83dbSDimitry Andric   State = checkNonNull(C, StateNonZeroSize, Buffer, MemVal);
26030b57cec5SDimitry Andric   if (!State)
26040b57cec5SDimitry Andric     return;
26050b57cec5SDimitry Andric 
26065ffd83dbSDimitry Andric   State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write);
26070b57cec5SDimitry Andric   if (!State)
26080b57cec5SDimitry Andric     return;
26090b57cec5SDimitry Andric 
26105ffd83dbSDimitry Andric   if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State))
26110b57cec5SDimitry Andric     return;
26120b57cec5SDimitry Andric 
26130b57cec5SDimitry Andric   C.addTransition(State);
26140b57cec5SDimitry Andric }
26150b57cec5SDimitry Andric 
2616647cbc5dSDimitry Andric void CStringChecker::evalSprintf(CheckerContext &C,
2617647cbc5dSDimitry Andric                                  const CallEvent &Call) const {
261806c3fb27SDimitry Andric   CurrentFunctionDescription = "'sprintf'";
2619*0fca6ea1SDimitry Andric   evalSprintfCommon(C, Call, /* IsBounded = */ false);
262006c3fb27SDimitry Andric }
262106c3fb27SDimitry Andric 
2622647cbc5dSDimitry Andric void CStringChecker::evalSnprintf(CheckerContext &C,
2623647cbc5dSDimitry Andric                                   const CallEvent &Call) const {
262406c3fb27SDimitry Andric   CurrentFunctionDescription = "'snprintf'";
2625*0fca6ea1SDimitry Andric   evalSprintfCommon(C, Call, /* IsBounded = */ true);
262606c3fb27SDimitry Andric }
262706c3fb27SDimitry Andric 
2628647cbc5dSDimitry Andric void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallEvent &Call,
2629*0fca6ea1SDimitry Andric                                        bool IsBounded) const {
263006c3fb27SDimitry Andric   ProgramStateRef State = C.getState();
2631647cbc5dSDimitry Andric   const auto *CE = cast<CallExpr>(Call.getOriginExpr());
2632647cbc5dSDimitry Andric   DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
263306c3fb27SDimitry Andric 
2634647cbc5dSDimitry Andric   const auto NumParams = Call.parameters().size();
2635*0fca6ea1SDimitry Andric   if (CE->getNumArgs() < NumParams) {
2636*0fca6ea1SDimitry Andric     // This is an invalid call, let's just ignore it.
2637*0fca6ea1SDimitry Andric     return;
2638*0fca6ea1SDimitry Andric   }
263906c3fb27SDimitry Andric 
264006c3fb27SDimitry Andric   const auto AllArguments =
264106c3fb27SDimitry Andric       llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
264206c3fb27SDimitry Andric   const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
264306c3fb27SDimitry Andric 
264406c3fb27SDimitry Andric   for (const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
264506c3fb27SDimitry Andric     // We consider only string buffers
264606c3fb27SDimitry Andric     if (const QualType type = ArgExpr->getType();
264706c3fb27SDimitry Andric         !type->isAnyPointerType() ||
264806c3fb27SDimitry Andric         !type->getPointeeType()->isAnyCharacterType())
264906c3fb27SDimitry Andric       continue;
265006c3fb27SDimitry Andric     SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
265106c3fb27SDimitry Andric 
265206c3fb27SDimitry Andric     // Ensure the buffers do not overlap.
265306c3fb27SDimitry Andric     SizeArgExpr SrcExprAsSizeDummy = {
265406c3fb27SDimitry Andric         {Source.Expression, Source.ArgumentIndex}};
265506c3fb27SDimitry Andric     State = CheckOverlap(
265606c3fb27SDimitry Andric         C, State,
2657647cbc5dSDimitry Andric         (IsBounded ? SizeArgExpr{{Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
265806c3fb27SDimitry Andric         Dest, Source);
265906c3fb27SDimitry Andric     if (!State)
266006c3fb27SDimitry Andric       return;
266106c3fb27SDimitry Andric   }
266206c3fb27SDimitry Andric 
266306c3fb27SDimitry Andric   C.addTransition(State);
266406c3fb27SDimitry Andric }
266506c3fb27SDimitry Andric 
26660b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
26670b57cec5SDimitry Andric // The driver method, and other Checker callbacks.
26680b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
26690b57cec5SDimitry Andric 
26700b57cec5SDimitry Andric CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call,
26710b57cec5SDimitry Andric                                                      CheckerContext &C) const {
26720b57cec5SDimitry Andric   const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
26730b57cec5SDimitry Andric   if (!CE)
26740b57cec5SDimitry Andric     return nullptr;
26750b57cec5SDimitry Andric 
26760b57cec5SDimitry Andric   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
26770b57cec5SDimitry Andric   if (!FD)
26780b57cec5SDimitry Andric     return nullptr;
26790b57cec5SDimitry Andric 
2680349cc55cSDimitry Andric   if (StdCopy.matches(Call))
26810b57cec5SDimitry Andric     return &CStringChecker::evalStdCopy;
2682349cc55cSDimitry Andric   if (StdCopyBackward.matches(Call))
26830b57cec5SDimitry Andric     return &CStringChecker::evalStdCopyBackward;
26840b57cec5SDimitry Andric 
26850b57cec5SDimitry Andric   // Pro-actively check that argument types are safe to do arithmetic upon.
26860b57cec5SDimitry Andric   // We do not want to crash if someone accidentally passes a structure
26870b57cec5SDimitry Andric   // into, say, a C++ overload of any of these functions. We could not check
26880b57cec5SDimitry Andric   // that for std::copy because they may have arguments of other types.
26890b57cec5SDimitry Andric   for (auto I : CE->arguments()) {
26900b57cec5SDimitry Andric     QualType T = I->getType();
26910b57cec5SDimitry Andric     if (!T->isIntegralOrEnumerationType() && !T->isPointerType())
26920b57cec5SDimitry Andric       return nullptr;
26930b57cec5SDimitry Andric   }
26940b57cec5SDimitry Andric 
26950b57cec5SDimitry Andric   const FnCheck *Callback = Callbacks.lookup(Call);
26960b57cec5SDimitry Andric   if (Callback)
26970b57cec5SDimitry Andric     return *Callback;
26980b57cec5SDimitry Andric 
26990b57cec5SDimitry Andric   return nullptr;
27000b57cec5SDimitry Andric }
27010b57cec5SDimitry Andric 
27020b57cec5SDimitry Andric bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
27030b57cec5SDimitry Andric   FnCheck Callback = identifyCall(Call, C);
27040b57cec5SDimitry Andric 
27050b57cec5SDimitry Andric   // If the callee isn't a string function, let another checker handle it.
27060b57cec5SDimitry Andric   if (!Callback)
27070b57cec5SDimitry Andric     return false;
27080b57cec5SDimitry Andric 
27090b57cec5SDimitry Andric   // Check and evaluate the call.
2710647cbc5dSDimitry Andric   assert(isa<CallExpr>(Call.getOriginExpr()));
2711647cbc5dSDimitry Andric   Callback(this, C, Call);
27120b57cec5SDimitry Andric 
27130b57cec5SDimitry Andric   // If the evaluate call resulted in no change, chain to the next eval call
27140b57cec5SDimitry Andric   // handler.
27150b57cec5SDimitry Andric   // Note, the custom CString evaluation calls assume that basic safety
27160b57cec5SDimitry Andric   // properties are held. However, if the user chooses to turn off some of these
27170b57cec5SDimitry Andric   // checks, we ignore the issues and leave the call evaluation to a generic
27180b57cec5SDimitry Andric   // handler.
27190b57cec5SDimitry Andric   return C.isDifferent();
27200b57cec5SDimitry Andric }
27210b57cec5SDimitry Andric 
27220b57cec5SDimitry Andric void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {
27230b57cec5SDimitry Andric   // Record string length for char a[] = "abc";
27240b57cec5SDimitry Andric   ProgramStateRef state = C.getState();
27250b57cec5SDimitry Andric 
27260b57cec5SDimitry Andric   for (const auto *I : DS->decls()) {
27270b57cec5SDimitry Andric     const VarDecl *D = dyn_cast<VarDecl>(I);
27280b57cec5SDimitry Andric     if (!D)
27290b57cec5SDimitry Andric       continue;
27300b57cec5SDimitry Andric 
27310b57cec5SDimitry Andric     // FIXME: Handle array fields of structs.
27320b57cec5SDimitry Andric     if (!D->getType()->isArrayType())
27330b57cec5SDimitry Andric       continue;
27340b57cec5SDimitry Andric 
27350b57cec5SDimitry Andric     const Expr *Init = D->getInit();
27360b57cec5SDimitry Andric     if (!Init)
27370b57cec5SDimitry Andric       continue;
27380b57cec5SDimitry Andric     if (!isa<StringLiteral>(Init))
27390b57cec5SDimitry Andric       continue;
27400b57cec5SDimitry Andric 
27410b57cec5SDimitry Andric     Loc VarLoc = state->getLValue(D, C.getLocationContext());
27420b57cec5SDimitry Andric     const MemRegion *MR = VarLoc.getAsRegion();
27430b57cec5SDimitry Andric     if (!MR)
27440b57cec5SDimitry Andric       continue;
27450b57cec5SDimitry Andric 
27460b57cec5SDimitry Andric     SVal StrVal = C.getSVal(Init);
27470b57cec5SDimitry Andric     assert(StrVal.isValid() && "Initializer string is unknown or undefined");
27480b57cec5SDimitry Andric     DefinedOrUnknownSVal strLength =
27490b57cec5SDimitry Andric       getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>();
27500b57cec5SDimitry Andric 
27510b57cec5SDimitry Andric     state = state->set<CStringLength>(MR, strLength);
27520b57cec5SDimitry Andric   }
27530b57cec5SDimitry Andric 
27540b57cec5SDimitry Andric   C.addTransition(state);
27550b57cec5SDimitry Andric }
27560b57cec5SDimitry Andric 
27570b57cec5SDimitry Andric ProgramStateRef
27580b57cec5SDimitry Andric CStringChecker::checkRegionChanges(ProgramStateRef state,
27590b57cec5SDimitry Andric     const InvalidatedSymbols *,
27600b57cec5SDimitry Andric     ArrayRef<const MemRegion *> ExplicitRegions,
27610b57cec5SDimitry Andric     ArrayRef<const MemRegion *> Regions,
27620b57cec5SDimitry Andric     const LocationContext *LCtx,
27630b57cec5SDimitry Andric     const CallEvent *Call) const {
27640b57cec5SDimitry Andric   CStringLengthTy Entries = state->get<CStringLength>();
27650b57cec5SDimitry Andric   if (Entries.isEmpty())
27660b57cec5SDimitry Andric     return state;
27670b57cec5SDimitry Andric 
27680b57cec5SDimitry Andric   llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
27690b57cec5SDimitry Andric   llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
27700b57cec5SDimitry Andric 
27710b57cec5SDimitry Andric   // First build sets for the changed regions and their super-regions.
277206c3fb27SDimitry Andric   for (const MemRegion *MR : Regions) {
27730b57cec5SDimitry Andric     Invalidated.insert(MR);
27740b57cec5SDimitry Andric 
27750b57cec5SDimitry Andric     SuperRegions.insert(MR);
27760b57cec5SDimitry Andric     while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
27770b57cec5SDimitry Andric       MR = SR->getSuperRegion();
27780b57cec5SDimitry Andric       SuperRegions.insert(MR);
27790b57cec5SDimitry Andric     }
27800b57cec5SDimitry Andric   }
27810b57cec5SDimitry Andric 
27820b57cec5SDimitry Andric   CStringLengthTy::Factory &F = state->get_context<CStringLength>();
27830b57cec5SDimitry Andric 
27840b57cec5SDimitry Andric   // Then loop over the entries in the current state.
278506c3fb27SDimitry Andric   for (const MemRegion *MR : llvm::make_first_range(Entries)) {
27860b57cec5SDimitry Andric     // Is this entry for a super-region of a changed region?
27870b57cec5SDimitry Andric     if (SuperRegions.count(MR)) {
27880b57cec5SDimitry Andric       Entries = F.remove(Entries, MR);
27890b57cec5SDimitry Andric       continue;
27900b57cec5SDimitry Andric     }
27910b57cec5SDimitry Andric 
27920b57cec5SDimitry Andric     // Is this entry for a sub-region of a changed region?
27930b57cec5SDimitry Andric     const MemRegion *Super = MR;
27940b57cec5SDimitry Andric     while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
27950b57cec5SDimitry Andric       Super = SR->getSuperRegion();
27960b57cec5SDimitry Andric       if (Invalidated.count(Super)) {
27970b57cec5SDimitry Andric         Entries = F.remove(Entries, MR);
27980b57cec5SDimitry Andric         break;
27990b57cec5SDimitry Andric       }
28000b57cec5SDimitry Andric     }
28010b57cec5SDimitry Andric   }
28020b57cec5SDimitry Andric 
28030b57cec5SDimitry Andric   return state->set<CStringLength>(Entries);
28040b57cec5SDimitry Andric }
28050b57cec5SDimitry Andric 
28060b57cec5SDimitry Andric void CStringChecker::checkLiveSymbols(ProgramStateRef state,
28070b57cec5SDimitry Andric     SymbolReaper &SR) const {
28080b57cec5SDimitry Andric   // Mark all symbols in our string length map as valid.
28090b57cec5SDimitry Andric   CStringLengthTy Entries = state->get<CStringLength>();
28100b57cec5SDimitry Andric 
281106c3fb27SDimitry Andric   for (SVal Len : llvm::make_second_range(Entries)) {
281206c3fb27SDimitry Andric     for (SymbolRef Sym : Len.symbols())
281306c3fb27SDimitry Andric       SR.markInUse(Sym);
28140b57cec5SDimitry Andric   }
28150b57cec5SDimitry Andric }
28160b57cec5SDimitry Andric 
28170b57cec5SDimitry Andric void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
28180b57cec5SDimitry Andric     CheckerContext &C) const {
28190b57cec5SDimitry Andric   ProgramStateRef state = C.getState();
28200b57cec5SDimitry Andric   CStringLengthTy Entries = state->get<CStringLength>();
28210b57cec5SDimitry Andric   if (Entries.isEmpty())
28220b57cec5SDimitry Andric     return;
28230b57cec5SDimitry Andric 
28240b57cec5SDimitry Andric   CStringLengthTy::Factory &F = state->get_context<CStringLength>();
282506c3fb27SDimitry Andric   for (auto [Reg, Len] : Entries) {
28260b57cec5SDimitry Andric     if (SymbolRef Sym = Len.getAsSymbol()) {
28270b57cec5SDimitry Andric       if (SR.isDead(Sym))
282806c3fb27SDimitry Andric         Entries = F.remove(Entries, Reg);
28290b57cec5SDimitry Andric     }
28300b57cec5SDimitry Andric   }
28310b57cec5SDimitry Andric 
28320b57cec5SDimitry Andric   state = state->set<CStringLength>(Entries);
28330b57cec5SDimitry Andric   C.addTransition(state);
28340b57cec5SDimitry Andric }
28350b57cec5SDimitry Andric 
28360b57cec5SDimitry Andric void ento::registerCStringModeling(CheckerManager &Mgr) {
28370b57cec5SDimitry Andric   Mgr.registerChecker<CStringChecker>();
28380b57cec5SDimitry Andric }
28390b57cec5SDimitry Andric 
28405ffd83dbSDimitry Andric bool ento::shouldRegisterCStringModeling(const CheckerManager &mgr) {
28410b57cec5SDimitry Andric   return true;
28420b57cec5SDimitry Andric }
28430b57cec5SDimitry Andric 
28440b57cec5SDimitry Andric #define REGISTER_CHECKER(name)                                                 \
28450b57cec5SDimitry Andric   void ento::register##name(CheckerManager &mgr) {                             \
28460b57cec5SDimitry Andric     CStringChecker *checker = mgr.getChecker<CStringChecker>();                \
28470b57cec5SDimitry Andric     checker->Filter.Check##name = true;                                        \
2848a7dea167SDimitry Andric     checker->Filter.CheckName##name = mgr.getCurrentCheckerName();             \
28490b57cec5SDimitry Andric   }                                                                            \
28500b57cec5SDimitry Andric                                                                                \
28515ffd83dbSDimitry Andric   bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
28520b57cec5SDimitry Andric 
28530b57cec5SDimitry Andric REGISTER_CHECKER(CStringNullArg)
28540b57cec5SDimitry Andric REGISTER_CHECKER(CStringOutOfBounds)
28550b57cec5SDimitry Andric REGISTER_CHECKER(CStringBufferOverlap)
28560b57cec5SDimitry Andric REGISTER_CHECKER(CStringNotNullTerm)
285781ad6265SDimitry Andric REGISTER_CHECKER(CStringUninitializedRead)
2858