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