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