10b57cec5SDimitry Andric //= CStringChecker.cpp - Checks calls to C string functions --------*- C++ -*-// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This defines CStringChecker, which is an assortment of checks on calls 100b57cec5SDimitry Andric // to functions in <string.h>. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 150b57cec5SDimitry Andric #include "InterCheckerAPI.h" 160b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h" 170b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 180b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h" 190b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h" 200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" 210b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 220b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 230b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 240b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 250b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric using namespace clang; 280b57cec5SDimitry Andric using namespace ento; 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric namespace { 31*480093f4SDimitry Andric enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 }; 320b57cec5SDimitry Andric class CStringChecker : public Checker< eval::Call, 330b57cec5SDimitry Andric check::PreStmt<DeclStmt>, 340b57cec5SDimitry Andric check::LiveSymbols, 350b57cec5SDimitry Andric check::DeadSymbols, 360b57cec5SDimitry Andric check::RegionChanges 370b57cec5SDimitry Andric > { 380b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap, 390b57cec5SDimitry Andric BT_NotCString, BT_AdditionOverflow; 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric mutable const char *CurrentFunctionDescription; 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric public: 440b57cec5SDimitry Andric /// The filter is used to filter out the diagnostics which are not enabled by 450b57cec5SDimitry Andric /// the user. 460b57cec5SDimitry Andric struct CStringChecksFilter { 470b57cec5SDimitry Andric DefaultBool CheckCStringNullArg; 480b57cec5SDimitry Andric DefaultBool CheckCStringOutOfBounds; 490b57cec5SDimitry Andric DefaultBool CheckCStringBufferOverlap; 500b57cec5SDimitry Andric DefaultBool CheckCStringNotNullTerm; 510b57cec5SDimitry Andric 52a7dea167SDimitry Andric CheckerNameRef CheckNameCStringNullArg; 53a7dea167SDimitry Andric CheckerNameRef CheckNameCStringOutOfBounds; 54a7dea167SDimitry Andric CheckerNameRef CheckNameCStringBufferOverlap; 55a7dea167SDimitry Andric CheckerNameRef CheckNameCStringNotNullTerm; 560b57cec5SDimitry Andric }; 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric CStringChecksFilter Filter; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric static void *getTag() { static int tag; return &tag; } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 630b57cec5SDimitry Andric void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 640b57cec5SDimitry Andric void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const; 650b57cec5SDimitry Andric void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric ProgramStateRef 680b57cec5SDimitry Andric checkRegionChanges(ProgramStateRef state, 690b57cec5SDimitry Andric const InvalidatedSymbols *, 700b57cec5SDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 710b57cec5SDimitry Andric ArrayRef<const MemRegion *> Regions, 720b57cec5SDimitry Andric const LocationContext *LCtx, 730b57cec5SDimitry Andric const CallEvent *Call) const; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric typedef void (CStringChecker::*FnCheck)(CheckerContext &, 760b57cec5SDimitry Andric const CallExpr *) const; 770b57cec5SDimitry Andric CallDescriptionMap<FnCheck> Callbacks = { 780b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy}, 790b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy}, 800b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp}, 810b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove}, 820b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset}, 830b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "explicit_memset", 3}, &CStringChecker::evalMemset}, 840b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy}, 850b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy}, 860b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy}, 870b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy}, 880b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat}, 890b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat}, 900b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat}, 910b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength}, 920b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength}, 930b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp}, 940b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp}, 950b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp}, 960b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strncasecmp", 3}, &CStringChecker::evalStrncasecmp}, 970b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep}, 980b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy}, 990b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "bcmp", 3}, &CStringChecker::evalMemcmp}, 1000b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero}, 1010b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "explicit_bzero", 2}, &CStringChecker::evalBzero}, 1020b57cec5SDimitry Andric }; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric // These require a bit of special handling. 1050b57cec5SDimitry Andric CallDescription StdCopy{{"std", "copy"}, 3}, 1060b57cec5SDimitry Andric StdCopyBackward{{"std", "copy_backward"}, 3}; 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const; 1090b57cec5SDimitry Andric void evalMemcpy(CheckerContext &C, const CallExpr *CE) const; 1100b57cec5SDimitry Andric void evalMempcpy(CheckerContext &C, const CallExpr *CE) const; 1110b57cec5SDimitry Andric void evalMemmove(CheckerContext &C, const CallExpr *CE) const; 1120b57cec5SDimitry Andric void evalBcopy(CheckerContext &C, const CallExpr *CE) const; 1130b57cec5SDimitry Andric void evalCopyCommon(CheckerContext &C, const CallExpr *CE, 1140b57cec5SDimitry Andric ProgramStateRef state, 1150b57cec5SDimitry Andric const Expr *Size, 1160b57cec5SDimitry Andric const Expr *Source, 1170b57cec5SDimitry Andric const Expr *Dest, 1180b57cec5SDimitry Andric bool Restricted = false, 1190b57cec5SDimitry Andric bool IsMempcpy = false) const; 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric void evalMemcmp(CheckerContext &C, const CallExpr *CE) const; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric void evalstrLength(CheckerContext &C, const CallExpr *CE) const; 1240b57cec5SDimitry Andric void evalstrnLength(CheckerContext &C, const CallExpr *CE) const; 1250b57cec5SDimitry Andric void evalstrLengthCommon(CheckerContext &C, 1260b57cec5SDimitry Andric const CallExpr *CE, 1270b57cec5SDimitry Andric bool IsStrnlen = false) const; 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; 1300b57cec5SDimitry Andric void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; 1310b57cec5SDimitry Andric void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; 1320b57cec5SDimitry Andric void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const; 133*480093f4SDimitry Andric void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd, 134*480093f4SDimitry Andric bool IsBounded, ConcatFnKind appendK, 1350b57cec5SDimitry Andric bool returnPtr = true) const; 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric void evalStrcat(CheckerContext &C, const CallExpr *CE) const; 1380b57cec5SDimitry Andric void evalStrncat(CheckerContext &C, const CallExpr *CE) const; 1390b57cec5SDimitry Andric void evalStrlcat(CheckerContext &C, const CallExpr *CE) const; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; 1420b57cec5SDimitry Andric void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; 1430b57cec5SDimitry Andric void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; 1440b57cec5SDimitry Andric void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; 1450b57cec5SDimitry Andric void evalStrcmpCommon(CheckerContext &C, 1460b57cec5SDimitry Andric const CallExpr *CE, 147*480093f4SDimitry Andric bool IsBounded = false, 148*480093f4SDimitry Andric bool IgnoreCase = false) const; 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric void evalStrsep(CheckerContext &C, const CallExpr *CE) const; 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric void evalStdCopy(CheckerContext &C, const CallExpr *CE) const; 1530b57cec5SDimitry Andric void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const; 1540b57cec5SDimitry Andric void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const; 1550b57cec5SDimitry Andric void evalMemset(CheckerContext &C, const CallExpr *CE) const; 1560b57cec5SDimitry Andric void evalBzero(CheckerContext &C, const CallExpr *CE) const; 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric // Utility methods 1590b57cec5SDimitry Andric std::pair<ProgramStateRef , ProgramStateRef > 1600b57cec5SDimitry Andric static assumeZero(CheckerContext &C, 1610b57cec5SDimitry Andric ProgramStateRef state, SVal V, QualType Ty); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric static ProgramStateRef setCStringLength(ProgramStateRef state, 1640b57cec5SDimitry Andric const MemRegion *MR, 1650b57cec5SDimitry Andric SVal strLength); 1660b57cec5SDimitry Andric static SVal getCStringLengthForRegion(CheckerContext &C, 1670b57cec5SDimitry Andric ProgramStateRef &state, 1680b57cec5SDimitry Andric const Expr *Ex, 1690b57cec5SDimitry Andric const MemRegion *MR, 1700b57cec5SDimitry Andric bool hypothetical); 1710b57cec5SDimitry Andric SVal getCStringLength(CheckerContext &C, 1720b57cec5SDimitry Andric ProgramStateRef &state, 1730b57cec5SDimitry Andric const Expr *Ex, 1740b57cec5SDimitry Andric SVal Buf, 1750b57cec5SDimitry Andric bool hypothetical = false) const; 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric const StringLiteral *getCStringLiteral(CheckerContext &C, 1780b57cec5SDimitry Andric ProgramStateRef &state, 1790b57cec5SDimitry Andric const Expr *expr, 1800b57cec5SDimitry Andric SVal val) const; 1810b57cec5SDimitry Andric 1820b57cec5SDimitry Andric static ProgramStateRef InvalidateBuffer(CheckerContext &C, 1830b57cec5SDimitry Andric ProgramStateRef state, 1840b57cec5SDimitry Andric const Expr *Ex, SVal V, 1850b57cec5SDimitry Andric bool IsSourceBuffer, 1860b57cec5SDimitry Andric const Expr *Size); 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, 1890b57cec5SDimitry Andric const MemRegion *MR); 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric static bool memsetAux(const Expr *DstBuffer, SVal CharE, 1920b57cec5SDimitry Andric const Expr *Size, CheckerContext &C, 1930b57cec5SDimitry Andric ProgramStateRef &State); 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric // Re-usable checks 1960b57cec5SDimitry Andric ProgramStateRef checkNonNull(CheckerContext &C, 1970b57cec5SDimitry Andric ProgramStateRef state, 1980b57cec5SDimitry Andric const Expr *S, 199a7dea167SDimitry Andric SVal l, 200a7dea167SDimitry Andric unsigned IdxOfArg) const; 2010b57cec5SDimitry Andric ProgramStateRef CheckLocation(CheckerContext &C, 2020b57cec5SDimitry Andric ProgramStateRef state, 2030b57cec5SDimitry Andric const Expr *S, 2040b57cec5SDimitry Andric SVal l, 2050b57cec5SDimitry Andric const char *message = nullptr) const; 2060b57cec5SDimitry Andric ProgramStateRef CheckBufferAccess(CheckerContext &C, 2070b57cec5SDimitry Andric ProgramStateRef state, 2080b57cec5SDimitry Andric const Expr *Size, 2090b57cec5SDimitry Andric const Expr *FirstBuf, 2100b57cec5SDimitry Andric const Expr *SecondBuf, 2110b57cec5SDimitry Andric const char *firstMessage = nullptr, 2120b57cec5SDimitry Andric const char *secondMessage = nullptr, 2130b57cec5SDimitry Andric bool WarnAboutSize = false) const; 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric ProgramStateRef CheckBufferAccess(CheckerContext &C, 2160b57cec5SDimitry Andric ProgramStateRef state, 2170b57cec5SDimitry Andric const Expr *Size, 2180b57cec5SDimitry Andric const Expr *Buf, 2190b57cec5SDimitry Andric const char *message = nullptr, 2200b57cec5SDimitry Andric bool WarnAboutSize = false) const { 2210b57cec5SDimitry Andric // This is a convenience overload. 2220b57cec5SDimitry Andric return CheckBufferAccess(C, state, Size, Buf, nullptr, message, nullptr, 2230b57cec5SDimitry Andric WarnAboutSize); 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric ProgramStateRef CheckOverlap(CheckerContext &C, 2260b57cec5SDimitry Andric ProgramStateRef state, 2270b57cec5SDimitry Andric const Expr *Size, 2280b57cec5SDimitry Andric const Expr *First, 2290b57cec5SDimitry Andric const Expr *Second) const; 2300b57cec5SDimitry Andric void emitOverlapBug(CheckerContext &C, 2310b57cec5SDimitry Andric ProgramStateRef state, 2320b57cec5SDimitry Andric const Stmt *First, 2330b57cec5SDimitry Andric const Stmt *Second) const; 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric void emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, 2360b57cec5SDimitry Andric StringRef WarningMsg) const; 2370b57cec5SDimitry Andric void emitOutOfBoundsBug(CheckerContext &C, ProgramStateRef State, 2380b57cec5SDimitry Andric const Stmt *S, StringRef WarningMsg) const; 2390b57cec5SDimitry Andric void emitNotCStringBug(CheckerContext &C, ProgramStateRef State, 2400b57cec5SDimitry Andric const Stmt *S, StringRef WarningMsg) const; 2410b57cec5SDimitry Andric void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const; 2420b57cec5SDimitry Andric 2430b57cec5SDimitry Andric ProgramStateRef checkAdditionOverflow(CheckerContext &C, 2440b57cec5SDimitry Andric ProgramStateRef state, 2450b57cec5SDimitry Andric NonLoc left, 2460b57cec5SDimitry Andric NonLoc right) const; 2470b57cec5SDimitry Andric 2480b57cec5SDimitry Andric // Return true if the destination buffer of the copy function may be in bound. 2490b57cec5SDimitry Andric // Expects SVal of Size to be positive and unsigned. 2500b57cec5SDimitry Andric // Expects SVal of FirstBuf to be a FieldRegion. 2510b57cec5SDimitry Andric static bool IsFirstBufInBound(CheckerContext &C, 2520b57cec5SDimitry Andric ProgramStateRef state, 2530b57cec5SDimitry Andric const Expr *FirstBuf, 2540b57cec5SDimitry Andric const Expr *Size); 2550b57cec5SDimitry Andric }; 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric } //end anonymous namespace 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal) 2600b57cec5SDimitry Andric 2610b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2620b57cec5SDimitry Andric // Individual checks and utility methods. 2630b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric std::pair<ProgramStateRef , ProgramStateRef > 2660b57cec5SDimitry Andric CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V, 2670b57cec5SDimitry Andric QualType Ty) { 2680b57cec5SDimitry Andric Optional<DefinedSVal> val = V.getAs<DefinedSVal>(); 2690b57cec5SDimitry Andric if (!val) 2700b57cec5SDimitry Andric return std::pair<ProgramStateRef , ProgramStateRef >(state, state); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 2730b57cec5SDimitry Andric DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty); 2740b57cec5SDimitry Andric return state->assume(svalBuilder.evalEQ(state, *val, zero)); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, 2780b57cec5SDimitry Andric ProgramStateRef state, 279a7dea167SDimitry Andric const Expr *S, SVal l, 280a7dea167SDimitry Andric unsigned IdxOfArg) const { 2810b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 2820b57cec5SDimitry Andric if (!state) 2830b57cec5SDimitry Andric return nullptr; 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric ProgramStateRef stateNull, stateNonNull; 2860b57cec5SDimitry Andric std::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType()); 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric if (stateNull && !stateNonNull) { 2890b57cec5SDimitry Andric if (Filter.CheckCStringNullArg) { 2900b57cec5SDimitry Andric SmallString<80> buf; 291a7dea167SDimitry Andric llvm::raw_svector_ostream OS(buf); 2920b57cec5SDimitry Andric assert(CurrentFunctionDescription); 293*480093f4SDimitry Andric OS << "Null pointer passed as " << IdxOfArg 294*480093f4SDimitry Andric << llvm::getOrdinalSuffix(IdxOfArg) << " argument to " 295*480093f4SDimitry Andric << CurrentFunctionDescription; 2960b57cec5SDimitry Andric 297a7dea167SDimitry Andric emitNullArgBug(C, stateNull, S, OS.str()); 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric return nullptr; 3000b57cec5SDimitry Andric } 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric // From here on, assume that the value is non-null. 3030b57cec5SDimitry Andric assert(stateNonNull); 3040b57cec5SDimitry Andric return stateNonNull; 3050b57cec5SDimitry Andric } 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric // FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor? 3080b57cec5SDimitry Andric ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, 3090b57cec5SDimitry Andric ProgramStateRef state, 3100b57cec5SDimitry Andric const Expr *S, SVal l, 3110b57cec5SDimitry Andric const char *warningMsg) const { 3120b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 3130b57cec5SDimitry Andric if (!state) 3140b57cec5SDimitry Andric return nullptr; 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric // Check for out of bound array element access. 3170b57cec5SDimitry Andric const MemRegion *R = l.getAsRegion(); 3180b57cec5SDimitry Andric if (!R) 3190b57cec5SDimitry Andric return state; 3200b57cec5SDimitry Andric 3210b57cec5SDimitry Andric const ElementRegion *ER = dyn_cast<ElementRegion>(R); 3220b57cec5SDimitry Andric if (!ER) 3230b57cec5SDimitry Andric return state; 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric if (ER->getValueType() != C.getASTContext().CharTy) 3260b57cec5SDimitry Andric return state; 3270b57cec5SDimitry Andric 3280b57cec5SDimitry Andric // Get the size of the array. 3290b57cec5SDimitry Andric const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); 3300b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 3310b57cec5SDimitry Andric SVal Extent = 3320b57cec5SDimitry Andric svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); 3330b57cec5SDimitry Andric DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>(); 3340b57cec5SDimitry Andric 3350b57cec5SDimitry Andric // Get the index of the accessed element. 3360b57cec5SDimitry Andric DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 3370b57cec5SDimitry Andric 3380b57cec5SDimitry Andric ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true); 3390b57cec5SDimitry Andric ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false); 3400b57cec5SDimitry Andric if (StOutBound && !StInBound) { 3410b57cec5SDimitry Andric // These checks are either enabled by the CString out-of-bounds checker 3420b57cec5SDimitry Andric // explicitly or implicitly by the Malloc checker. 3430b57cec5SDimitry Andric // In the latter case we only do modeling but do not emit warning. 3440b57cec5SDimitry Andric if (!Filter.CheckCStringOutOfBounds) 3450b57cec5SDimitry Andric return nullptr; 3460b57cec5SDimitry Andric // Emit a bug report. 3470b57cec5SDimitry Andric if (warningMsg) { 3480b57cec5SDimitry Andric emitOutOfBoundsBug(C, StOutBound, S, warningMsg); 3490b57cec5SDimitry Andric } else { 3500b57cec5SDimitry Andric assert(CurrentFunctionDescription); 3510b57cec5SDimitry Andric assert(CurrentFunctionDescription[0] != '\0'); 3520b57cec5SDimitry Andric 3530b57cec5SDimitry Andric SmallString<80> buf; 3540b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 3550b57cec5SDimitry Andric os << toUppercase(CurrentFunctionDescription[0]) 3560b57cec5SDimitry Andric << &CurrentFunctionDescription[1] 3570b57cec5SDimitry Andric << " accesses out-of-bound array element"; 3580b57cec5SDimitry Andric emitOutOfBoundsBug(C, StOutBound, S, os.str()); 3590b57cec5SDimitry Andric } 3600b57cec5SDimitry Andric return nullptr; 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric 3630b57cec5SDimitry Andric // Array bound check succeeded. From this point forward the array bound 3640b57cec5SDimitry Andric // should always succeed. 3650b57cec5SDimitry Andric return StInBound; 3660b57cec5SDimitry Andric } 3670b57cec5SDimitry Andric 3680b57cec5SDimitry Andric ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, 3690b57cec5SDimitry Andric ProgramStateRef state, 3700b57cec5SDimitry Andric const Expr *Size, 3710b57cec5SDimitry Andric const Expr *FirstBuf, 3720b57cec5SDimitry Andric const Expr *SecondBuf, 3730b57cec5SDimitry Andric const char *firstMessage, 3740b57cec5SDimitry Andric const char *secondMessage, 3750b57cec5SDimitry Andric bool WarnAboutSize) const { 3760b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 3770b57cec5SDimitry Andric if (!state) 3780b57cec5SDimitry Andric return nullptr; 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 3810b57cec5SDimitry Andric ASTContext &Ctx = svalBuilder.getContext(); 3820b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric QualType sizeTy = Size->getType(); 3850b57cec5SDimitry Andric QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); 3860b57cec5SDimitry Andric 3870b57cec5SDimitry Andric // Check that the first buffer is non-null. 3880b57cec5SDimitry Andric SVal BufVal = C.getSVal(FirstBuf); 389a7dea167SDimitry Andric state = checkNonNull(C, state, FirstBuf, BufVal, 1); 3900b57cec5SDimitry Andric if (!state) 3910b57cec5SDimitry Andric return nullptr; 3920b57cec5SDimitry Andric 3930b57cec5SDimitry Andric // If out-of-bounds checking is turned off, skip the rest. 3940b57cec5SDimitry Andric if (!Filter.CheckCStringOutOfBounds) 3950b57cec5SDimitry Andric return state; 3960b57cec5SDimitry Andric 3970b57cec5SDimitry Andric // Get the access length and make sure it is known. 3980b57cec5SDimitry Andric // FIXME: This assumes the caller has already checked that the access length 3990b57cec5SDimitry Andric // is positive. And that it's unsigned. 4000b57cec5SDimitry Andric SVal LengthVal = C.getSVal(Size); 4010b57cec5SDimitry Andric Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 4020b57cec5SDimitry Andric if (!Length) 4030b57cec5SDimitry Andric return state; 4040b57cec5SDimitry Andric 4050b57cec5SDimitry Andric // Compute the offset of the last element to be accessed: size-1. 4060b57cec5SDimitry Andric NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 4070b57cec5SDimitry Andric SVal Offset = svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy); 4080b57cec5SDimitry Andric if (Offset.isUnknown()) 4090b57cec5SDimitry Andric return nullptr; 4100b57cec5SDimitry Andric NonLoc LastOffset = Offset.castAs<NonLoc>(); 4110b57cec5SDimitry Andric 4120b57cec5SDimitry Andric // Check that the first buffer is sufficiently long. 4130b57cec5SDimitry Andric SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); 4140b57cec5SDimitry Andric if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { 4150b57cec5SDimitry Andric const Expr *warningExpr = (WarnAboutSize ? Size : FirstBuf); 4160b57cec5SDimitry Andric 4170b57cec5SDimitry Andric SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, 4180b57cec5SDimitry Andric LastOffset, PtrTy); 4190b57cec5SDimitry Andric state = CheckLocation(C, state, warningExpr, BufEnd, firstMessage); 4200b57cec5SDimitry Andric 4210b57cec5SDimitry Andric // If the buffer isn't large enough, abort. 4220b57cec5SDimitry Andric if (!state) 4230b57cec5SDimitry Andric return nullptr; 4240b57cec5SDimitry Andric } 4250b57cec5SDimitry Andric 4260b57cec5SDimitry Andric // If there's a second buffer, check it as well. 4270b57cec5SDimitry Andric if (SecondBuf) { 4280b57cec5SDimitry Andric BufVal = state->getSVal(SecondBuf, LCtx); 429a7dea167SDimitry Andric state = checkNonNull(C, state, SecondBuf, BufVal, 2); 4300b57cec5SDimitry Andric if (!state) 4310b57cec5SDimitry Andric return nullptr; 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType()); 4340b57cec5SDimitry Andric if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { 4350b57cec5SDimitry Andric const Expr *warningExpr = (WarnAboutSize ? Size : SecondBuf); 4360b57cec5SDimitry Andric 4370b57cec5SDimitry Andric SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, 4380b57cec5SDimitry Andric LastOffset, PtrTy); 4390b57cec5SDimitry Andric state = CheckLocation(C, state, warningExpr, BufEnd, secondMessage); 4400b57cec5SDimitry Andric } 4410b57cec5SDimitry Andric } 4420b57cec5SDimitry Andric 4430b57cec5SDimitry Andric // Large enough or not, return this state! 4440b57cec5SDimitry Andric return state; 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric 4470b57cec5SDimitry Andric ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, 4480b57cec5SDimitry Andric ProgramStateRef state, 4490b57cec5SDimitry Andric const Expr *Size, 4500b57cec5SDimitry Andric const Expr *First, 4510b57cec5SDimitry Andric const Expr *Second) const { 4520b57cec5SDimitry Andric if (!Filter.CheckCStringBufferOverlap) 4530b57cec5SDimitry Andric return state; 4540b57cec5SDimitry Andric 4550b57cec5SDimitry Andric // Do a simple check for overlap: if the two arguments are from the same 4560b57cec5SDimitry Andric // buffer, see if the end of the first is greater than the start of the second 4570b57cec5SDimitry Andric // or vice versa. 4580b57cec5SDimitry Andric 4590b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 4600b57cec5SDimitry Andric if (!state) 4610b57cec5SDimitry Andric return nullptr; 4620b57cec5SDimitry Andric 4630b57cec5SDimitry Andric ProgramStateRef stateTrue, stateFalse; 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric // Get the buffer values and make sure they're known locations. 4660b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 4670b57cec5SDimitry Andric SVal firstVal = state->getSVal(First, LCtx); 4680b57cec5SDimitry Andric SVal secondVal = state->getSVal(Second, LCtx); 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric Optional<Loc> firstLoc = firstVal.getAs<Loc>(); 4710b57cec5SDimitry Andric if (!firstLoc) 4720b57cec5SDimitry Andric return state; 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric Optional<Loc> secondLoc = secondVal.getAs<Loc>(); 4750b57cec5SDimitry Andric if (!secondLoc) 4760b57cec5SDimitry Andric return state; 4770b57cec5SDimitry Andric 4780b57cec5SDimitry Andric // Are the two values the same? 4790b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 4800b57cec5SDimitry Andric std::tie(stateTrue, stateFalse) = 4810b57cec5SDimitry Andric state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc)); 4820b57cec5SDimitry Andric 4830b57cec5SDimitry Andric if (stateTrue && !stateFalse) { 4840b57cec5SDimitry Andric // If the values are known to be equal, that's automatically an overlap. 4850b57cec5SDimitry Andric emitOverlapBug(C, stateTrue, First, Second); 4860b57cec5SDimitry Andric return nullptr; 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric 4890b57cec5SDimitry Andric // assume the two expressions are not equal. 4900b57cec5SDimitry Andric assert(stateFalse); 4910b57cec5SDimitry Andric state = stateFalse; 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric // Which value comes first? 4940b57cec5SDimitry Andric QualType cmpTy = svalBuilder.getConditionType(); 4950b57cec5SDimitry Andric SVal reverse = svalBuilder.evalBinOpLL(state, BO_GT, 4960b57cec5SDimitry Andric *firstLoc, *secondLoc, cmpTy); 4970b57cec5SDimitry Andric Optional<DefinedOrUnknownSVal> reverseTest = 4980b57cec5SDimitry Andric reverse.getAs<DefinedOrUnknownSVal>(); 4990b57cec5SDimitry Andric if (!reverseTest) 5000b57cec5SDimitry Andric return state; 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric std::tie(stateTrue, stateFalse) = state->assume(*reverseTest); 5030b57cec5SDimitry Andric if (stateTrue) { 5040b57cec5SDimitry Andric if (stateFalse) { 5050b57cec5SDimitry Andric // If we don't know which one comes first, we can't perform this test. 5060b57cec5SDimitry Andric return state; 5070b57cec5SDimitry Andric } else { 5080b57cec5SDimitry Andric // Switch the values so that firstVal is before secondVal. 5090b57cec5SDimitry Andric std::swap(firstLoc, secondLoc); 5100b57cec5SDimitry Andric 5110b57cec5SDimitry Andric // Switch the Exprs as well, so that they still correspond. 5120b57cec5SDimitry Andric std::swap(First, Second); 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric } 5150b57cec5SDimitry Andric 5160b57cec5SDimitry Andric // Get the length, and make sure it too is known. 5170b57cec5SDimitry Andric SVal LengthVal = state->getSVal(Size, LCtx); 5180b57cec5SDimitry Andric Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 5190b57cec5SDimitry Andric if (!Length) 5200b57cec5SDimitry Andric return state; 5210b57cec5SDimitry Andric 5220b57cec5SDimitry Andric // Convert the first buffer's start address to char*. 5230b57cec5SDimitry Andric // Bail out if the cast fails. 5240b57cec5SDimitry Andric ASTContext &Ctx = svalBuilder.getContext(); 5250b57cec5SDimitry Andric QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); 5260b57cec5SDimitry Andric SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy, 5270b57cec5SDimitry Andric First->getType()); 5280b57cec5SDimitry Andric Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>(); 5290b57cec5SDimitry Andric if (!FirstStartLoc) 5300b57cec5SDimitry Andric return state; 5310b57cec5SDimitry Andric 5320b57cec5SDimitry Andric // Compute the end of the first buffer. Bail out if THAT fails. 5330b57cec5SDimitry Andric SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, 5340b57cec5SDimitry Andric *FirstStartLoc, *Length, CharPtrTy); 5350b57cec5SDimitry Andric Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>(); 5360b57cec5SDimitry Andric if (!FirstEndLoc) 5370b57cec5SDimitry Andric return state; 5380b57cec5SDimitry Andric 5390b57cec5SDimitry Andric // Is the end of the first buffer past the start of the second buffer? 5400b57cec5SDimitry Andric SVal Overlap = svalBuilder.evalBinOpLL(state, BO_GT, 5410b57cec5SDimitry Andric *FirstEndLoc, *secondLoc, cmpTy); 5420b57cec5SDimitry Andric Optional<DefinedOrUnknownSVal> OverlapTest = 5430b57cec5SDimitry Andric Overlap.getAs<DefinedOrUnknownSVal>(); 5440b57cec5SDimitry Andric if (!OverlapTest) 5450b57cec5SDimitry Andric return state; 5460b57cec5SDimitry Andric 5470b57cec5SDimitry Andric std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest); 5480b57cec5SDimitry Andric 5490b57cec5SDimitry Andric if (stateTrue && !stateFalse) { 5500b57cec5SDimitry Andric // Overlap! 5510b57cec5SDimitry Andric emitOverlapBug(C, stateTrue, First, Second); 5520b57cec5SDimitry Andric return nullptr; 5530b57cec5SDimitry Andric } 5540b57cec5SDimitry Andric 5550b57cec5SDimitry Andric // assume the two expressions don't overlap. 5560b57cec5SDimitry Andric assert(stateFalse); 5570b57cec5SDimitry Andric return stateFalse; 5580b57cec5SDimitry Andric } 5590b57cec5SDimitry Andric 5600b57cec5SDimitry Andric void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, 5610b57cec5SDimitry Andric const Stmt *First, const Stmt *Second) const { 5620b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(state); 5630b57cec5SDimitry Andric if (!N) 5640b57cec5SDimitry Andric return; 5650b57cec5SDimitry Andric 5660b57cec5SDimitry Andric if (!BT_Overlap) 5670b57cec5SDimitry Andric BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap, 5680b57cec5SDimitry Andric categories::UnixAPI, "Improper arguments")); 5690b57cec5SDimitry Andric 5700b57cec5SDimitry Andric // Generate a report for this bug. 571a7dea167SDimitry Andric auto report = std::make_unique<PathSensitiveBugReport>( 5720b57cec5SDimitry Andric *BT_Overlap, "Arguments must not be overlapping buffers", N); 5730b57cec5SDimitry Andric report->addRange(First->getSourceRange()); 5740b57cec5SDimitry Andric report->addRange(Second->getSourceRange()); 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric C.emitReport(std::move(report)); 5770b57cec5SDimitry Andric } 5780b57cec5SDimitry Andric 5790b57cec5SDimitry Andric void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State, 5800b57cec5SDimitry Andric const Stmt *S, StringRef WarningMsg) const { 5810b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode(State)) { 5820b57cec5SDimitry Andric if (!BT_Null) 5830b57cec5SDimitry Andric BT_Null.reset(new BuiltinBug( 5840b57cec5SDimitry Andric Filter.CheckNameCStringNullArg, categories::UnixAPI, 5850b57cec5SDimitry Andric "Null pointer argument in call to byte string function")); 5860b57cec5SDimitry Andric 5870b57cec5SDimitry Andric BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get()); 588a7dea167SDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); 5890b57cec5SDimitry Andric Report->addRange(S->getSourceRange()); 5900b57cec5SDimitry Andric if (const auto *Ex = dyn_cast<Expr>(S)) 5910b57cec5SDimitry Andric bugreporter::trackExpressionValue(N, Ex, *Report); 5920b57cec5SDimitry Andric C.emitReport(std::move(Report)); 5930b57cec5SDimitry Andric } 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric void CStringChecker::emitOutOfBoundsBug(CheckerContext &C, 5970b57cec5SDimitry Andric ProgramStateRef State, const Stmt *S, 5980b57cec5SDimitry Andric StringRef WarningMsg) const { 5990b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode(State)) { 6000b57cec5SDimitry Andric if (!BT_Bounds) 6010b57cec5SDimitry Andric BT_Bounds.reset(new BuiltinBug( 6020b57cec5SDimitry Andric Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds 6030b57cec5SDimitry Andric : Filter.CheckNameCStringNullArg, 6040b57cec5SDimitry Andric "Out-of-bound array access", 6050b57cec5SDimitry Andric "Byte string function accesses out-of-bound array element")); 6060b57cec5SDimitry Andric 6070b57cec5SDimitry Andric BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Bounds.get()); 6080b57cec5SDimitry Andric 6090b57cec5SDimitry Andric // FIXME: It would be nice to eventually make this diagnostic more clear, 6100b57cec5SDimitry Andric // e.g., by referencing the original declaration or by saying *why* this 6110b57cec5SDimitry Andric // reference is outside the range. 612a7dea167SDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); 6130b57cec5SDimitry Andric Report->addRange(S->getSourceRange()); 6140b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6150b57cec5SDimitry Andric } 6160b57cec5SDimitry Andric } 6170b57cec5SDimitry Andric 6180b57cec5SDimitry Andric void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State, 6190b57cec5SDimitry Andric const Stmt *S, 6200b57cec5SDimitry Andric StringRef WarningMsg) const { 6210b57cec5SDimitry Andric if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { 6220b57cec5SDimitry Andric if (!BT_NotCString) 6230b57cec5SDimitry Andric BT_NotCString.reset(new BuiltinBug( 6240b57cec5SDimitry Andric Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, 6250b57cec5SDimitry Andric "Argument is not a null-terminated string.")); 6260b57cec5SDimitry Andric 627a7dea167SDimitry Andric auto Report = 628a7dea167SDimitry Andric std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric Report->addRange(S->getSourceRange()); 6310b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6320b57cec5SDimitry Andric } 6330b57cec5SDimitry Andric } 6340b57cec5SDimitry Andric 6350b57cec5SDimitry Andric void CStringChecker::emitAdditionOverflowBug(CheckerContext &C, 6360b57cec5SDimitry Andric ProgramStateRef State) const { 6370b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode(State)) { 6380b57cec5SDimitry Andric if (!BT_NotCString) 6390b57cec5SDimitry Andric BT_NotCString.reset( 6400b57cec5SDimitry Andric new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API", 6410b57cec5SDimitry Andric "Sum of expressions causes overflow.")); 6420b57cec5SDimitry Andric 6430b57cec5SDimitry Andric // This isn't a great error message, but this should never occur in real 6440b57cec5SDimitry Andric // code anyway -- you'd have to create a buffer longer than a size_t can 6450b57cec5SDimitry Andric // represent, which is sort of a contradiction. 6460b57cec5SDimitry Andric const char *WarningMsg = 6470b57cec5SDimitry Andric "This expression will create a string whose length is too big to " 6480b57cec5SDimitry Andric "be represented as a size_t"; 6490b57cec5SDimitry Andric 650a7dea167SDimitry Andric auto Report = 651a7dea167SDimitry Andric std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); 6520b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric } 6550b57cec5SDimitry Andric 6560b57cec5SDimitry Andric ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, 6570b57cec5SDimitry Andric ProgramStateRef state, 6580b57cec5SDimitry Andric NonLoc left, 6590b57cec5SDimitry Andric NonLoc right) const { 6600b57cec5SDimitry Andric // If out-of-bounds checking is turned off, skip the rest. 6610b57cec5SDimitry Andric if (!Filter.CheckCStringOutOfBounds) 6620b57cec5SDimitry Andric return state; 6630b57cec5SDimitry Andric 6640b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 6650b57cec5SDimitry Andric if (!state) 6660b57cec5SDimitry Andric return nullptr; 6670b57cec5SDimitry Andric 6680b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 6690b57cec5SDimitry Andric BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); 6700b57cec5SDimitry Andric 6710b57cec5SDimitry Andric QualType sizeTy = svalBuilder.getContext().getSizeType(); 6720b57cec5SDimitry Andric const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); 6730b57cec5SDimitry Andric NonLoc maxVal = svalBuilder.makeIntVal(maxValInt); 6740b57cec5SDimitry Andric 6750b57cec5SDimitry Andric SVal maxMinusRight; 6760b57cec5SDimitry Andric if (right.getAs<nonloc::ConcreteInt>()) { 6770b57cec5SDimitry Andric maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right, 6780b57cec5SDimitry Andric sizeTy); 6790b57cec5SDimitry Andric } else { 6800b57cec5SDimitry Andric // Try switching the operands. (The order of these two assignments is 6810b57cec5SDimitry Andric // important!) 6820b57cec5SDimitry Andric maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left, 6830b57cec5SDimitry Andric sizeTy); 6840b57cec5SDimitry Andric left = right; 6850b57cec5SDimitry Andric } 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) { 6880b57cec5SDimitry Andric QualType cmpTy = svalBuilder.getConditionType(); 6890b57cec5SDimitry Andric // If left > max - right, we have an overflow. 6900b57cec5SDimitry Andric SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left, 6910b57cec5SDimitry Andric *maxMinusRightNL, cmpTy); 6920b57cec5SDimitry Andric 6930b57cec5SDimitry Andric ProgramStateRef stateOverflow, stateOkay; 6940b57cec5SDimitry Andric std::tie(stateOverflow, stateOkay) = 6950b57cec5SDimitry Andric state->assume(willOverflow.castAs<DefinedOrUnknownSVal>()); 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric if (stateOverflow && !stateOkay) { 6980b57cec5SDimitry Andric // We have an overflow. Emit a bug report. 6990b57cec5SDimitry Andric emitAdditionOverflowBug(C, stateOverflow); 7000b57cec5SDimitry Andric return nullptr; 7010b57cec5SDimitry Andric } 7020b57cec5SDimitry Andric 7030b57cec5SDimitry Andric // From now on, assume an overflow didn't occur. 7040b57cec5SDimitry Andric assert(stateOkay); 7050b57cec5SDimitry Andric state = stateOkay; 7060b57cec5SDimitry Andric } 7070b57cec5SDimitry Andric 7080b57cec5SDimitry Andric return state; 7090b57cec5SDimitry Andric } 7100b57cec5SDimitry Andric 7110b57cec5SDimitry Andric ProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state, 7120b57cec5SDimitry Andric const MemRegion *MR, 7130b57cec5SDimitry Andric SVal strLength) { 7140b57cec5SDimitry Andric assert(!strLength.isUndef() && "Attempt to set an undefined string length"); 7150b57cec5SDimitry Andric 7160b57cec5SDimitry Andric MR = MR->StripCasts(); 7170b57cec5SDimitry Andric 7180b57cec5SDimitry Andric switch (MR->getKind()) { 7190b57cec5SDimitry Andric case MemRegion::StringRegionKind: 7200b57cec5SDimitry Andric // FIXME: This can happen if we strcpy() into a string region. This is 7210b57cec5SDimitry Andric // undefined [C99 6.4.5p6], but we should still warn about it. 7220b57cec5SDimitry Andric return state; 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric case MemRegion::SymbolicRegionKind: 7250b57cec5SDimitry Andric case MemRegion::AllocaRegionKind: 7260b57cec5SDimitry Andric case MemRegion::VarRegionKind: 7270b57cec5SDimitry Andric case MemRegion::FieldRegionKind: 7280b57cec5SDimitry Andric case MemRegion::ObjCIvarRegionKind: 7290b57cec5SDimitry Andric // These are the types we can currently track string lengths for. 7300b57cec5SDimitry Andric break; 7310b57cec5SDimitry Andric 7320b57cec5SDimitry Andric case MemRegion::ElementRegionKind: 7330b57cec5SDimitry Andric // FIXME: Handle element regions by upper-bounding the parent region's 7340b57cec5SDimitry Andric // string length. 7350b57cec5SDimitry Andric return state; 7360b57cec5SDimitry Andric 7370b57cec5SDimitry Andric default: 7380b57cec5SDimitry Andric // Other regions (mostly non-data) can't have a reliable C string length. 7390b57cec5SDimitry Andric // For now, just ignore the change. 7400b57cec5SDimitry Andric // FIXME: These are rare but not impossible. We should output some kind of 7410b57cec5SDimitry Andric // warning for things like strcpy((char[]){'a', 0}, "b"); 7420b57cec5SDimitry Andric return state; 7430b57cec5SDimitry Andric } 7440b57cec5SDimitry Andric 7450b57cec5SDimitry Andric if (strLength.isUnknown()) 7460b57cec5SDimitry Andric return state->remove<CStringLength>(MR); 7470b57cec5SDimitry Andric 7480b57cec5SDimitry Andric return state->set<CStringLength>(MR, strLength); 7490b57cec5SDimitry Andric } 7500b57cec5SDimitry Andric 7510b57cec5SDimitry Andric SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, 7520b57cec5SDimitry Andric ProgramStateRef &state, 7530b57cec5SDimitry Andric const Expr *Ex, 7540b57cec5SDimitry Andric const MemRegion *MR, 7550b57cec5SDimitry Andric bool hypothetical) { 7560b57cec5SDimitry Andric if (!hypothetical) { 7570b57cec5SDimitry Andric // If there's a recorded length, go ahead and return it. 7580b57cec5SDimitry Andric const SVal *Recorded = state->get<CStringLength>(MR); 7590b57cec5SDimitry Andric if (Recorded) 7600b57cec5SDimitry Andric return *Recorded; 7610b57cec5SDimitry Andric } 7620b57cec5SDimitry Andric 7630b57cec5SDimitry Andric // Otherwise, get a new symbol and update the state. 7640b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 7650b57cec5SDimitry Andric QualType sizeTy = svalBuilder.getContext().getSizeType(); 7660b57cec5SDimitry Andric SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), 7670b57cec5SDimitry Andric MR, Ex, sizeTy, 7680b57cec5SDimitry Andric C.getLocationContext(), 7690b57cec5SDimitry Andric C.blockCount()); 7700b57cec5SDimitry Andric 7710b57cec5SDimitry Andric if (!hypothetical) { 7720b57cec5SDimitry Andric if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) { 7730b57cec5SDimitry Andric // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4 7740b57cec5SDimitry Andric BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); 7750b57cec5SDimitry Andric const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); 7760b57cec5SDimitry Andric llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4); 7770b57cec5SDimitry Andric const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt, 7780b57cec5SDimitry Andric fourInt); 7790b57cec5SDimitry Andric NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt); 7800b57cec5SDimitry Andric SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, 7810b57cec5SDimitry Andric maxLength, sizeTy); 7820b57cec5SDimitry Andric state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true); 7830b57cec5SDimitry Andric } 7840b57cec5SDimitry Andric state = state->set<CStringLength>(MR, strLength); 7850b57cec5SDimitry Andric } 7860b57cec5SDimitry Andric 7870b57cec5SDimitry Andric return strLength; 7880b57cec5SDimitry Andric } 7890b57cec5SDimitry Andric 7900b57cec5SDimitry Andric SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, 7910b57cec5SDimitry Andric const Expr *Ex, SVal Buf, 7920b57cec5SDimitry Andric bool hypothetical) const { 7930b57cec5SDimitry Andric const MemRegion *MR = Buf.getAsRegion(); 7940b57cec5SDimitry Andric if (!MR) { 7950b57cec5SDimitry Andric // If we can't get a region, see if it's something we /know/ isn't a 7960b57cec5SDimitry Andric // C string. In the context of locations, the only time we can issue such 7970b57cec5SDimitry Andric // a warning is for labels. 7980b57cec5SDimitry Andric if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) { 7990b57cec5SDimitry Andric if (Filter.CheckCStringNotNullTerm) { 8000b57cec5SDimitry Andric SmallString<120> buf; 8010b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 8020b57cec5SDimitry Andric assert(CurrentFunctionDescription); 8030b57cec5SDimitry Andric os << "Argument to " << CurrentFunctionDescription 8040b57cec5SDimitry Andric << " is the address of the label '" << Label->getLabel()->getName() 8050b57cec5SDimitry Andric << "', which is not a null-terminated string"; 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric emitNotCStringBug(C, state, Ex, os.str()); 8080b57cec5SDimitry Andric } 8090b57cec5SDimitry Andric return UndefinedVal(); 8100b57cec5SDimitry Andric } 8110b57cec5SDimitry Andric 8120b57cec5SDimitry Andric // If it's not a region and not a label, give up. 8130b57cec5SDimitry Andric return UnknownVal(); 8140b57cec5SDimitry Andric } 8150b57cec5SDimitry Andric 8160b57cec5SDimitry Andric // If we have a region, strip casts from it and see if we can figure out 8170b57cec5SDimitry Andric // its length. For anything we can't figure out, just return UnknownVal. 8180b57cec5SDimitry Andric MR = MR->StripCasts(); 8190b57cec5SDimitry Andric 8200b57cec5SDimitry Andric switch (MR->getKind()) { 8210b57cec5SDimitry Andric case MemRegion::StringRegionKind: { 8220b57cec5SDimitry Andric // Modifying the contents of string regions is undefined [C99 6.4.5p6], 8230b57cec5SDimitry Andric // so we can assume that the byte length is the correct C string length. 8240b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 8250b57cec5SDimitry Andric QualType sizeTy = svalBuilder.getContext().getSizeType(); 8260b57cec5SDimitry Andric const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral(); 8270b57cec5SDimitry Andric return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy); 8280b57cec5SDimitry Andric } 8290b57cec5SDimitry Andric case MemRegion::SymbolicRegionKind: 8300b57cec5SDimitry Andric case MemRegion::AllocaRegionKind: 8310b57cec5SDimitry Andric case MemRegion::VarRegionKind: 8320b57cec5SDimitry Andric case MemRegion::FieldRegionKind: 8330b57cec5SDimitry Andric case MemRegion::ObjCIvarRegionKind: 8340b57cec5SDimitry Andric return getCStringLengthForRegion(C, state, Ex, MR, hypothetical); 8350b57cec5SDimitry Andric case MemRegion::CompoundLiteralRegionKind: 8360b57cec5SDimitry Andric // FIXME: Can we track this? Is it necessary? 8370b57cec5SDimitry Andric return UnknownVal(); 8380b57cec5SDimitry Andric case MemRegion::ElementRegionKind: 8390b57cec5SDimitry Andric // FIXME: How can we handle this? It's not good enough to subtract the 8400b57cec5SDimitry Andric // offset from the base string length; consider "123\x00567" and &a[5]. 8410b57cec5SDimitry Andric return UnknownVal(); 8420b57cec5SDimitry Andric default: 8430b57cec5SDimitry Andric // Other regions (mostly non-data) can't have a reliable C string length. 8440b57cec5SDimitry Andric // In this case, an error is emitted and UndefinedVal is returned. 8450b57cec5SDimitry Andric // The caller should always be prepared to handle this case. 8460b57cec5SDimitry Andric if (Filter.CheckCStringNotNullTerm) { 8470b57cec5SDimitry Andric SmallString<120> buf; 8480b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 8490b57cec5SDimitry Andric 8500b57cec5SDimitry Andric assert(CurrentFunctionDescription); 8510b57cec5SDimitry Andric os << "Argument to " << CurrentFunctionDescription << " is "; 8520b57cec5SDimitry Andric 8530b57cec5SDimitry Andric if (SummarizeRegion(os, C.getASTContext(), MR)) 8540b57cec5SDimitry Andric os << ", which is not a null-terminated string"; 8550b57cec5SDimitry Andric else 8560b57cec5SDimitry Andric os << "not a null-terminated string"; 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric emitNotCStringBug(C, state, Ex, os.str()); 8590b57cec5SDimitry Andric } 8600b57cec5SDimitry Andric return UndefinedVal(); 8610b57cec5SDimitry Andric } 8620b57cec5SDimitry Andric } 8630b57cec5SDimitry Andric 8640b57cec5SDimitry Andric const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, 8650b57cec5SDimitry Andric ProgramStateRef &state, const Expr *expr, SVal val) const { 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric // Get the memory region pointed to by the val. 8680b57cec5SDimitry Andric const MemRegion *bufRegion = val.getAsRegion(); 8690b57cec5SDimitry Andric if (!bufRegion) 8700b57cec5SDimitry Andric return nullptr; 8710b57cec5SDimitry Andric 8720b57cec5SDimitry Andric // Strip casts off the memory region. 8730b57cec5SDimitry Andric bufRegion = bufRegion->StripCasts(); 8740b57cec5SDimitry Andric 8750b57cec5SDimitry Andric // Cast the memory region to a string region. 8760b57cec5SDimitry Andric const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion); 8770b57cec5SDimitry Andric if (!strRegion) 8780b57cec5SDimitry Andric return nullptr; 8790b57cec5SDimitry Andric 8800b57cec5SDimitry Andric // Return the actual string in the string region. 8810b57cec5SDimitry Andric return strRegion->getStringLiteral(); 8820b57cec5SDimitry Andric } 8830b57cec5SDimitry Andric 8840b57cec5SDimitry Andric bool CStringChecker::IsFirstBufInBound(CheckerContext &C, 8850b57cec5SDimitry Andric ProgramStateRef state, 8860b57cec5SDimitry Andric const Expr *FirstBuf, 8870b57cec5SDimitry Andric const Expr *Size) { 8880b57cec5SDimitry Andric // If we do not know that the buffer is long enough we return 'true'. 8890b57cec5SDimitry Andric // Otherwise the parent region of this field region would also get 8900b57cec5SDimitry Andric // invalidated, which would lead to warnings based on an unknown state. 8910b57cec5SDimitry Andric 8920b57cec5SDimitry Andric // Originally copied from CheckBufferAccess and CheckLocation. 8930b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 8940b57cec5SDimitry Andric ASTContext &Ctx = svalBuilder.getContext(); 8950b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 8960b57cec5SDimitry Andric 8970b57cec5SDimitry Andric QualType sizeTy = Size->getType(); 8980b57cec5SDimitry Andric QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); 8990b57cec5SDimitry Andric SVal BufVal = state->getSVal(FirstBuf, LCtx); 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric SVal LengthVal = state->getSVal(Size, LCtx); 9020b57cec5SDimitry Andric Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 9030b57cec5SDimitry Andric if (!Length) 9040b57cec5SDimitry Andric return true; // cf top comment. 9050b57cec5SDimitry Andric 9060b57cec5SDimitry Andric // Compute the offset of the last element to be accessed: size-1. 9070b57cec5SDimitry Andric NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 9080b57cec5SDimitry Andric SVal Offset = svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy); 9090b57cec5SDimitry Andric if (Offset.isUnknown()) 9100b57cec5SDimitry Andric return true; // cf top comment 9110b57cec5SDimitry Andric NonLoc LastOffset = Offset.castAs<NonLoc>(); 9120b57cec5SDimitry Andric 9130b57cec5SDimitry Andric // Check that the first buffer is sufficiently long. 9140b57cec5SDimitry Andric SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); 9150b57cec5SDimitry Andric Optional<Loc> BufLoc = BufStart.getAs<Loc>(); 9160b57cec5SDimitry Andric if (!BufLoc) 9170b57cec5SDimitry Andric return true; // cf top comment. 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric SVal BufEnd = 9200b57cec5SDimitry Andric svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, LastOffset, PtrTy); 9210b57cec5SDimitry Andric 9220b57cec5SDimitry Andric // Check for out of bound array element access. 9230b57cec5SDimitry Andric const MemRegion *R = BufEnd.getAsRegion(); 9240b57cec5SDimitry Andric if (!R) 9250b57cec5SDimitry Andric return true; // cf top comment. 9260b57cec5SDimitry Andric 9270b57cec5SDimitry Andric const ElementRegion *ER = dyn_cast<ElementRegion>(R); 9280b57cec5SDimitry Andric if (!ER) 9290b57cec5SDimitry Andric return true; // cf top comment. 9300b57cec5SDimitry Andric 9310b57cec5SDimitry Andric // FIXME: Does this crash when a non-standard definition 9320b57cec5SDimitry Andric // of a library function is encountered? 9330b57cec5SDimitry Andric assert(ER->getValueType() == C.getASTContext().CharTy && 9340b57cec5SDimitry Andric "IsFirstBufInBound should only be called with char* ElementRegions"); 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric // Get the size of the array. 9370b57cec5SDimitry Andric const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); 9380b57cec5SDimitry Andric SVal Extent = 9390b57cec5SDimitry Andric svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); 9400b57cec5SDimitry Andric DefinedOrUnknownSVal ExtentSize = Extent.castAs<DefinedOrUnknownSVal>(); 9410b57cec5SDimitry Andric 9420b57cec5SDimitry Andric // Get the index of the accessed element. 9430b57cec5SDimitry Andric DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 9440b57cec5SDimitry Andric 9450b57cec5SDimitry Andric ProgramStateRef StInBound = state->assumeInBound(Idx, ExtentSize, true); 9460b57cec5SDimitry Andric 9470b57cec5SDimitry Andric return static_cast<bool>(StInBound); 9480b57cec5SDimitry Andric } 9490b57cec5SDimitry Andric 9500b57cec5SDimitry Andric ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, 9510b57cec5SDimitry Andric ProgramStateRef state, 9520b57cec5SDimitry Andric const Expr *E, SVal V, 9530b57cec5SDimitry Andric bool IsSourceBuffer, 9540b57cec5SDimitry Andric const Expr *Size) { 9550b57cec5SDimitry Andric Optional<Loc> L = V.getAs<Loc>(); 9560b57cec5SDimitry Andric if (!L) 9570b57cec5SDimitry Andric return state; 9580b57cec5SDimitry Andric 9590b57cec5SDimitry Andric // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes 9600b57cec5SDimitry Andric // some assumptions about the value that CFRefCount can't. Even so, it should 9610b57cec5SDimitry Andric // probably be refactored. 9620b57cec5SDimitry Andric if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) { 9630b57cec5SDimitry Andric const MemRegion *R = MR->getRegion()->StripCasts(); 9640b57cec5SDimitry Andric 9650b57cec5SDimitry Andric // Are we dealing with an ElementRegion? If so, we should be invalidating 9660b57cec5SDimitry Andric // the super-region. 9670b57cec5SDimitry Andric if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { 9680b57cec5SDimitry Andric R = ER->getSuperRegion(); 9690b57cec5SDimitry Andric // FIXME: What about layers of ElementRegions? 9700b57cec5SDimitry Andric } 9710b57cec5SDimitry Andric 9720b57cec5SDimitry Andric // Invalidate this region. 9730b57cec5SDimitry Andric const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); 9740b57cec5SDimitry Andric 9750b57cec5SDimitry Andric bool CausesPointerEscape = false; 9760b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits ITraits; 9770b57cec5SDimitry Andric // Invalidate and escape only indirect regions accessible through the source 9780b57cec5SDimitry Andric // buffer. 9790b57cec5SDimitry Andric if (IsSourceBuffer) { 9800b57cec5SDimitry Andric ITraits.setTrait(R->getBaseRegion(), 9810b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits::TK_PreserveContents); 9820b57cec5SDimitry Andric ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); 9830b57cec5SDimitry Andric CausesPointerEscape = true; 9840b57cec5SDimitry Andric } else { 9850b57cec5SDimitry Andric const MemRegion::Kind& K = R->getKind(); 9860b57cec5SDimitry Andric if (K == MemRegion::FieldRegionKind) 9870b57cec5SDimitry Andric if (Size && IsFirstBufInBound(C, state, E, Size)) { 9880b57cec5SDimitry Andric // If destination buffer is a field region and access is in bound, 9890b57cec5SDimitry Andric // do not invalidate its super region. 9900b57cec5SDimitry Andric ITraits.setTrait( 9910b57cec5SDimitry Andric R, 9920b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); 9930b57cec5SDimitry Andric } 9940b57cec5SDimitry Andric } 9950b57cec5SDimitry Andric 9960b57cec5SDimitry Andric return state->invalidateRegions(R, E, C.blockCount(), LCtx, 9970b57cec5SDimitry Andric CausesPointerEscape, nullptr, nullptr, 9980b57cec5SDimitry Andric &ITraits); 9990b57cec5SDimitry Andric } 10000b57cec5SDimitry Andric 10010b57cec5SDimitry Andric // If we have a non-region value by chance, just remove the binding. 10020b57cec5SDimitry Andric // FIXME: is this necessary or correct? This handles the non-Region 10030b57cec5SDimitry Andric // cases. Is it ever valid to store to these? 10040b57cec5SDimitry Andric return state->killBinding(*L); 10050b57cec5SDimitry Andric } 10060b57cec5SDimitry Andric 10070b57cec5SDimitry Andric bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, 10080b57cec5SDimitry Andric const MemRegion *MR) { 10090b57cec5SDimitry Andric switch (MR->getKind()) { 10100b57cec5SDimitry Andric case MemRegion::FunctionCodeRegionKind: { 1011*480093f4SDimitry Andric if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl()) 10120b57cec5SDimitry Andric os << "the address of the function '" << *FD << '\''; 10130b57cec5SDimitry Andric else 10140b57cec5SDimitry Andric os << "the address of a function"; 10150b57cec5SDimitry Andric return true; 10160b57cec5SDimitry Andric } 10170b57cec5SDimitry Andric case MemRegion::BlockCodeRegionKind: 10180b57cec5SDimitry Andric os << "block text"; 10190b57cec5SDimitry Andric return true; 10200b57cec5SDimitry Andric case MemRegion::BlockDataRegionKind: 10210b57cec5SDimitry Andric os << "a block"; 10220b57cec5SDimitry Andric return true; 10230b57cec5SDimitry Andric case MemRegion::CXXThisRegionKind: 10240b57cec5SDimitry Andric case MemRegion::CXXTempObjectRegionKind: 1025*480093f4SDimitry Andric os << "a C++ temp object of type " 1026*480093f4SDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10270b57cec5SDimitry Andric return true; 10280b57cec5SDimitry Andric case MemRegion::VarRegionKind: 1029*480093f4SDimitry Andric os << "a variable of type" 1030*480093f4SDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10310b57cec5SDimitry Andric return true; 10320b57cec5SDimitry Andric case MemRegion::FieldRegionKind: 1033*480093f4SDimitry Andric os << "a field of type " 1034*480093f4SDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10350b57cec5SDimitry Andric return true; 10360b57cec5SDimitry Andric case MemRegion::ObjCIvarRegionKind: 1037*480093f4SDimitry Andric os << "an instance variable of type " 1038*480093f4SDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10390b57cec5SDimitry Andric return true; 10400b57cec5SDimitry Andric default: 10410b57cec5SDimitry Andric return false; 10420b57cec5SDimitry Andric } 10430b57cec5SDimitry Andric } 10440b57cec5SDimitry Andric 10450b57cec5SDimitry Andric bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, 10460b57cec5SDimitry Andric const Expr *Size, CheckerContext &C, 10470b57cec5SDimitry Andric ProgramStateRef &State) { 10480b57cec5SDimitry Andric SVal MemVal = C.getSVal(DstBuffer); 10490b57cec5SDimitry Andric SVal SizeVal = C.getSVal(Size); 10500b57cec5SDimitry Andric const MemRegion *MR = MemVal.getAsRegion(); 10510b57cec5SDimitry Andric if (!MR) 10520b57cec5SDimitry Andric return false; 10530b57cec5SDimitry Andric 10540b57cec5SDimitry Andric // We're about to model memset by producing a "default binding" in the Store. 10550b57cec5SDimitry Andric // Our current implementation - RegionStore - doesn't support default bindings 10560b57cec5SDimitry Andric // that don't cover the whole base region. So we should first get the offset 10570b57cec5SDimitry Andric // and the base region to figure out whether the offset of buffer is 0. 10580b57cec5SDimitry Andric RegionOffset Offset = MR->getAsOffset(); 10590b57cec5SDimitry Andric const MemRegion *BR = Offset.getRegion(); 10600b57cec5SDimitry Andric 10610b57cec5SDimitry Andric Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>(); 10620b57cec5SDimitry Andric if (!SizeNL) 10630b57cec5SDimitry Andric return false; 10640b57cec5SDimitry Andric 10650b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 10660b57cec5SDimitry Andric ASTContext &Ctx = C.getASTContext(); 10670b57cec5SDimitry Andric 10680b57cec5SDimitry Andric // void *memset(void *dest, int ch, size_t count); 10690b57cec5SDimitry Andric // For now we can only handle the case of offset is 0 and concrete char value. 10700b57cec5SDimitry Andric if (Offset.isValid() && !Offset.hasSymbolicOffset() && 10710b57cec5SDimitry Andric Offset.getOffset() == 0) { 10720b57cec5SDimitry Andric // Get the base region's extent. 10730b57cec5SDimitry Andric auto *SubReg = cast<SubRegion>(BR); 10740b57cec5SDimitry Andric DefinedOrUnknownSVal Extent = SubReg->getExtent(svalBuilder); 10750b57cec5SDimitry Andric 10760b57cec5SDimitry Andric ProgramStateRef StateWholeReg, StateNotWholeReg; 10770b57cec5SDimitry Andric std::tie(StateWholeReg, StateNotWholeReg) = 10780b57cec5SDimitry Andric State->assume(svalBuilder.evalEQ(State, Extent, *SizeNL)); 10790b57cec5SDimitry Andric 10800b57cec5SDimitry Andric // With the semantic of 'memset()', we should convert the CharVal to 10810b57cec5SDimitry Andric // unsigned char. 10820b57cec5SDimitry Andric CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy); 10830b57cec5SDimitry Andric 10840b57cec5SDimitry Andric ProgramStateRef StateNullChar, StateNonNullChar; 10850b57cec5SDimitry Andric std::tie(StateNullChar, StateNonNullChar) = 10860b57cec5SDimitry Andric assumeZero(C, State, CharVal, Ctx.UnsignedCharTy); 10870b57cec5SDimitry Andric 10880b57cec5SDimitry Andric if (StateWholeReg && !StateNotWholeReg && StateNullChar && 10890b57cec5SDimitry Andric !StateNonNullChar) { 10900b57cec5SDimitry Andric // If the 'memset()' acts on the whole region of destination buffer and 10910b57cec5SDimitry Andric // the value of the second argument of 'memset()' is zero, bind the second 10920b57cec5SDimitry Andric // argument's value to the destination buffer with 'default binding'. 10930b57cec5SDimitry Andric // FIXME: Since there is no perfect way to bind the non-zero character, we 10940b57cec5SDimitry Andric // can only deal with zero value here. In the future, we need to deal with 10950b57cec5SDimitry Andric // the binding of non-zero value in the case of whole region. 10960b57cec5SDimitry Andric State = State->bindDefaultZero(svalBuilder.makeLoc(BR), 10970b57cec5SDimitry Andric C.getLocationContext()); 10980b57cec5SDimitry Andric } else { 10990b57cec5SDimitry Andric // If the destination buffer's extent is not equal to the value of 11000b57cec5SDimitry Andric // third argument, just invalidate buffer. 11010b57cec5SDimitry Andric State = InvalidateBuffer(C, State, DstBuffer, MemVal, 11020b57cec5SDimitry Andric /*IsSourceBuffer*/ false, Size); 11030b57cec5SDimitry Andric } 11040b57cec5SDimitry Andric 11050b57cec5SDimitry Andric if (StateNullChar && !StateNonNullChar) { 11060b57cec5SDimitry Andric // If the value of the second argument of 'memset()' is zero, set the 11070b57cec5SDimitry Andric // string length of destination buffer to 0 directly. 11080b57cec5SDimitry Andric State = setCStringLength(State, MR, 11090b57cec5SDimitry Andric svalBuilder.makeZeroVal(Ctx.getSizeType())); 11100b57cec5SDimitry Andric } else if (!StateNullChar && StateNonNullChar) { 11110b57cec5SDimitry Andric SVal NewStrLen = svalBuilder.getMetadataSymbolVal( 11120b57cec5SDimitry Andric CStringChecker::getTag(), MR, DstBuffer, Ctx.getSizeType(), 11130b57cec5SDimitry Andric C.getLocationContext(), C.blockCount()); 11140b57cec5SDimitry Andric 11150b57cec5SDimitry Andric // If the value of second argument is not zero, then the string length 11160b57cec5SDimitry Andric // is at least the size argument. 11170b57cec5SDimitry Andric SVal NewStrLenGESize = svalBuilder.evalBinOp( 11180b57cec5SDimitry Andric State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType()); 11190b57cec5SDimitry Andric 11200b57cec5SDimitry Andric State = setCStringLength( 11210b57cec5SDimitry Andric State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(), true), 11220b57cec5SDimitry Andric MR, NewStrLen); 11230b57cec5SDimitry Andric } 11240b57cec5SDimitry Andric } else { 11250b57cec5SDimitry Andric // If the offset is not zero and char value is not concrete, we can do 11260b57cec5SDimitry Andric // nothing but invalidate the buffer. 11270b57cec5SDimitry Andric State = InvalidateBuffer(C, State, DstBuffer, MemVal, 11280b57cec5SDimitry Andric /*IsSourceBuffer*/ false, Size); 11290b57cec5SDimitry Andric } 11300b57cec5SDimitry Andric return true; 11310b57cec5SDimitry Andric } 11320b57cec5SDimitry Andric 11330b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11340b57cec5SDimitry Andric // evaluation of individual function calls. 11350b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric void CStringChecker::evalCopyCommon(CheckerContext &C, 11380b57cec5SDimitry Andric const CallExpr *CE, 11390b57cec5SDimitry Andric ProgramStateRef state, 11400b57cec5SDimitry Andric const Expr *Size, const Expr *Dest, 11410b57cec5SDimitry Andric const Expr *Source, bool Restricted, 11420b57cec5SDimitry Andric bool IsMempcpy) const { 11430b57cec5SDimitry Andric CurrentFunctionDescription = "memory copy function"; 11440b57cec5SDimitry Andric 11450b57cec5SDimitry Andric // See if the size argument is zero. 11460b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 11470b57cec5SDimitry Andric SVal sizeVal = state->getSVal(Size, LCtx); 11480b57cec5SDimitry Andric QualType sizeTy = Size->getType(); 11490b57cec5SDimitry Andric 11500b57cec5SDimitry Andric ProgramStateRef stateZeroSize, stateNonZeroSize; 11510b57cec5SDimitry Andric std::tie(stateZeroSize, stateNonZeroSize) = 11520b57cec5SDimitry Andric assumeZero(C, state, sizeVal, sizeTy); 11530b57cec5SDimitry Andric 11540b57cec5SDimitry Andric // Get the value of the Dest. 11550b57cec5SDimitry Andric SVal destVal = state->getSVal(Dest, LCtx); 11560b57cec5SDimitry Andric 11570b57cec5SDimitry Andric // If the size is zero, there won't be any actual memory access, so 11580b57cec5SDimitry Andric // just bind the return value to the destination buffer and return. 11590b57cec5SDimitry Andric if (stateZeroSize && !stateNonZeroSize) { 11600b57cec5SDimitry Andric stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal); 11610b57cec5SDimitry Andric C.addTransition(stateZeroSize); 11620b57cec5SDimitry Andric return; 11630b57cec5SDimitry Andric } 11640b57cec5SDimitry Andric 11650b57cec5SDimitry Andric // If the size can be nonzero, we have to check the other arguments. 11660b57cec5SDimitry Andric if (stateNonZeroSize) { 11670b57cec5SDimitry Andric state = stateNonZeroSize; 11680b57cec5SDimitry Andric 11690b57cec5SDimitry Andric // Ensure the destination is not null. If it is NULL there will be a 11700b57cec5SDimitry Andric // NULL pointer dereference. 1171a7dea167SDimitry Andric state = checkNonNull(C, state, Dest, destVal, 1); 11720b57cec5SDimitry Andric if (!state) 11730b57cec5SDimitry Andric return; 11740b57cec5SDimitry Andric 11750b57cec5SDimitry Andric // Get the value of the Src. 11760b57cec5SDimitry Andric SVal srcVal = state->getSVal(Source, LCtx); 11770b57cec5SDimitry Andric 11780b57cec5SDimitry Andric // Ensure the source is not null. If it is NULL there will be a 11790b57cec5SDimitry Andric // NULL pointer dereference. 1180a7dea167SDimitry Andric state = checkNonNull(C, state, Source, srcVal, 2); 11810b57cec5SDimitry Andric if (!state) 11820b57cec5SDimitry Andric return; 11830b57cec5SDimitry Andric 11840b57cec5SDimitry Andric // Ensure the accesses are valid and that the buffers do not overlap. 11850b57cec5SDimitry Andric const char * const writeWarning = 11860b57cec5SDimitry Andric "Memory copy function overflows destination buffer"; 11870b57cec5SDimitry Andric state = CheckBufferAccess(C, state, Size, Dest, Source, 11880b57cec5SDimitry Andric writeWarning, /* sourceWarning = */ nullptr); 11890b57cec5SDimitry Andric if (Restricted) 11900b57cec5SDimitry Andric state = CheckOverlap(C, state, Size, Dest, Source); 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric if (!state) 11930b57cec5SDimitry Andric return; 11940b57cec5SDimitry Andric 11950b57cec5SDimitry Andric // If this is mempcpy, get the byte after the last byte copied and 11960b57cec5SDimitry Andric // bind the expr. 11970b57cec5SDimitry Andric if (IsMempcpy) { 11980b57cec5SDimitry Andric // Get the byte after the last byte copied. 11990b57cec5SDimitry Andric SValBuilder &SvalBuilder = C.getSValBuilder(); 12000b57cec5SDimitry Andric ASTContext &Ctx = SvalBuilder.getContext(); 12010b57cec5SDimitry Andric QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); 12020b57cec5SDimitry Andric SVal DestRegCharVal = 12030b57cec5SDimitry Andric SvalBuilder.evalCast(destVal, CharPtrTy, Dest->getType()); 12040b57cec5SDimitry Andric SVal lastElement = C.getSValBuilder().evalBinOp( 12050b57cec5SDimitry Andric state, BO_Add, DestRegCharVal, sizeVal, Dest->getType()); 12060b57cec5SDimitry Andric // If we don't know how much we copied, we can at least 12070b57cec5SDimitry Andric // conjure a return value for later. 12080b57cec5SDimitry Andric if (lastElement.isUnknown()) 12090b57cec5SDimitry Andric lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 12100b57cec5SDimitry Andric C.blockCount()); 12110b57cec5SDimitry Andric 12120b57cec5SDimitry Andric // The byte after the last byte copied is the return value. 12130b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, lastElement); 12140b57cec5SDimitry Andric } else { 12150b57cec5SDimitry Andric // All other copies return the destination buffer. 12160b57cec5SDimitry Andric // (Well, bcopy() has a void return type, but this won't hurt.) 12170b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, destVal); 12180b57cec5SDimitry Andric } 12190b57cec5SDimitry Andric 12200b57cec5SDimitry Andric // Invalidate the destination (regular invalidation without pointer-escaping 12210b57cec5SDimitry Andric // the address of the top-level region). 12220b57cec5SDimitry Andric // FIXME: Even if we can't perfectly model the copy, we should see if we 12230b57cec5SDimitry Andric // can use LazyCompoundVals to copy the source values into the destination. 12240b57cec5SDimitry Andric // This would probably remove any existing bindings past the end of the 12250b57cec5SDimitry Andric // copied region, but that's still an improvement over blank invalidation. 12260b57cec5SDimitry Andric state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest), 12270b57cec5SDimitry Andric /*IsSourceBuffer*/false, Size); 12280b57cec5SDimitry Andric 12290b57cec5SDimitry Andric // Invalidate the source (const-invalidation without const-pointer-escaping 12300b57cec5SDimitry Andric // the address of the top-level region). 12310b57cec5SDimitry Andric state = InvalidateBuffer(C, state, Source, C.getSVal(Source), 12320b57cec5SDimitry Andric /*IsSourceBuffer*/true, nullptr); 12330b57cec5SDimitry Andric 12340b57cec5SDimitry Andric C.addTransition(state); 12350b57cec5SDimitry Andric } 12360b57cec5SDimitry Andric } 12370b57cec5SDimitry Andric 12380b57cec5SDimitry Andric 12390b57cec5SDimitry Andric void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { 12400b57cec5SDimitry Andric // void *memcpy(void *restrict dst, const void *restrict src, size_t n); 12410b57cec5SDimitry Andric // The return value is the address of the destination buffer. 12420b57cec5SDimitry Andric const Expr *Dest = CE->getArg(0); 12430b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 12440b57cec5SDimitry Andric 12450b57cec5SDimitry Andric evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true); 12460b57cec5SDimitry Andric } 12470b57cec5SDimitry Andric 12480b57cec5SDimitry Andric void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { 12490b57cec5SDimitry Andric // void *mempcpy(void *restrict dst, const void *restrict src, size_t n); 12500b57cec5SDimitry Andric // The return value is a pointer to the byte following the last written byte. 12510b57cec5SDimitry Andric const Expr *Dest = CE->getArg(0); 12520b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 12530b57cec5SDimitry Andric 12540b57cec5SDimitry Andric evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true); 12550b57cec5SDimitry Andric } 12560b57cec5SDimitry Andric 12570b57cec5SDimitry Andric void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { 12580b57cec5SDimitry Andric // void *memmove(void *dst, const void *src, size_t n); 12590b57cec5SDimitry Andric // The return value is the address of the destination buffer. 12600b57cec5SDimitry Andric const Expr *Dest = CE->getArg(0); 12610b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 12620b57cec5SDimitry Andric 12630b57cec5SDimitry Andric evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1)); 12640b57cec5SDimitry Andric } 12650b57cec5SDimitry Andric 12660b57cec5SDimitry Andric void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { 12670b57cec5SDimitry Andric // void bcopy(const void *src, void *dst, size_t n); 12680b57cec5SDimitry Andric evalCopyCommon(C, CE, C.getState(), 12690b57cec5SDimitry Andric CE->getArg(2), CE->getArg(1), CE->getArg(0)); 12700b57cec5SDimitry Andric } 12710b57cec5SDimitry Andric 12720b57cec5SDimitry Andric void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { 12730b57cec5SDimitry Andric // int memcmp(const void *s1, const void *s2, size_t n); 12740b57cec5SDimitry Andric CurrentFunctionDescription = "memory comparison function"; 12750b57cec5SDimitry Andric 12760b57cec5SDimitry Andric const Expr *Left = CE->getArg(0); 12770b57cec5SDimitry Andric const Expr *Right = CE->getArg(1); 12780b57cec5SDimitry Andric const Expr *Size = CE->getArg(2); 12790b57cec5SDimitry Andric 12800b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 12810b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 12820b57cec5SDimitry Andric 12830b57cec5SDimitry Andric // See if the size argument is zero. 12840b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 12850b57cec5SDimitry Andric SVal sizeVal = state->getSVal(Size, LCtx); 12860b57cec5SDimitry Andric QualType sizeTy = Size->getType(); 12870b57cec5SDimitry Andric 12880b57cec5SDimitry Andric ProgramStateRef stateZeroSize, stateNonZeroSize; 12890b57cec5SDimitry Andric std::tie(stateZeroSize, stateNonZeroSize) = 12900b57cec5SDimitry Andric assumeZero(C, state, sizeVal, sizeTy); 12910b57cec5SDimitry Andric 12920b57cec5SDimitry Andric // If the size can be zero, the result will be 0 in that case, and we don't 12930b57cec5SDimitry Andric // have to check either of the buffers. 12940b57cec5SDimitry Andric if (stateZeroSize) { 12950b57cec5SDimitry Andric state = stateZeroSize; 12960b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, 12970b57cec5SDimitry Andric svalBuilder.makeZeroVal(CE->getType())); 12980b57cec5SDimitry Andric C.addTransition(state); 12990b57cec5SDimitry Andric } 13000b57cec5SDimitry Andric 13010b57cec5SDimitry Andric // If the size can be nonzero, we have to check the other arguments. 13020b57cec5SDimitry Andric if (stateNonZeroSize) { 13030b57cec5SDimitry Andric state = stateNonZeroSize; 13040b57cec5SDimitry Andric // If we know the two buffers are the same, we know the result is 0. 13050b57cec5SDimitry Andric // First, get the two buffers' addresses. Another checker will have already 13060b57cec5SDimitry Andric // made sure they're not undefined. 13070b57cec5SDimitry Andric DefinedOrUnknownSVal LV = 13080b57cec5SDimitry Andric state->getSVal(Left, LCtx).castAs<DefinedOrUnknownSVal>(); 13090b57cec5SDimitry Andric DefinedOrUnknownSVal RV = 13100b57cec5SDimitry Andric state->getSVal(Right, LCtx).castAs<DefinedOrUnknownSVal>(); 13110b57cec5SDimitry Andric 13120b57cec5SDimitry Andric // See if they are the same. 13130b57cec5SDimitry Andric DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); 13140b57cec5SDimitry Andric ProgramStateRef StSameBuf, StNotSameBuf; 13150b57cec5SDimitry Andric std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); 13160b57cec5SDimitry Andric 1317*480093f4SDimitry Andric // If the two arguments are the same buffer, we know the result is 0, 13180b57cec5SDimitry Andric // and we only need to check one size. 1319*480093f4SDimitry Andric if (StSameBuf && !StNotSameBuf) { 13200b57cec5SDimitry Andric state = StSameBuf; 13210b57cec5SDimitry Andric state = CheckBufferAccess(C, state, Size, Left); 13220b57cec5SDimitry Andric if (state) { 13230b57cec5SDimitry Andric state = StSameBuf->BindExpr(CE, LCtx, 13240b57cec5SDimitry Andric svalBuilder.makeZeroVal(CE->getType())); 13250b57cec5SDimitry Andric C.addTransition(state); 13260b57cec5SDimitry Andric } 1327*480093f4SDimitry Andric return; 13280b57cec5SDimitry Andric } 13290b57cec5SDimitry Andric 1330*480093f4SDimitry Andric // If the two arguments might be different buffers, we have to check 1331*480093f4SDimitry Andric // the size of both of them. 1332*480093f4SDimitry Andric assert(StNotSameBuf); 13330b57cec5SDimitry Andric state = CheckBufferAccess(C, state, Size, Left, Right); 13340b57cec5SDimitry Andric if (state) { 13350b57cec5SDimitry Andric // The return value is the comparison result, which we don't know. 1336*480093f4SDimitry Andric SVal CmpV = 1337*480093f4SDimitry Andric svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 13380b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, CmpV); 13390b57cec5SDimitry Andric C.addTransition(state); 13400b57cec5SDimitry Andric } 13410b57cec5SDimitry Andric } 13420b57cec5SDimitry Andric } 13430b57cec5SDimitry Andric 13440b57cec5SDimitry Andric void CStringChecker::evalstrLength(CheckerContext &C, 13450b57cec5SDimitry Andric const CallExpr *CE) const { 13460b57cec5SDimitry Andric // size_t strlen(const char *s); 13470b57cec5SDimitry Andric evalstrLengthCommon(C, CE, /* IsStrnlen = */ false); 13480b57cec5SDimitry Andric } 13490b57cec5SDimitry Andric 13500b57cec5SDimitry Andric void CStringChecker::evalstrnLength(CheckerContext &C, 13510b57cec5SDimitry Andric const CallExpr *CE) const { 13520b57cec5SDimitry Andric // size_t strnlen(const char *s, size_t maxlen); 13530b57cec5SDimitry Andric evalstrLengthCommon(C, CE, /* IsStrnlen = */ true); 13540b57cec5SDimitry Andric } 13550b57cec5SDimitry Andric 13560b57cec5SDimitry Andric void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, 13570b57cec5SDimitry Andric bool IsStrnlen) const { 13580b57cec5SDimitry Andric CurrentFunctionDescription = "string length function"; 13590b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 13600b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 13610b57cec5SDimitry Andric 13620b57cec5SDimitry Andric if (IsStrnlen) { 13630b57cec5SDimitry Andric const Expr *maxlenExpr = CE->getArg(1); 13640b57cec5SDimitry Andric SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); 13650b57cec5SDimitry Andric 13660b57cec5SDimitry Andric ProgramStateRef stateZeroSize, stateNonZeroSize; 13670b57cec5SDimitry Andric std::tie(stateZeroSize, stateNonZeroSize) = 13680b57cec5SDimitry Andric assumeZero(C, state, maxlenVal, maxlenExpr->getType()); 13690b57cec5SDimitry Andric 13700b57cec5SDimitry Andric // If the size can be zero, the result will be 0 in that case, and we don't 13710b57cec5SDimitry Andric // have to check the string itself. 13720b57cec5SDimitry Andric if (stateZeroSize) { 13730b57cec5SDimitry Andric SVal zero = C.getSValBuilder().makeZeroVal(CE->getType()); 13740b57cec5SDimitry Andric stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero); 13750b57cec5SDimitry Andric C.addTransition(stateZeroSize); 13760b57cec5SDimitry Andric } 13770b57cec5SDimitry Andric 13780b57cec5SDimitry Andric // If the size is GUARANTEED to be zero, we're done! 13790b57cec5SDimitry Andric if (!stateNonZeroSize) 13800b57cec5SDimitry Andric return; 13810b57cec5SDimitry Andric 13820b57cec5SDimitry Andric // Otherwise, record the assumption that the size is nonzero. 13830b57cec5SDimitry Andric state = stateNonZeroSize; 13840b57cec5SDimitry Andric } 13850b57cec5SDimitry Andric 13860b57cec5SDimitry Andric // Check that the string argument is non-null. 13870b57cec5SDimitry Andric const Expr *Arg = CE->getArg(0); 13880b57cec5SDimitry Andric SVal ArgVal = state->getSVal(Arg, LCtx); 13890b57cec5SDimitry Andric 1390a7dea167SDimitry Andric state = checkNonNull(C, state, Arg, ArgVal, 1); 13910b57cec5SDimitry Andric 13920b57cec5SDimitry Andric if (!state) 13930b57cec5SDimitry Andric return; 13940b57cec5SDimitry Andric 13950b57cec5SDimitry Andric SVal strLength = getCStringLength(C, state, Arg, ArgVal); 13960b57cec5SDimitry Andric 13970b57cec5SDimitry Andric // If the argument isn't a valid C string, there's no valid state to 13980b57cec5SDimitry Andric // transition to. 13990b57cec5SDimitry Andric if (strLength.isUndef()) 14000b57cec5SDimitry Andric return; 14010b57cec5SDimitry Andric 14020b57cec5SDimitry Andric DefinedOrUnknownSVal result = UnknownVal(); 14030b57cec5SDimitry Andric 14040b57cec5SDimitry Andric // If the check is for strnlen() then bind the return value to no more than 14050b57cec5SDimitry Andric // the maxlen value. 14060b57cec5SDimitry Andric if (IsStrnlen) { 14070b57cec5SDimitry Andric QualType cmpTy = C.getSValBuilder().getConditionType(); 14080b57cec5SDimitry Andric 14090b57cec5SDimitry Andric // It's a little unfortunate to be getting this again, 14100b57cec5SDimitry Andric // but it's not that expensive... 14110b57cec5SDimitry Andric const Expr *maxlenExpr = CE->getArg(1); 14120b57cec5SDimitry Andric SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); 14130b57cec5SDimitry Andric 14140b57cec5SDimitry Andric Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); 14150b57cec5SDimitry Andric Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>(); 14160b57cec5SDimitry Andric 14170b57cec5SDimitry Andric if (strLengthNL && maxlenValNL) { 14180b57cec5SDimitry Andric ProgramStateRef stateStringTooLong, stateStringNotTooLong; 14190b57cec5SDimitry Andric 14200b57cec5SDimitry Andric // Check if the strLength is greater than the maxlen. 14210b57cec5SDimitry Andric std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume( 14220b57cec5SDimitry Andric C.getSValBuilder() 14230b57cec5SDimitry Andric .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy) 14240b57cec5SDimitry Andric .castAs<DefinedOrUnknownSVal>()); 14250b57cec5SDimitry Andric 14260b57cec5SDimitry Andric if (stateStringTooLong && !stateStringNotTooLong) { 14270b57cec5SDimitry Andric // If the string is longer than maxlen, return maxlen. 14280b57cec5SDimitry Andric result = *maxlenValNL; 14290b57cec5SDimitry Andric } else if (stateStringNotTooLong && !stateStringTooLong) { 14300b57cec5SDimitry Andric // If the string is shorter than maxlen, return its length. 14310b57cec5SDimitry Andric result = *strLengthNL; 14320b57cec5SDimitry Andric } 14330b57cec5SDimitry Andric } 14340b57cec5SDimitry Andric 14350b57cec5SDimitry Andric if (result.isUnknown()) { 14360b57cec5SDimitry Andric // If we don't have enough information for a comparison, there's 14370b57cec5SDimitry Andric // no guarantee the full string length will actually be returned. 14380b57cec5SDimitry Andric // All we know is the return value is the min of the string length 14390b57cec5SDimitry Andric // and the limit. This is better than nothing. 14400b57cec5SDimitry Andric result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 14410b57cec5SDimitry Andric C.blockCount()); 14420b57cec5SDimitry Andric NonLoc resultNL = result.castAs<NonLoc>(); 14430b57cec5SDimitry Andric 14440b57cec5SDimitry Andric if (strLengthNL) { 14450b57cec5SDimitry Andric state = state->assume(C.getSValBuilder().evalBinOpNN( 14460b57cec5SDimitry Andric state, BO_LE, resultNL, *strLengthNL, cmpTy) 14470b57cec5SDimitry Andric .castAs<DefinedOrUnknownSVal>(), true); 14480b57cec5SDimitry Andric } 14490b57cec5SDimitry Andric 14500b57cec5SDimitry Andric if (maxlenValNL) { 14510b57cec5SDimitry Andric state = state->assume(C.getSValBuilder().evalBinOpNN( 14520b57cec5SDimitry Andric state, BO_LE, resultNL, *maxlenValNL, cmpTy) 14530b57cec5SDimitry Andric .castAs<DefinedOrUnknownSVal>(), true); 14540b57cec5SDimitry Andric } 14550b57cec5SDimitry Andric } 14560b57cec5SDimitry Andric 14570b57cec5SDimitry Andric } else { 14580b57cec5SDimitry Andric // This is a plain strlen(), not strnlen(). 14590b57cec5SDimitry Andric result = strLength.castAs<DefinedOrUnknownSVal>(); 14600b57cec5SDimitry Andric 14610b57cec5SDimitry Andric // If we don't know the length of the string, conjure a return 14620b57cec5SDimitry Andric // value, so it can be used in constraints, at least. 14630b57cec5SDimitry Andric if (result.isUnknown()) { 14640b57cec5SDimitry Andric result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 14650b57cec5SDimitry Andric C.blockCount()); 14660b57cec5SDimitry Andric } 14670b57cec5SDimitry Andric } 14680b57cec5SDimitry Andric 14690b57cec5SDimitry Andric // Bind the return value. 14700b57cec5SDimitry Andric assert(!result.isUnknown() && "Should have conjured a value by now"); 14710b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, result); 14720b57cec5SDimitry Andric C.addTransition(state); 14730b57cec5SDimitry Andric } 14740b57cec5SDimitry Andric 14750b57cec5SDimitry Andric void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { 14760b57cec5SDimitry Andric // char *strcpy(char *restrict dst, const char *restrict src); 14770b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1478*480093f4SDimitry Andric /* ReturnEnd = */ false, 1479*480093f4SDimitry Andric /* IsBounded = */ false, 1480*480093f4SDimitry Andric /* appendK = */ ConcatFnKind::none); 14810b57cec5SDimitry Andric } 14820b57cec5SDimitry Andric 14830b57cec5SDimitry Andric void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { 14840b57cec5SDimitry Andric // char *strncpy(char *restrict dst, const char *restrict src, size_t n); 14850b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1486*480093f4SDimitry Andric /* ReturnEnd = */ false, 1487*480093f4SDimitry Andric /* IsBounded = */ true, 1488*480093f4SDimitry Andric /* appendK = */ ConcatFnKind::none); 14890b57cec5SDimitry Andric } 14900b57cec5SDimitry Andric 14910b57cec5SDimitry Andric void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const { 14920b57cec5SDimitry Andric // char *stpcpy(char *restrict dst, const char *restrict src); 14930b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1494*480093f4SDimitry Andric /* ReturnEnd = */ true, 1495*480093f4SDimitry Andric /* IsBounded = */ false, 1496*480093f4SDimitry Andric /* appendK = */ ConcatFnKind::none); 14970b57cec5SDimitry Andric } 14980b57cec5SDimitry Andric 14990b57cec5SDimitry Andric void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const { 1500*480093f4SDimitry Andric // size_t strlcpy(char *dest, const char *src, size_t size); 15010b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1502*480093f4SDimitry Andric /* ReturnEnd = */ true, 1503*480093f4SDimitry Andric /* IsBounded = */ true, 1504*480093f4SDimitry Andric /* appendK = */ ConcatFnKind::none, 15050b57cec5SDimitry Andric /* returnPtr = */ false); 15060b57cec5SDimitry Andric } 15070b57cec5SDimitry Andric 15080b57cec5SDimitry Andric void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { 15090b57cec5SDimitry Andric // char *strcat(char *restrict s1, const char *restrict s2); 15100b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1511*480093f4SDimitry Andric /* ReturnEnd = */ false, 1512*480093f4SDimitry Andric /* IsBounded = */ false, 1513*480093f4SDimitry Andric /* appendK = */ ConcatFnKind::strcat); 15140b57cec5SDimitry Andric } 15150b57cec5SDimitry Andric 15160b57cec5SDimitry Andric void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const { 15170b57cec5SDimitry Andric //char *strncat(char *restrict s1, const char *restrict s2, size_t n); 15180b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1519*480093f4SDimitry Andric /* ReturnEnd = */ false, 1520*480093f4SDimitry Andric /* IsBounded = */ true, 1521*480093f4SDimitry Andric /* appendK = */ ConcatFnKind::strcat); 15220b57cec5SDimitry Andric } 15230b57cec5SDimitry Andric 15240b57cec5SDimitry Andric void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const { 1525*480093f4SDimitry Andric // size_t strlcat(char *dst, const char *src, size_t size); 1526*480093f4SDimitry Andric // It will append at most size - strlen(dst) - 1 bytes, 1527*480093f4SDimitry Andric // NULL-terminating the result. 15280b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1529*480093f4SDimitry Andric /* ReturnEnd = */ false, 1530*480093f4SDimitry Andric /* IsBounded = */ true, 1531*480093f4SDimitry Andric /* appendK = */ ConcatFnKind::strlcat, 15320b57cec5SDimitry Andric /* returnPtr = */ false); 15330b57cec5SDimitry Andric } 15340b57cec5SDimitry Andric 15350b57cec5SDimitry Andric void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, 1536*480093f4SDimitry Andric bool ReturnEnd, bool IsBounded, 1537*480093f4SDimitry Andric ConcatFnKind appendK, 1538*480093f4SDimitry Andric bool returnPtr) const { 1539*480093f4SDimitry Andric if (appendK == ConcatFnKind::none) 15400b57cec5SDimitry Andric CurrentFunctionDescription = "string copy function"; 1541*480093f4SDimitry Andric else 1542*480093f4SDimitry Andric CurrentFunctionDescription = "string concatenation function"; 15430b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 15440b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 15450b57cec5SDimitry Andric 15460b57cec5SDimitry Andric // Check that the destination is non-null. 15470b57cec5SDimitry Andric const Expr *Dst = CE->getArg(0); 15480b57cec5SDimitry Andric SVal DstVal = state->getSVal(Dst, LCtx); 15490b57cec5SDimitry Andric 1550a7dea167SDimitry Andric state = checkNonNull(C, state, Dst, DstVal, 1); 15510b57cec5SDimitry Andric if (!state) 15520b57cec5SDimitry Andric return; 15530b57cec5SDimitry Andric 15540b57cec5SDimitry Andric // Check that the source is non-null. 15550b57cec5SDimitry Andric const Expr *srcExpr = CE->getArg(1); 15560b57cec5SDimitry Andric SVal srcVal = state->getSVal(srcExpr, LCtx); 1557a7dea167SDimitry Andric state = checkNonNull(C, state, srcExpr, srcVal, 2); 15580b57cec5SDimitry Andric if (!state) 15590b57cec5SDimitry Andric return; 15600b57cec5SDimitry Andric 15610b57cec5SDimitry Andric // Get the string length of the source. 15620b57cec5SDimitry Andric SVal strLength = getCStringLength(C, state, srcExpr, srcVal); 1563*480093f4SDimitry Andric Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); 1564*480093f4SDimitry Andric 1565*480093f4SDimitry Andric // Get the string length of the destination buffer. 1566*480093f4SDimitry Andric SVal dstStrLength = getCStringLength(C, state, Dst, DstVal); 1567*480093f4SDimitry Andric Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); 15680b57cec5SDimitry Andric 15690b57cec5SDimitry Andric // If the source isn't a valid C string, give up. 15700b57cec5SDimitry Andric if (strLength.isUndef()) 15710b57cec5SDimitry Andric return; 15720b57cec5SDimitry Andric 15730b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 15740b57cec5SDimitry Andric QualType cmpTy = svalBuilder.getConditionType(); 15750b57cec5SDimitry Andric QualType sizeTy = svalBuilder.getContext().getSizeType(); 15760b57cec5SDimitry Andric 15770b57cec5SDimitry Andric // These two values allow checking two kinds of errors: 15780b57cec5SDimitry Andric // - actual overflows caused by a source that doesn't fit in the destination 15790b57cec5SDimitry Andric // - potential overflows caused by a bound that could exceed the destination 15800b57cec5SDimitry Andric SVal amountCopied = UnknownVal(); 15810b57cec5SDimitry Andric SVal maxLastElementIndex = UnknownVal(); 15820b57cec5SDimitry Andric const char *boundWarning = nullptr; 15830b57cec5SDimitry Andric 1584*480093f4SDimitry Andric state = CheckOverlap(C, state, IsBounded ? CE->getArg(2) : CE->getArg(1), Dst, 1585*480093f4SDimitry Andric srcExpr); 15860b57cec5SDimitry Andric 15870b57cec5SDimitry Andric if (!state) 15880b57cec5SDimitry Andric return; 15890b57cec5SDimitry Andric 15900b57cec5SDimitry Andric // If the function is strncpy, strncat, etc... it is bounded. 1591*480093f4SDimitry Andric if (IsBounded) { 15920b57cec5SDimitry Andric // Get the max number of characters to copy. 15930b57cec5SDimitry Andric const Expr *lenExpr = CE->getArg(2); 15940b57cec5SDimitry Andric SVal lenVal = state->getSVal(lenExpr, LCtx); 15950b57cec5SDimitry Andric 15960b57cec5SDimitry Andric // Protect against misdeclared strncpy(). 15970b57cec5SDimitry Andric lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType()); 15980b57cec5SDimitry Andric 15990b57cec5SDimitry Andric Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>(); 16000b57cec5SDimitry Andric 16010b57cec5SDimitry Andric // If we know both values, we might be able to figure out how much 16020b57cec5SDimitry Andric // we're copying. 16030b57cec5SDimitry Andric if (strLengthNL && lenValNL) { 1604*480093f4SDimitry Andric switch (appendK) { 1605*480093f4SDimitry Andric case ConcatFnKind::none: 1606*480093f4SDimitry Andric case ConcatFnKind::strcat: { 16070b57cec5SDimitry Andric ProgramStateRef stateSourceTooLong, stateSourceNotTooLong; 16080b57cec5SDimitry Andric // Check if the max number to copy is less than the length of the src. 16090b57cec5SDimitry Andric // If the bound is equal to the source length, strncpy won't null- 16100b57cec5SDimitry Andric // terminate the result! 16110b57cec5SDimitry Andric std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( 1612*480093f4SDimitry Andric svalBuilder 1613*480093f4SDimitry Andric .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) 16140b57cec5SDimitry Andric .castAs<DefinedOrUnknownSVal>()); 16150b57cec5SDimitry Andric 16160b57cec5SDimitry Andric if (stateSourceTooLong && !stateSourceNotTooLong) { 1617*480093f4SDimitry Andric // Max number to copy is less than the length of the src, so the 1618*480093f4SDimitry Andric // actual strLength copied is the max number arg. 16190b57cec5SDimitry Andric state = stateSourceTooLong; 16200b57cec5SDimitry Andric amountCopied = lenVal; 16210b57cec5SDimitry Andric 16220b57cec5SDimitry Andric } else if (!stateSourceTooLong && stateSourceNotTooLong) { 16230b57cec5SDimitry Andric // The source buffer entirely fits in the bound. 16240b57cec5SDimitry Andric state = stateSourceNotTooLong; 16250b57cec5SDimitry Andric amountCopied = strLength; 16260b57cec5SDimitry Andric } 1627*480093f4SDimitry Andric break; 1628*480093f4SDimitry Andric } 1629*480093f4SDimitry Andric case ConcatFnKind::strlcat: 1630*480093f4SDimitry Andric if (!dstStrLengthNL) 1631*480093f4SDimitry Andric return; 1632*480093f4SDimitry Andric 1633*480093f4SDimitry Andric // amountCopied = min (size - dstLen - 1 , srcLen) 1634*480093f4SDimitry Andric SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, 1635*480093f4SDimitry Andric *dstStrLengthNL, sizeTy); 1636*480093f4SDimitry Andric if (!freeSpace.getAs<NonLoc>()) 1637*480093f4SDimitry Andric return; 1638*480093f4SDimitry Andric freeSpace = 1639*480093f4SDimitry Andric svalBuilder.evalBinOp(state, BO_Sub, freeSpace, 1640*480093f4SDimitry Andric svalBuilder.makeIntVal(1, sizeTy), sizeTy); 1641*480093f4SDimitry Andric Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>(); 1642*480093f4SDimitry Andric 1643*480093f4SDimitry Andric // While unlikely, it is possible that the subtraction is 1644*480093f4SDimitry Andric // too complex to compute, let's check whether it succeeded. 1645*480093f4SDimitry Andric if (!freeSpaceNL) 1646*480093f4SDimitry Andric return; 1647*480093f4SDimitry Andric SVal hasEnoughSpace = svalBuilder.evalBinOpNN( 1648*480093f4SDimitry Andric state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy); 1649*480093f4SDimitry Andric 1650*480093f4SDimitry Andric ProgramStateRef TrueState, FalseState; 1651*480093f4SDimitry Andric std::tie(TrueState, FalseState) = 1652*480093f4SDimitry Andric state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>()); 1653*480093f4SDimitry Andric 1654*480093f4SDimitry Andric // srcStrLength <= size - dstStrLength -1 1655*480093f4SDimitry Andric if (TrueState && !FalseState) { 1656*480093f4SDimitry Andric amountCopied = strLength; 16570b57cec5SDimitry Andric } 16580b57cec5SDimitry Andric 1659*480093f4SDimitry Andric // srcStrLength > size - dstStrLength -1 1660*480093f4SDimitry Andric if (!TrueState && FalseState) { 1661*480093f4SDimitry Andric amountCopied = freeSpace; 1662*480093f4SDimitry Andric } 1663*480093f4SDimitry Andric 1664*480093f4SDimitry Andric if (TrueState && FalseState) 1665*480093f4SDimitry Andric amountCopied = UnknownVal(); 1666*480093f4SDimitry Andric break; 1667*480093f4SDimitry Andric } 1668*480093f4SDimitry Andric } 16690b57cec5SDimitry Andric // We still want to know if the bound is known to be too large. 16700b57cec5SDimitry Andric if (lenValNL) { 1671*480093f4SDimitry Andric switch (appendK) { 1672*480093f4SDimitry Andric case ConcatFnKind::strcat: 16730b57cec5SDimitry Andric // For strncat, the check is strlen(dst) + lenVal < sizeof(dst) 16740b57cec5SDimitry Andric 16750b57cec5SDimitry Andric // Get the string length of the destination. If the destination is 16760b57cec5SDimitry Andric // memory that can't have a string length, we shouldn't be copying 16770b57cec5SDimitry Andric // into it anyway. 16780b57cec5SDimitry Andric if (dstStrLength.isUndef()) 16790b57cec5SDimitry Andric return; 16800b57cec5SDimitry Andric 1681*480093f4SDimitry Andric if (dstStrLengthNL) { 1682*480093f4SDimitry Andric maxLastElementIndex = svalBuilder.evalBinOpNN( 1683*480093f4SDimitry Andric state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy); 1684*480093f4SDimitry Andric 16850b57cec5SDimitry Andric boundWarning = "Size argument is greater than the free space in the " 16860b57cec5SDimitry Andric "destination buffer"; 16870b57cec5SDimitry Andric } 1688*480093f4SDimitry Andric break; 1689*480093f4SDimitry Andric case ConcatFnKind::none: 1690*480093f4SDimitry Andric case ConcatFnKind::strlcat: 1691*480093f4SDimitry Andric // For strncpy and strlcat, this is just checking 1692*480093f4SDimitry Andric // that lenVal <= sizeof(dst). 16930b57cec5SDimitry Andric // (Yes, strncpy and strncat differ in how they treat termination. 16940b57cec5SDimitry Andric // strncat ALWAYS terminates, but strncpy doesn't.) 16950b57cec5SDimitry Andric 16960b57cec5SDimitry Andric // We need a special case for when the copy size is zero, in which 16970b57cec5SDimitry Andric // case strncpy will do no work at all. Our bounds check uses n-1 16980b57cec5SDimitry Andric // as the last element accessed, so n == 0 is problematic. 16990b57cec5SDimitry Andric ProgramStateRef StateZeroSize, StateNonZeroSize; 17000b57cec5SDimitry Andric std::tie(StateZeroSize, StateNonZeroSize) = 17010b57cec5SDimitry Andric assumeZero(C, state, *lenValNL, sizeTy); 17020b57cec5SDimitry Andric 17030b57cec5SDimitry Andric // If the size is known to be zero, we're done. 17040b57cec5SDimitry Andric if (StateZeroSize && !StateNonZeroSize) { 17050b57cec5SDimitry Andric if (returnPtr) { 17060b57cec5SDimitry Andric StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal); 17070b57cec5SDimitry Andric } else { 1708*480093f4SDimitry Andric if (appendK == ConcatFnKind::none) { 1709*480093f4SDimitry Andric // strlcpy returns strlen(src) 1710*480093f4SDimitry Andric StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength); 1711*480093f4SDimitry Andric } else { 1712*480093f4SDimitry Andric // strlcat returns strlen(src) + strlen(dst) 1713*480093f4SDimitry Andric SVal retSize = svalBuilder.evalBinOp( 1714*480093f4SDimitry Andric state, BO_Add, strLength, dstStrLength, sizeTy); 1715*480093f4SDimitry Andric StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize); 1716*480093f4SDimitry Andric } 17170b57cec5SDimitry Andric } 17180b57cec5SDimitry Andric C.addTransition(StateZeroSize); 17190b57cec5SDimitry Andric return; 17200b57cec5SDimitry Andric } 17210b57cec5SDimitry Andric 17220b57cec5SDimitry Andric // Otherwise, go ahead and figure out the last element we'll touch. 17230b57cec5SDimitry Andric // We don't record the non-zero assumption here because we can't 17240b57cec5SDimitry Andric // be sure. We won't warn on a possible zero. 17250b57cec5SDimitry Andric NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 1726*480093f4SDimitry Andric maxLastElementIndex = 1727*480093f4SDimitry Andric svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy); 17280b57cec5SDimitry Andric boundWarning = "Size argument is greater than the length of the " 17290b57cec5SDimitry Andric "destination buffer"; 1730*480093f4SDimitry Andric break; 17310b57cec5SDimitry Andric } 17320b57cec5SDimitry Andric } 17330b57cec5SDimitry Andric } else { 17340b57cec5SDimitry Andric // The function isn't bounded. The amount copied should match the length 17350b57cec5SDimitry Andric // of the source buffer. 17360b57cec5SDimitry Andric amountCopied = strLength; 17370b57cec5SDimitry Andric } 17380b57cec5SDimitry Andric 17390b57cec5SDimitry Andric assert(state); 17400b57cec5SDimitry Andric 17410b57cec5SDimitry Andric // This represents the number of characters copied into the destination 17420b57cec5SDimitry Andric // buffer. (It may not actually be the strlen if the destination buffer 17430b57cec5SDimitry Andric // is not terminated.) 17440b57cec5SDimitry Andric SVal finalStrLength = UnknownVal(); 1745*480093f4SDimitry Andric SVal strlRetVal = UnknownVal(); 1746*480093f4SDimitry Andric 1747*480093f4SDimitry Andric if (appendK == ConcatFnKind::none && !returnPtr) { 1748*480093f4SDimitry Andric // strlcpy returns the sizeof(src) 1749*480093f4SDimitry Andric strlRetVal = strLength; 1750*480093f4SDimitry Andric } 17510b57cec5SDimitry Andric 17520b57cec5SDimitry Andric // If this is an appending function (strcat, strncat...) then set the 17530b57cec5SDimitry Andric // string length to strlen(src) + strlen(dst) since the buffer will 17540b57cec5SDimitry Andric // ultimately contain both. 1755*480093f4SDimitry Andric if (appendK != ConcatFnKind::none) { 17560b57cec5SDimitry Andric // Get the string length of the destination. If the destination is memory 17570b57cec5SDimitry Andric // that can't have a string length, we shouldn't be copying into it anyway. 17580b57cec5SDimitry Andric if (dstStrLength.isUndef()) 17590b57cec5SDimitry Andric return; 17600b57cec5SDimitry Andric 1761*480093f4SDimitry Andric if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) { 1762*480093f4SDimitry Andric strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL, 1763*480093f4SDimitry Andric *dstStrLengthNL, sizeTy); 1764*480093f4SDimitry Andric } 1765*480093f4SDimitry Andric 1766*480093f4SDimitry Andric Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>(); 17670b57cec5SDimitry Andric 17680b57cec5SDimitry Andric // If we know both string lengths, we might know the final string length. 1769*480093f4SDimitry Andric if (amountCopiedNL && dstStrLengthNL) { 17700b57cec5SDimitry Andric // Make sure the two lengths together don't overflow a size_t. 1771*480093f4SDimitry Andric state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL); 17720b57cec5SDimitry Andric if (!state) 17730b57cec5SDimitry Andric return; 17740b57cec5SDimitry Andric 1775*480093f4SDimitry Andric finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL, 17760b57cec5SDimitry Andric *dstStrLengthNL, sizeTy); 17770b57cec5SDimitry Andric } 17780b57cec5SDimitry Andric 17790b57cec5SDimitry Andric // If we couldn't get a single value for the final string length, 17800b57cec5SDimitry Andric // we can at least bound it by the individual lengths. 17810b57cec5SDimitry Andric if (finalStrLength.isUnknown()) { 17820b57cec5SDimitry Andric // Try to get a "hypothetical" string length symbol, which we can later 17830b57cec5SDimitry Andric // set as a real value if that turns out to be the case. 17840b57cec5SDimitry Andric finalStrLength = getCStringLength(C, state, CE, DstVal, true); 17850b57cec5SDimitry Andric assert(!finalStrLength.isUndef()); 17860b57cec5SDimitry Andric 17870b57cec5SDimitry Andric if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) { 1788*480093f4SDimitry Andric if (amountCopiedNL && appendK == ConcatFnKind::none) { 1789*480093f4SDimitry Andric // we overwrite dst string with the src 17900b57cec5SDimitry Andric // finalStrLength >= srcStrLength 1791*480093f4SDimitry Andric SVal sourceInResult = svalBuilder.evalBinOpNN( 1792*480093f4SDimitry Andric state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy); 17930b57cec5SDimitry Andric state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(), 17940b57cec5SDimitry Andric true); 17950b57cec5SDimitry Andric if (!state) 17960b57cec5SDimitry Andric return; 17970b57cec5SDimitry Andric } 17980b57cec5SDimitry Andric 1799*480093f4SDimitry Andric if (dstStrLengthNL && appendK != ConcatFnKind::none) { 1800*480093f4SDimitry Andric // we extend the dst string with the src 18010b57cec5SDimitry Andric // finalStrLength >= dstStrLength 18020b57cec5SDimitry Andric SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE, 18030b57cec5SDimitry Andric *finalStrLengthNL, 18040b57cec5SDimitry Andric *dstStrLengthNL, 18050b57cec5SDimitry Andric cmpTy); 18060b57cec5SDimitry Andric state = 18070b57cec5SDimitry Andric state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true); 18080b57cec5SDimitry Andric if (!state) 18090b57cec5SDimitry Andric return; 18100b57cec5SDimitry Andric } 18110b57cec5SDimitry Andric } 18120b57cec5SDimitry Andric } 18130b57cec5SDimitry Andric 18140b57cec5SDimitry Andric } else { 18150b57cec5SDimitry Andric // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and 18160b57cec5SDimitry Andric // the final string length will match the input string length. 18170b57cec5SDimitry Andric finalStrLength = amountCopied; 18180b57cec5SDimitry Andric } 18190b57cec5SDimitry Andric 18200b57cec5SDimitry Andric SVal Result; 18210b57cec5SDimitry Andric 18220b57cec5SDimitry Andric if (returnPtr) { 18230b57cec5SDimitry Andric // The final result of the function will either be a pointer past the last 18240b57cec5SDimitry Andric // copied element, or a pointer to the start of the destination buffer. 1825*480093f4SDimitry Andric Result = (ReturnEnd ? UnknownVal() : DstVal); 18260b57cec5SDimitry Andric } else { 1827*480093f4SDimitry Andric if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none) 1828*480093f4SDimitry Andric //strlcpy, strlcat 1829*480093f4SDimitry Andric Result = strlRetVal; 1830*480093f4SDimitry Andric else 18310b57cec5SDimitry Andric Result = finalStrLength; 18320b57cec5SDimitry Andric } 18330b57cec5SDimitry Andric 18340b57cec5SDimitry Andric assert(state); 18350b57cec5SDimitry Andric 18360b57cec5SDimitry Andric // If the destination is a MemRegion, try to check for a buffer overflow and 18370b57cec5SDimitry Andric // record the new string length. 18380b57cec5SDimitry Andric if (Optional<loc::MemRegionVal> dstRegVal = 18390b57cec5SDimitry Andric DstVal.getAs<loc::MemRegionVal>()) { 18400b57cec5SDimitry Andric QualType ptrTy = Dst->getType(); 18410b57cec5SDimitry Andric 18420b57cec5SDimitry Andric // If we have an exact value on a bounded copy, use that to check for 18430b57cec5SDimitry Andric // overflows, rather than our estimate about how much is actually copied. 18440b57cec5SDimitry Andric if (boundWarning) { 18450b57cec5SDimitry Andric if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) { 18460b57cec5SDimitry Andric SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, 18470b57cec5SDimitry Andric *maxLastNL, ptrTy); 18480b57cec5SDimitry Andric state = CheckLocation(C, state, CE->getArg(2), maxLastElement, 18490b57cec5SDimitry Andric boundWarning); 18500b57cec5SDimitry Andric if (!state) 18510b57cec5SDimitry Andric return; 18520b57cec5SDimitry Andric } 18530b57cec5SDimitry Andric } 18540b57cec5SDimitry Andric 18550b57cec5SDimitry Andric // Then, if the final length is known... 18560b57cec5SDimitry Andric if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) { 18570b57cec5SDimitry Andric SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, 18580b57cec5SDimitry Andric *knownStrLength, ptrTy); 18590b57cec5SDimitry Andric 18600b57cec5SDimitry Andric // ...and we haven't checked the bound, we'll check the actual copy. 18610b57cec5SDimitry Andric if (!boundWarning) { 18620b57cec5SDimitry Andric const char * const warningMsg = 18630b57cec5SDimitry Andric "String copy function overflows destination buffer"; 18640b57cec5SDimitry Andric state = CheckLocation(C, state, Dst, lastElement, warningMsg); 18650b57cec5SDimitry Andric if (!state) 18660b57cec5SDimitry Andric return; 18670b57cec5SDimitry Andric } 18680b57cec5SDimitry Andric 18690b57cec5SDimitry Andric // If this is a stpcpy-style copy, the last element is the return value. 1870*480093f4SDimitry Andric if (returnPtr && ReturnEnd) 18710b57cec5SDimitry Andric Result = lastElement; 18720b57cec5SDimitry Andric } 18730b57cec5SDimitry Andric 18740b57cec5SDimitry Andric // Invalidate the destination (regular invalidation without pointer-escaping 18750b57cec5SDimitry Andric // the address of the top-level region). This must happen before we set the 18760b57cec5SDimitry Andric // C string length because invalidation will clear the length. 18770b57cec5SDimitry Andric // FIXME: Even if we can't perfectly model the copy, we should see if we 18780b57cec5SDimitry Andric // can use LazyCompoundVals to copy the source values into the destination. 18790b57cec5SDimitry Andric // This would probably remove any existing bindings past the end of the 18800b57cec5SDimitry Andric // string, but that's still an improvement over blank invalidation. 18810b57cec5SDimitry Andric state = InvalidateBuffer(C, state, Dst, *dstRegVal, 18820b57cec5SDimitry Andric /*IsSourceBuffer*/false, nullptr); 18830b57cec5SDimitry Andric 18840b57cec5SDimitry Andric // Invalidate the source (const-invalidation without const-pointer-escaping 18850b57cec5SDimitry Andric // the address of the top-level region). 18860b57cec5SDimitry Andric state = InvalidateBuffer(C, state, srcExpr, srcVal, /*IsSourceBuffer*/true, 18870b57cec5SDimitry Andric nullptr); 18880b57cec5SDimitry Andric 18890b57cec5SDimitry Andric // Set the C string length of the destination, if we know it. 1890*480093f4SDimitry Andric if (IsBounded && (appendK == ConcatFnKind::none)) { 18910b57cec5SDimitry Andric // strncpy is annoying in that it doesn't guarantee to null-terminate 18920b57cec5SDimitry Andric // the result string. If the original string didn't fit entirely inside 18930b57cec5SDimitry Andric // the bound (including the null-terminator), we don't know how long the 18940b57cec5SDimitry Andric // result is. 18950b57cec5SDimitry Andric if (amountCopied != strLength) 18960b57cec5SDimitry Andric finalStrLength = UnknownVal(); 18970b57cec5SDimitry Andric } 18980b57cec5SDimitry Andric state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength); 18990b57cec5SDimitry Andric } 19000b57cec5SDimitry Andric 19010b57cec5SDimitry Andric assert(state); 19020b57cec5SDimitry Andric 19030b57cec5SDimitry Andric if (returnPtr) { 19040b57cec5SDimitry Andric // If this is a stpcpy-style copy, but we were unable to check for a buffer 19050b57cec5SDimitry Andric // overflow, we still need a result. Conjure a return value. 1906*480093f4SDimitry Andric if (ReturnEnd && Result.isUnknown()) { 19070b57cec5SDimitry Andric Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 19080b57cec5SDimitry Andric } 19090b57cec5SDimitry Andric } 19100b57cec5SDimitry Andric // Set the return value. 19110b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, Result); 19120b57cec5SDimitry Andric C.addTransition(state); 19130b57cec5SDimitry Andric } 19140b57cec5SDimitry Andric 19150b57cec5SDimitry Andric void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { 19160b57cec5SDimitry Andric //int strcmp(const char *s1, const char *s2); 1917*480093f4SDimitry Andric evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ false); 19180b57cec5SDimitry Andric } 19190b57cec5SDimitry Andric 19200b57cec5SDimitry Andric void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { 19210b57cec5SDimitry Andric //int strncmp(const char *s1, const char *s2, size_t n); 1922*480093f4SDimitry Andric evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ false); 19230b57cec5SDimitry Andric } 19240b57cec5SDimitry Andric 19250b57cec5SDimitry Andric void CStringChecker::evalStrcasecmp(CheckerContext &C, 19260b57cec5SDimitry Andric const CallExpr *CE) const { 19270b57cec5SDimitry Andric //int strcasecmp(const char *s1, const char *s2); 1928*480093f4SDimitry Andric evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ true); 19290b57cec5SDimitry Andric } 19300b57cec5SDimitry Andric 19310b57cec5SDimitry Andric void CStringChecker::evalStrncasecmp(CheckerContext &C, 19320b57cec5SDimitry Andric const CallExpr *CE) const { 19330b57cec5SDimitry Andric //int strncasecmp(const char *s1, const char *s2, size_t n); 1934*480093f4SDimitry Andric evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ true); 19350b57cec5SDimitry Andric } 19360b57cec5SDimitry Andric 19370b57cec5SDimitry Andric void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, 1938*480093f4SDimitry Andric bool IsBounded, bool IgnoreCase) const { 19390b57cec5SDimitry Andric CurrentFunctionDescription = "string comparison function"; 19400b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 19410b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 19420b57cec5SDimitry Andric 19430b57cec5SDimitry Andric // Check that the first string is non-null 19440b57cec5SDimitry Andric const Expr *s1 = CE->getArg(0); 19450b57cec5SDimitry Andric SVal s1Val = state->getSVal(s1, LCtx); 1946a7dea167SDimitry Andric state = checkNonNull(C, state, s1, s1Val, 1); 19470b57cec5SDimitry Andric if (!state) 19480b57cec5SDimitry Andric return; 19490b57cec5SDimitry Andric 19500b57cec5SDimitry Andric // Check that the second string is non-null. 19510b57cec5SDimitry Andric const Expr *s2 = CE->getArg(1); 19520b57cec5SDimitry Andric SVal s2Val = state->getSVal(s2, LCtx); 1953a7dea167SDimitry Andric state = checkNonNull(C, state, s2, s2Val, 2); 19540b57cec5SDimitry Andric if (!state) 19550b57cec5SDimitry Andric return; 19560b57cec5SDimitry Andric 19570b57cec5SDimitry Andric // Get the string length of the first string or give up. 19580b57cec5SDimitry Andric SVal s1Length = getCStringLength(C, state, s1, s1Val); 19590b57cec5SDimitry Andric if (s1Length.isUndef()) 19600b57cec5SDimitry Andric return; 19610b57cec5SDimitry Andric 19620b57cec5SDimitry Andric // Get the string length of the second string or give up. 19630b57cec5SDimitry Andric SVal s2Length = getCStringLength(C, state, s2, s2Val); 19640b57cec5SDimitry Andric if (s2Length.isUndef()) 19650b57cec5SDimitry Andric return; 19660b57cec5SDimitry Andric 19670b57cec5SDimitry Andric // If we know the two buffers are the same, we know the result is 0. 19680b57cec5SDimitry Andric // First, get the two buffers' addresses. Another checker will have already 19690b57cec5SDimitry Andric // made sure they're not undefined. 19700b57cec5SDimitry Andric DefinedOrUnknownSVal LV = s1Val.castAs<DefinedOrUnknownSVal>(); 19710b57cec5SDimitry Andric DefinedOrUnknownSVal RV = s2Val.castAs<DefinedOrUnknownSVal>(); 19720b57cec5SDimitry Andric 19730b57cec5SDimitry Andric // See if they are the same. 19740b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 19750b57cec5SDimitry Andric DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); 19760b57cec5SDimitry Andric ProgramStateRef StSameBuf, StNotSameBuf; 19770b57cec5SDimitry Andric std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); 19780b57cec5SDimitry Andric 19790b57cec5SDimitry Andric // If the two arguments might be the same buffer, we know the result is 0, 19800b57cec5SDimitry Andric // and we only need to check one size. 19810b57cec5SDimitry Andric if (StSameBuf) { 19820b57cec5SDimitry Andric StSameBuf = StSameBuf->BindExpr(CE, LCtx, 19830b57cec5SDimitry Andric svalBuilder.makeZeroVal(CE->getType())); 19840b57cec5SDimitry Andric C.addTransition(StSameBuf); 19850b57cec5SDimitry Andric 19860b57cec5SDimitry Andric // If the two arguments are GUARANTEED to be the same, we're done! 19870b57cec5SDimitry Andric if (!StNotSameBuf) 19880b57cec5SDimitry Andric return; 19890b57cec5SDimitry Andric } 19900b57cec5SDimitry Andric 19910b57cec5SDimitry Andric assert(StNotSameBuf); 19920b57cec5SDimitry Andric state = StNotSameBuf; 19930b57cec5SDimitry Andric 19940b57cec5SDimitry Andric // At this point we can go about comparing the two buffers. 19950b57cec5SDimitry Andric // For now, we only do this if they're both known string literals. 19960b57cec5SDimitry Andric 19970b57cec5SDimitry Andric // Attempt to extract string literals from both expressions. 19980b57cec5SDimitry Andric const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val); 19990b57cec5SDimitry Andric const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val); 20000b57cec5SDimitry Andric bool canComputeResult = false; 20010b57cec5SDimitry Andric SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, 20020b57cec5SDimitry Andric C.blockCount()); 20030b57cec5SDimitry Andric 20040b57cec5SDimitry Andric if (s1StrLiteral && s2StrLiteral) { 20050b57cec5SDimitry Andric StringRef s1StrRef = s1StrLiteral->getString(); 20060b57cec5SDimitry Andric StringRef s2StrRef = s2StrLiteral->getString(); 20070b57cec5SDimitry Andric 2008*480093f4SDimitry Andric if (IsBounded) { 20090b57cec5SDimitry Andric // Get the max number of characters to compare. 20100b57cec5SDimitry Andric const Expr *lenExpr = CE->getArg(2); 20110b57cec5SDimitry Andric SVal lenVal = state->getSVal(lenExpr, LCtx); 20120b57cec5SDimitry Andric 20130b57cec5SDimitry Andric // If the length is known, we can get the right substrings. 20140b57cec5SDimitry Andric if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) { 20150b57cec5SDimitry Andric // Create substrings of each to compare the prefix. 20160b57cec5SDimitry Andric s1StrRef = s1StrRef.substr(0, (size_t)len->getZExtValue()); 20170b57cec5SDimitry Andric s2StrRef = s2StrRef.substr(0, (size_t)len->getZExtValue()); 20180b57cec5SDimitry Andric canComputeResult = true; 20190b57cec5SDimitry Andric } 20200b57cec5SDimitry Andric } else { 20210b57cec5SDimitry Andric // This is a normal, unbounded strcmp. 20220b57cec5SDimitry Andric canComputeResult = true; 20230b57cec5SDimitry Andric } 20240b57cec5SDimitry Andric 20250b57cec5SDimitry Andric if (canComputeResult) { 20260b57cec5SDimitry Andric // Real strcmp stops at null characters. 20270b57cec5SDimitry Andric size_t s1Term = s1StrRef.find('\0'); 20280b57cec5SDimitry Andric if (s1Term != StringRef::npos) 20290b57cec5SDimitry Andric s1StrRef = s1StrRef.substr(0, s1Term); 20300b57cec5SDimitry Andric 20310b57cec5SDimitry Andric size_t s2Term = s2StrRef.find('\0'); 20320b57cec5SDimitry Andric if (s2Term != StringRef::npos) 20330b57cec5SDimitry Andric s2StrRef = s2StrRef.substr(0, s2Term); 20340b57cec5SDimitry Andric 20350b57cec5SDimitry Andric // Use StringRef's comparison methods to compute the actual result. 2036*480093f4SDimitry Andric int compareRes = IgnoreCase ? s1StrRef.compare_lower(s2StrRef) 20370b57cec5SDimitry Andric : s1StrRef.compare(s2StrRef); 20380b57cec5SDimitry Andric 20390b57cec5SDimitry Andric // The strcmp function returns an integer greater than, equal to, or less 20400b57cec5SDimitry Andric // than zero, [c11, p7.24.4.2]. 20410b57cec5SDimitry Andric if (compareRes == 0) { 20420b57cec5SDimitry Andric resultVal = svalBuilder.makeIntVal(compareRes, CE->getType()); 20430b57cec5SDimitry Andric } 20440b57cec5SDimitry Andric else { 20450b57cec5SDimitry Andric DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType()); 20460b57cec5SDimitry Andric // Constrain strcmp's result range based on the result of StringRef's 20470b57cec5SDimitry Andric // comparison methods. 20480b57cec5SDimitry Andric BinaryOperatorKind op = (compareRes == 1) ? BO_GT : BO_LT; 20490b57cec5SDimitry Andric SVal compareWithZero = 20500b57cec5SDimitry Andric svalBuilder.evalBinOp(state, op, resultVal, zeroVal, 20510b57cec5SDimitry Andric svalBuilder.getConditionType()); 20520b57cec5SDimitry Andric DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>(); 20530b57cec5SDimitry Andric state = state->assume(compareWithZeroVal, true); 20540b57cec5SDimitry Andric } 20550b57cec5SDimitry Andric } 20560b57cec5SDimitry Andric } 20570b57cec5SDimitry Andric 20580b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, resultVal); 20590b57cec5SDimitry Andric 20600b57cec5SDimitry Andric // Record this as a possible path. 20610b57cec5SDimitry Andric C.addTransition(state); 20620b57cec5SDimitry Andric } 20630b57cec5SDimitry Andric 20640b57cec5SDimitry Andric void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { 20650b57cec5SDimitry Andric //char *strsep(char **stringp, const char *delim); 20660b57cec5SDimitry Andric // Sanity: does the search string parameter match the return type? 20670b57cec5SDimitry Andric const Expr *SearchStrPtr = CE->getArg(0); 20680b57cec5SDimitry Andric QualType CharPtrTy = SearchStrPtr->getType()->getPointeeType(); 20690b57cec5SDimitry Andric if (CharPtrTy.isNull() || 20700b57cec5SDimitry Andric CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType()) 20710b57cec5SDimitry Andric return; 20720b57cec5SDimitry Andric 20730b57cec5SDimitry Andric CurrentFunctionDescription = "strsep()"; 20740b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 20750b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 20760b57cec5SDimitry Andric 20770b57cec5SDimitry Andric // Check that the search string pointer is non-null (though it may point to 20780b57cec5SDimitry Andric // a null string). 20790b57cec5SDimitry Andric SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx); 2080a7dea167SDimitry Andric State = checkNonNull(C, State, SearchStrPtr, SearchStrVal, 1); 20810b57cec5SDimitry Andric if (!State) 20820b57cec5SDimitry Andric return; 20830b57cec5SDimitry Andric 20840b57cec5SDimitry Andric // Check that the delimiter string is non-null. 20850b57cec5SDimitry Andric const Expr *DelimStr = CE->getArg(1); 20860b57cec5SDimitry Andric SVal DelimStrVal = State->getSVal(DelimStr, LCtx); 2087a7dea167SDimitry Andric State = checkNonNull(C, State, DelimStr, DelimStrVal, 2); 20880b57cec5SDimitry Andric if (!State) 20890b57cec5SDimitry Andric return; 20900b57cec5SDimitry Andric 20910b57cec5SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 20920b57cec5SDimitry Andric SVal Result; 20930b57cec5SDimitry Andric if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) { 20940b57cec5SDimitry Andric // Get the current value of the search string pointer, as a char*. 20950b57cec5SDimitry Andric Result = State->getSVal(*SearchStrLoc, CharPtrTy); 20960b57cec5SDimitry Andric 20970b57cec5SDimitry Andric // Invalidate the search string, representing the change of one delimiter 20980b57cec5SDimitry Andric // character to NUL. 20990b57cec5SDimitry Andric State = InvalidateBuffer(C, State, SearchStrPtr, Result, 21000b57cec5SDimitry Andric /*IsSourceBuffer*/false, nullptr); 21010b57cec5SDimitry Andric 21020b57cec5SDimitry Andric // Overwrite the search string pointer. The new value is either an address 21030b57cec5SDimitry Andric // further along in the same string, or NULL if there are no more tokens. 21040b57cec5SDimitry Andric State = State->bindLoc(*SearchStrLoc, 21050b57cec5SDimitry Andric SVB.conjureSymbolVal(getTag(), 21060b57cec5SDimitry Andric CE, 21070b57cec5SDimitry Andric LCtx, 21080b57cec5SDimitry Andric CharPtrTy, 21090b57cec5SDimitry Andric C.blockCount()), 21100b57cec5SDimitry Andric LCtx); 21110b57cec5SDimitry Andric } else { 21120b57cec5SDimitry Andric assert(SearchStrVal.isUnknown()); 21130b57cec5SDimitry Andric // Conjure a symbolic value. It's the best we can do. 21140b57cec5SDimitry Andric Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 21150b57cec5SDimitry Andric } 21160b57cec5SDimitry Andric 21170b57cec5SDimitry Andric // Set the return value, and finish. 21180b57cec5SDimitry Andric State = State->BindExpr(CE, LCtx, Result); 21190b57cec5SDimitry Andric C.addTransition(State); 21200b57cec5SDimitry Andric } 21210b57cec5SDimitry Andric 21220b57cec5SDimitry Andric // These should probably be moved into a C++ standard library checker. 21230b57cec5SDimitry Andric void CStringChecker::evalStdCopy(CheckerContext &C, const CallExpr *CE) const { 21240b57cec5SDimitry Andric evalStdCopyCommon(C, CE); 21250b57cec5SDimitry Andric } 21260b57cec5SDimitry Andric 21270b57cec5SDimitry Andric void CStringChecker::evalStdCopyBackward(CheckerContext &C, 21280b57cec5SDimitry Andric const CallExpr *CE) const { 21290b57cec5SDimitry Andric evalStdCopyCommon(C, CE); 21300b57cec5SDimitry Andric } 21310b57cec5SDimitry Andric 21320b57cec5SDimitry Andric void CStringChecker::evalStdCopyCommon(CheckerContext &C, 21330b57cec5SDimitry Andric const CallExpr *CE) const { 21340b57cec5SDimitry Andric if (!CE->getArg(2)->getType()->isPointerType()) 21350b57cec5SDimitry Andric return; 21360b57cec5SDimitry Andric 21370b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 21380b57cec5SDimitry Andric 21390b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 21400b57cec5SDimitry Andric 21410b57cec5SDimitry Andric // template <class _InputIterator, class _OutputIterator> 21420b57cec5SDimitry Andric // _OutputIterator 21430b57cec5SDimitry Andric // copy(_InputIterator __first, _InputIterator __last, 21440b57cec5SDimitry Andric // _OutputIterator __result) 21450b57cec5SDimitry Andric 21460b57cec5SDimitry Andric // Invalidate the destination buffer 21470b57cec5SDimitry Andric const Expr *Dst = CE->getArg(2); 21480b57cec5SDimitry Andric SVal DstVal = State->getSVal(Dst, LCtx); 21490b57cec5SDimitry Andric State = InvalidateBuffer(C, State, Dst, DstVal, /*IsSource=*/false, 21500b57cec5SDimitry Andric /*Size=*/nullptr); 21510b57cec5SDimitry Andric 21520b57cec5SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 21530b57cec5SDimitry Andric 21540b57cec5SDimitry Andric SVal ResultVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 21550b57cec5SDimitry Andric State = State->BindExpr(CE, LCtx, ResultVal); 21560b57cec5SDimitry Andric 21570b57cec5SDimitry Andric C.addTransition(State); 21580b57cec5SDimitry Andric } 21590b57cec5SDimitry Andric 21600b57cec5SDimitry Andric void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const { 21610b57cec5SDimitry Andric CurrentFunctionDescription = "memory set function"; 21620b57cec5SDimitry Andric 21630b57cec5SDimitry Andric const Expr *Mem = CE->getArg(0); 21640b57cec5SDimitry Andric const Expr *CharE = CE->getArg(1); 21650b57cec5SDimitry Andric const Expr *Size = CE->getArg(2); 21660b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 21670b57cec5SDimitry Andric 21680b57cec5SDimitry Andric // See if the size argument is zero. 21690b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 21700b57cec5SDimitry Andric SVal SizeVal = State->getSVal(Size, LCtx); 21710b57cec5SDimitry Andric QualType SizeTy = Size->getType(); 21720b57cec5SDimitry Andric 21730b57cec5SDimitry Andric ProgramStateRef StateZeroSize, StateNonZeroSize; 21740b57cec5SDimitry Andric std::tie(StateZeroSize, StateNonZeroSize) = 21750b57cec5SDimitry Andric assumeZero(C, State, SizeVal, SizeTy); 21760b57cec5SDimitry Andric 21770b57cec5SDimitry Andric // Get the value of the memory area. 21780b57cec5SDimitry Andric SVal MemVal = State->getSVal(Mem, LCtx); 21790b57cec5SDimitry Andric 21800b57cec5SDimitry Andric // If the size is zero, there won't be any actual memory access, so 21810b57cec5SDimitry Andric // just bind the return value to the Mem buffer and return. 21820b57cec5SDimitry Andric if (StateZeroSize && !StateNonZeroSize) { 21830b57cec5SDimitry Andric StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal); 21840b57cec5SDimitry Andric C.addTransition(StateZeroSize); 21850b57cec5SDimitry Andric return; 21860b57cec5SDimitry Andric } 21870b57cec5SDimitry Andric 21880b57cec5SDimitry Andric // Ensure the memory area is not null. 21890b57cec5SDimitry Andric // If it is NULL there will be a NULL pointer dereference. 2190a7dea167SDimitry Andric State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1); 21910b57cec5SDimitry Andric if (!State) 21920b57cec5SDimitry Andric return; 21930b57cec5SDimitry Andric 21940b57cec5SDimitry Andric State = CheckBufferAccess(C, State, Size, Mem); 21950b57cec5SDimitry Andric if (!State) 21960b57cec5SDimitry Andric return; 21970b57cec5SDimitry Andric 21980b57cec5SDimitry Andric // According to the values of the arguments, bind the value of the second 21990b57cec5SDimitry Andric // argument to the destination buffer and set string length, or just 22000b57cec5SDimitry Andric // invalidate the destination buffer. 22010b57cec5SDimitry Andric if (!memsetAux(Mem, C.getSVal(CharE), Size, C, State)) 22020b57cec5SDimitry Andric return; 22030b57cec5SDimitry Andric 22040b57cec5SDimitry Andric State = State->BindExpr(CE, LCtx, MemVal); 22050b57cec5SDimitry Andric C.addTransition(State); 22060b57cec5SDimitry Andric } 22070b57cec5SDimitry Andric 22080b57cec5SDimitry Andric void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const { 22090b57cec5SDimitry Andric CurrentFunctionDescription = "memory clearance function"; 22100b57cec5SDimitry Andric 22110b57cec5SDimitry Andric const Expr *Mem = CE->getArg(0); 22120b57cec5SDimitry Andric const Expr *Size = CE->getArg(1); 22130b57cec5SDimitry Andric SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy); 22140b57cec5SDimitry Andric 22150b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 22160b57cec5SDimitry Andric 22170b57cec5SDimitry Andric // See if the size argument is zero. 22180b57cec5SDimitry Andric SVal SizeVal = C.getSVal(Size); 22190b57cec5SDimitry Andric QualType SizeTy = Size->getType(); 22200b57cec5SDimitry Andric 22210b57cec5SDimitry Andric ProgramStateRef StateZeroSize, StateNonZeroSize; 22220b57cec5SDimitry Andric std::tie(StateZeroSize, StateNonZeroSize) = 22230b57cec5SDimitry Andric assumeZero(C, State, SizeVal, SizeTy); 22240b57cec5SDimitry Andric 22250b57cec5SDimitry Andric // If the size is zero, there won't be any actual memory access, 22260b57cec5SDimitry Andric // In this case we just return. 22270b57cec5SDimitry Andric if (StateZeroSize && !StateNonZeroSize) { 22280b57cec5SDimitry Andric C.addTransition(StateZeroSize); 22290b57cec5SDimitry Andric return; 22300b57cec5SDimitry Andric } 22310b57cec5SDimitry Andric 22320b57cec5SDimitry Andric // Get the value of the memory area. 22330b57cec5SDimitry Andric SVal MemVal = C.getSVal(Mem); 22340b57cec5SDimitry Andric 22350b57cec5SDimitry Andric // Ensure the memory area is not null. 22360b57cec5SDimitry Andric // If it is NULL there will be a NULL pointer dereference. 2237a7dea167SDimitry Andric State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1); 22380b57cec5SDimitry Andric if (!State) 22390b57cec5SDimitry Andric return; 22400b57cec5SDimitry Andric 22410b57cec5SDimitry Andric State = CheckBufferAccess(C, State, Size, Mem); 22420b57cec5SDimitry Andric if (!State) 22430b57cec5SDimitry Andric return; 22440b57cec5SDimitry Andric 22450b57cec5SDimitry Andric if (!memsetAux(Mem, Zero, Size, C, State)) 22460b57cec5SDimitry Andric return; 22470b57cec5SDimitry Andric 22480b57cec5SDimitry Andric C.addTransition(State); 22490b57cec5SDimitry Andric } 22500b57cec5SDimitry Andric 22510b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 22520b57cec5SDimitry Andric // The driver method, and other Checker callbacks. 22530b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 22540b57cec5SDimitry Andric 22550b57cec5SDimitry Andric CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call, 22560b57cec5SDimitry Andric CheckerContext &C) const { 22570b57cec5SDimitry Andric const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 22580b57cec5SDimitry Andric if (!CE) 22590b57cec5SDimitry Andric return nullptr; 22600b57cec5SDimitry Andric 22610b57cec5SDimitry Andric const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 22620b57cec5SDimitry Andric if (!FD) 22630b57cec5SDimitry Andric return nullptr; 22640b57cec5SDimitry Andric 22650b57cec5SDimitry Andric if (Call.isCalled(StdCopy)) { 22660b57cec5SDimitry Andric return &CStringChecker::evalStdCopy; 22670b57cec5SDimitry Andric } else if (Call.isCalled(StdCopyBackward)) { 22680b57cec5SDimitry Andric return &CStringChecker::evalStdCopyBackward; 22690b57cec5SDimitry Andric } 22700b57cec5SDimitry Andric 22710b57cec5SDimitry Andric // Pro-actively check that argument types are safe to do arithmetic upon. 22720b57cec5SDimitry Andric // We do not want to crash if someone accidentally passes a structure 22730b57cec5SDimitry Andric // into, say, a C++ overload of any of these functions. We could not check 22740b57cec5SDimitry Andric // that for std::copy because they may have arguments of other types. 22750b57cec5SDimitry Andric for (auto I : CE->arguments()) { 22760b57cec5SDimitry Andric QualType T = I->getType(); 22770b57cec5SDimitry Andric if (!T->isIntegralOrEnumerationType() && !T->isPointerType()) 22780b57cec5SDimitry Andric return nullptr; 22790b57cec5SDimitry Andric } 22800b57cec5SDimitry Andric 22810b57cec5SDimitry Andric const FnCheck *Callback = Callbacks.lookup(Call); 22820b57cec5SDimitry Andric if (Callback) 22830b57cec5SDimitry Andric return *Callback; 22840b57cec5SDimitry Andric 22850b57cec5SDimitry Andric return nullptr; 22860b57cec5SDimitry Andric } 22870b57cec5SDimitry Andric 22880b57cec5SDimitry Andric bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { 22890b57cec5SDimitry Andric FnCheck Callback = identifyCall(Call, C); 22900b57cec5SDimitry Andric 22910b57cec5SDimitry Andric // If the callee isn't a string function, let another checker handle it. 22920b57cec5SDimitry Andric if (!Callback) 22930b57cec5SDimitry Andric return false; 22940b57cec5SDimitry Andric 22950b57cec5SDimitry Andric // Check and evaluate the call. 22960b57cec5SDimitry Andric const auto *CE = cast<CallExpr>(Call.getOriginExpr()); 22970b57cec5SDimitry Andric (this->*Callback)(C, CE); 22980b57cec5SDimitry Andric 22990b57cec5SDimitry Andric // If the evaluate call resulted in no change, chain to the next eval call 23000b57cec5SDimitry Andric // handler. 23010b57cec5SDimitry Andric // Note, the custom CString evaluation calls assume that basic safety 23020b57cec5SDimitry Andric // properties are held. However, if the user chooses to turn off some of these 23030b57cec5SDimitry Andric // checks, we ignore the issues and leave the call evaluation to a generic 23040b57cec5SDimitry Andric // handler. 23050b57cec5SDimitry Andric return C.isDifferent(); 23060b57cec5SDimitry Andric } 23070b57cec5SDimitry Andric 23080b57cec5SDimitry Andric void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 23090b57cec5SDimitry Andric // Record string length for char a[] = "abc"; 23100b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 23110b57cec5SDimitry Andric 23120b57cec5SDimitry Andric for (const auto *I : DS->decls()) { 23130b57cec5SDimitry Andric const VarDecl *D = dyn_cast<VarDecl>(I); 23140b57cec5SDimitry Andric if (!D) 23150b57cec5SDimitry Andric continue; 23160b57cec5SDimitry Andric 23170b57cec5SDimitry Andric // FIXME: Handle array fields of structs. 23180b57cec5SDimitry Andric if (!D->getType()->isArrayType()) 23190b57cec5SDimitry Andric continue; 23200b57cec5SDimitry Andric 23210b57cec5SDimitry Andric const Expr *Init = D->getInit(); 23220b57cec5SDimitry Andric if (!Init) 23230b57cec5SDimitry Andric continue; 23240b57cec5SDimitry Andric if (!isa<StringLiteral>(Init)) 23250b57cec5SDimitry Andric continue; 23260b57cec5SDimitry Andric 23270b57cec5SDimitry Andric Loc VarLoc = state->getLValue(D, C.getLocationContext()); 23280b57cec5SDimitry Andric const MemRegion *MR = VarLoc.getAsRegion(); 23290b57cec5SDimitry Andric if (!MR) 23300b57cec5SDimitry Andric continue; 23310b57cec5SDimitry Andric 23320b57cec5SDimitry Andric SVal StrVal = C.getSVal(Init); 23330b57cec5SDimitry Andric assert(StrVal.isValid() && "Initializer string is unknown or undefined"); 23340b57cec5SDimitry Andric DefinedOrUnknownSVal strLength = 23350b57cec5SDimitry Andric getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>(); 23360b57cec5SDimitry Andric 23370b57cec5SDimitry Andric state = state->set<CStringLength>(MR, strLength); 23380b57cec5SDimitry Andric } 23390b57cec5SDimitry Andric 23400b57cec5SDimitry Andric C.addTransition(state); 23410b57cec5SDimitry Andric } 23420b57cec5SDimitry Andric 23430b57cec5SDimitry Andric ProgramStateRef 23440b57cec5SDimitry Andric CStringChecker::checkRegionChanges(ProgramStateRef state, 23450b57cec5SDimitry Andric const InvalidatedSymbols *, 23460b57cec5SDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 23470b57cec5SDimitry Andric ArrayRef<const MemRegion *> Regions, 23480b57cec5SDimitry Andric const LocationContext *LCtx, 23490b57cec5SDimitry Andric const CallEvent *Call) const { 23500b57cec5SDimitry Andric CStringLengthTy Entries = state->get<CStringLength>(); 23510b57cec5SDimitry Andric if (Entries.isEmpty()) 23520b57cec5SDimitry Andric return state; 23530b57cec5SDimitry Andric 23540b57cec5SDimitry Andric llvm::SmallPtrSet<const MemRegion *, 8> Invalidated; 23550b57cec5SDimitry Andric llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions; 23560b57cec5SDimitry Andric 23570b57cec5SDimitry Andric // First build sets for the changed regions and their super-regions. 23580b57cec5SDimitry Andric for (ArrayRef<const MemRegion *>::iterator 23590b57cec5SDimitry Andric I = Regions.begin(), E = Regions.end(); I != E; ++I) { 23600b57cec5SDimitry Andric const MemRegion *MR = *I; 23610b57cec5SDimitry Andric Invalidated.insert(MR); 23620b57cec5SDimitry Andric 23630b57cec5SDimitry Andric SuperRegions.insert(MR); 23640b57cec5SDimitry Andric while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) { 23650b57cec5SDimitry Andric MR = SR->getSuperRegion(); 23660b57cec5SDimitry Andric SuperRegions.insert(MR); 23670b57cec5SDimitry Andric } 23680b57cec5SDimitry Andric } 23690b57cec5SDimitry Andric 23700b57cec5SDimitry Andric CStringLengthTy::Factory &F = state->get_context<CStringLength>(); 23710b57cec5SDimitry Andric 23720b57cec5SDimitry Andric // Then loop over the entries in the current state. 23730b57cec5SDimitry Andric for (CStringLengthTy::iterator I = Entries.begin(), 23740b57cec5SDimitry Andric E = Entries.end(); I != E; ++I) { 23750b57cec5SDimitry Andric const MemRegion *MR = I.getKey(); 23760b57cec5SDimitry Andric 23770b57cec5SDimitry Andric // Is this entry for a super-region of a changed region? 23780b57cec5SDimitry Andric if (SuperRegions.count(MR)) { 23790b57cec5SDimitry Andric Entries = F.remove(Entries, MR); 23800b57cec5SDimitry Andric continue; 23810b57cec5SDimitry Andric } 23820b57cec5SDimitry Andric 23830b57cec5SDimitry Andric // Is this entry for a sub-region of a changed region? 23840b57cec5SDimitry Andric const MemRegion *Super = MR; 23850b57cec5SDimitry Andric while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) { 23860b57cec5SDimitry Andric Super = SR->getSuperRegion(); 23870b57cec5SDimitry Andric if (Invalidated.count(Super)) { 23880b57cec5SDimitry Andric Entries = F.remove(Entries, MR); 23890b57cec5SDimitry Andric break; 23900b57cec5SDimitry Andric } 23910b57cec5SDimitry Andric } 23920b57cec5SDimitry Andric } 23930b57cec5SDimitry Andric 23940b57cec5SDimitry Andric return state->set<CStringLength>(Entries); 23950b57cec5SDimitry Andric } 23960b57cec5SDimitry Andric 23970b57cec5SDimitry Andric void CStringChecker::checkLiveSymbols(ProgramStateRef state, 23980b57cec5SDimitry Andric SymbolReaper &SR) const { 23990b57cec5SDimitry Andric // Mark all symbols in our string length map as valid. 24000b57cec5SDimitry Andric CStringLengthTy Entries = state->get<CStringLength>(); 24010b57cec5SDimitry Andric 24020b57cec5SDimitry Andric for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); 24030b57cec5SDimitry Andric I != E; ++I) { 24040b57cec5SDimitry Andric SVal Len = I.getData(); 24050b57cec5SDimitry Andric 24060b57cec5SDimitry Andric for (SymExpr::symbol_iterator si = Len.symbol_begin(), 24070b57cec5SDimitry Andric se = Len.symbol_end(); si != se; ++si) 24080b57cec5SDimitry Andric SR.markInUse(*si); 24090b57cec5SDimitry Andric } 24100b57cec5SDimitry Andric } 24110b57cec5SDimitry Andric 24120b57cec5SDimitry Andric void CStringChecker::checkDeadSymbols(SymbolReaper &SR, 24130b57cec5SDimitry Andric CheckerContext &C) const { 24140b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 24150b57cec5SDimitry Andric CStringLengthTy Entries = state->get<CStringLength>(); 24160b57cec5SDimitry Andric if (Entries.isEmpty()) 24170b57cec5SDimitry Andric return; 24180b57cec5SDimitry Andric 24190b57cec5SDimitry Andric CStringLengthTy::Factory &F = state->get_context<CStringLength>(); 24200b57cec5SDimitry Andric for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); 24210b57cec5SDimitry Andric I != E; ++I) { 24220b57cec5SDimitry Andric SVal Len = I.getData(); 24230b57cec5SDimitry Andric if (SymbolRef Sym = Len.getAsSymbol()) { 24240b57cec5SDimitry Andric if (SR.isDead(Sym)) 24250b57cec5SDimitry Andric Entries = F.remove(Entries, I.getKey()); 24260b57cec5SDimitry Andric } 24270b57cec5SDimitry Andric } 24280b57cec5SDimitry Andric 24290b57cec5SDimitry Andric state = state->set<CStringLength>(Entries); 24300b57cec5SDimitry Andric C.addTransition(state); 24310b57cec5SDimitry Andric } 24320b57cec5SDimitry Andric 24330b57cec5SDimitry Andric void ento::registerCStringModeling(CheckerManager &Mgr) { 24340b57cec5SDimitry Andric Mgr.registerChecker<CStringChecker>(); 24350b57cec5SDimitry Andric } 24360b57cec5SDimitry Andric 24370b57cec5SDimitry Andric bool ento::shouldRegisterCStringModeling(const LangOptions &LO) { 24380b57cec5SDimitry Andric return true; 24390b57cec5SDimitry Andric } 24400b57cec5SDimitry Andric 24410b57cec5SDimitry Andric #define REGISTER_CHECKER(name) \ 24420b57cec5SDimitry Andric void ento::register##name(CheckerManager &mgr) { \ 24430b57cec5SDimitry Andric CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ 24440b57cec5SDimitry Andric checker->Filter.Check##name = true; \ 2445a7dea167SDimitry Andric checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ 24460b57cec5SDimitry Andric } \ 24470b57cec5SDimitry Andric \ 2448a7dea167SDimitry Andric bool ento::shouldRegister##name(const LangOptions &LO) { return true; } 24490b57cec5SDimitry Andric 24500b57cec5SDimitry Andric REGISTER_CHECKER(CStringNullArg) 24510b57cec5SDimitry Andric REGISTER_CHECKER(CStringOutOfBounds) 24520b57cec5SDimitry Andric REGISTER_CHECKER(CStringBufferOverlap) 24530b57cec5SDimitry Andric REGISTER_CHECKER(CStringNotNullTerm) 2454