10b57cec5SDimitry Andric //= CStringChecker.cpp - Checks calls to C string functions --------*- C++ -*-// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This defines CStringChecker, which is an assortment of checks on calls 100b57cec5SDimitry Andric // to functions in <string.h>. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "InterCheckerAPI.h" 150b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h" 165ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.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" 22*fe6060f1SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicExtent.h" 230b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 240b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 250b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 265ffd83dbSDimitry Andric #include "llvm/ADT/StringExtras.h" 270b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace clang; 300b57cec5SDimitry Andric using namespace ento; 310b57cec5SDimitry Andric 320b57cec5SDimitry Andric namespace { 335ffd83dbSDimitry Andric struct AnyArgExpr { 345ffd83dbSDimitry Andric // FIXME: Remove constructor in C++17 to turn it into an aggregate. 355ffd83dbSDimitry Andric AnyArgExpr(const Expr *Expression, unsigned ArgumentIndex) 365ffd83dbSDimitry Andric : Expression{Expression}, ArgumentIndex{ArgumentIndex} {} 375ffd83dbSDimitry Andric const Expr *Expression; 385ffd83dbSDimitry Andric unsigned ArgumentIndex; 395ffd83dbSDimitry Andric }; 405ffd83dbSDimitry Andric 415ffd83dbSDimitry Andric struct SourceArgExpr : AnyArgExpr { 425ffd83dbSDimitry Andric using AnyArgExpr::AnyArgExpr; // FIXME: Remove using in C++17. 435ffd83dbSDimitry Andric }; 445ffd83dbSDimitry Andric 455ffd83dbSDimitry Andric struct DestinationArgExpr : AnyArgExpr { 465ffd83dbSDimitry Andric using AnyArgExpr::AnyArgExpr; // FIXME: Same. 475ffd83dbSDimitry Andric }; 485ffd83dbSDimitry Andric 495ffd83dbSDimitry Andric struct SizeArgExpr : AnyArgExpr { 505ffd83dbSDimitry Andric using AnyArgExpr::AnyArgExpr; // FIXME: Same. 515ffd83dbSDimitry Andric }; 525ffd83dbSDimitry Andric 535ffd83dbSDimitry Andric using ErrorMessage = SmallString<128>; 545ffd83dbSDimitry Andric enum class AccessKind { write, read }; 555ffd83dbSDimitry Andric 565ffd83dbSDimitry Andric static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription, 575ffd83dbSDimitry Andric AccessKind Access) { 585ffd83dbSDimitry Andric ErrorMessage Message; 595ffd83dbSDimitry Andric llvm::raw_svector_ostream Os(Message); 605ffd83dbSDimitry Andric 615ffd83dbSDimitry Andric // Function classification like: Memory copy function 625ffd83dbSDimitry Andric Os << toUppercase(FunctionDescription.front()) 635ffd83dbSDimitry Andric << &FunctionDescription.data()[1]; 645ffd83dbSDimitry Andric 655ffd83dbSDimitry Andric if (Access == AccessKind::write) { 665ffd83dbSDimitry Andric Os << " overflows the destination buffer"; 675ffd83dbSDimitry Andric } else { // read access 685ffd83dbSDimitry Andric Os << " accesses out-of-bound array element"; 695ffd83dbSDimitry Andric } 705ffd83dbSDimitry Andric 715ffd83dbSDimitry Andric return Message; 725ffd83dbSDimitry Andric } 735ffd83dbSDimitry Andric 74480093f4SDimitry Andric enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 }; 750b57cec5SDimitry Andric class CStringChecker : public Checker< eval::Call, 760b57cec5SDimitry Andric check::PreStmt<DeclStmt>, 770b57cec5SDimitry Andric check::LiveSymbols, 780b57cec5SDimitry Andric check::DeadSymbols, 790b57cec5SDimitry Andric check::RegionChanges 800b57cec5SDimitry Andric > { 810b57cec5SDimitry Andric mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap, 820b57cec5SDimitry Andric BT_NotCString, BT_AdditionOverflow; 830b57cec5SDimitry Andric 840b57cec5SDimitry Andric mutable const char *CurrentFunctionDescription; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric public: 870b57cec5SDimitry Andric /// The filter is used to filter out the diagnostics which are not enabled by 880b57cec5SDimitry Andric /// the user. 890b57cec5SDimitry Andric struct CStringChecksFilter { 900b57cec5SDimitry Andric DefaultBool CheckCStringNullArg; 910b57cec5SDimitry Andric DefaultBool CheckCStringOutOfBounds; 920b57cec5SDimitry Andric DefaultBool CheckCStringBufferOverlap; 930b57cec5SDimitry Andric DefaultBool CheckCStringNotNullTerm; 940b57cec5SDimitry Andric 95a7dea167SDimitry Andric CheckerNameRef CheckNameCStringNullArg; 96a7dea167SDimitry Andric CheckerNameRef CheckNameCStringOutOfBounds; 97a7dea167SDimitry Andric CheckerNameRef CheckNameCStringBufferOverlap; 98a7dea167SDimitry Andric CheckerNameRef CheckNameCStringNotNullTerm; 990b57cec5SDimitry Andric }; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric CStringChecksFilter Filter; 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric static void *getTag() { static int tag; return &tag; } 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric bool evalCall(const CallEvent &Call, CheckerContext &C) const; 1060b57cec5SDimitry Andric void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 1070b57cec5SDimitry Andric void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const; 1080b57cec5SDimitry Andric void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric ProgramStateRef 1110b57cec5SDimitry Andric checkRegionChanges(ProgramStateRef state, 1120b57cec5SDimitry Andric const InvalidatedSymbols *, 1130b57cec5SDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 1140b57cec5SDimitry Andric ArrayRef<const MemRegion *> Regions, 1150b57cec5SDimitry Andric const LocationContext *LCtx, 1160b57cec5SDimitry Andric const CallEvent *Call) const; 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric typedef void (CStringChecker::*FnCheck)(CheckerContext &, 1190b57cec5SDimitry Andric const CallExpr *) const; 1200b57cec5SDimitry Andric CallDescriptionMap<FnCheck> Callbacks = { 1210b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy}, 1220b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy}, 1230b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp}, 1240b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove}, 1250b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset}, 1260b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "explicit_memset", 3}, &CStringChecker::evalMemset}, 1270b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy}, 1280b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy}, 1290b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy}, 1300b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy}, 1310b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat}, 1320b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat}, 1330b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat}, 1340b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength}, 1350b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength}, 1360b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp}, 1370b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp}, 1380b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp}, 1390b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strncasecmp", 3}, &CStringChecker::evalStrncasecmp}, 1400b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep}, 1410b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy}, 1420b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "bcmp", 3}, &CStringChecker::evalMemcmp}, 1430b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero}, 1440b57cec5SDimitry Andric {{CDF_MaybeBuiltin, "explicit_bzero", 2}, &CStringChecker::evalBzero}, 1450b57cec5SDimitry Andric }; 1460b57cec5SDimitry Andric 1470b57cec5SDimitry Andric // These require a bit of special handling. 1480b57cec5SDimitry Andric CallDescription StdCopy{{"std", "copy"}, 3}, 1490b57cec5SDimitry Andric StdCopyBackward{{"std", "copy_backward"}, 3}; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const; 1520b57cec5SDimitry Andric void evalMemcpy(CheckerContext &C, const CallExpr *CE) const; 1530b57cec5SDimitry Andric void evalMempcpy(CheckerContext &C, const CallExpr *CE) const; 1540b57cec5SDimitry Andric void evalMemmove(CheckerContext &C, const CallExpr *CE) const; 1550b57cec5SDimitry Andric void evalBcopy(CheckerContext &C, const CallExpr *CE) const; 1560b57cec5SDimitry Andric void evalCopyCommon(CheckerContext &C, const CallExpr *CE, 1575ffd83dbSDimitry Andric ProgramStateRef state, SizeArgExpr Size, 1585ffd83dbSDimitry Andric DestinationArgExpr Dest, SourceArgExpr Source, 1595ffd83dbSDimitry Andric bool Restricted, bool IsMempcpy) const; 1600b57cec5SDimitry Andric 1610b57cec5SDimitry Andric void evalMemcmp(CheckerContext &C, const CallExpr *CE) const; 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric void evalstrLength(CheckerContext &C, const CallExpr *CE) const; 1640b57cec5SDimitry Andric void evalstrnLength(CheckerContext &C, const CallExpr *CE) const; 1650b57cec5SDimitry Andric void evalstrLengthCommon(CheckerContext &C, 1660b57cec5SDimitry Andric const CallExpr *CE, 1670b57cec5SDimitry Andric bool IsStrnlen = false) const; 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; 1700b57cec5SDimitry Andric void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; 1710b57cec5SDimitry Andric void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; 1720b57cec5SDimitry Andric void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const; 173480093f4SDimitry Andric void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd, 174480093f4SDimitry Andric bool IsBounded, ConcatFnKind appendK, 1750b57cec5SDimitry Andric bool returnPtr = true) const; 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric void evalStrcat(CheckerContext &C, const CallExpr *CE) const; 1780b57cec5SDimitry Andric void evalStrncat(CheckerContext &C, const CallExpr *CE) const; 1790b57cec5SDimitry Andric void evalStrlcat(CheckerContext &C, const CallExpr *CE) const; 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; 1820b57cec5SDimitry Andric void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; 1830b57cec5SDimitry Andric void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; 1840b57cec5SDimitry Andric void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; 1850b57cec5SDimitry Andric void evalStrcmpCommon(CheckerContext &C, 1860b57cec5SDimitry Andric const CallExpr *CE, 187480093f4SDimitry Andric bool IsBounded = false, 188480093f4SDimitry Andric bool IgnoreCase = false) const; 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric void evalStrsep(CheckerContext &C, const CallExpr *CE) const; 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric void evalStdCopy(CheckerContext &C, const CallExpr *CE) const; 1930b57cec5SDimitry Andric void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const; 1940b57cec5SDimitry Andric void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const; 1950b57cec5SDimitry Andric void evalMemset(CheckerContext &C, const CallExpr *CE) const; 1960b57cec5SDimitry Andric void evalBzero(CheckerContext &C, const CallExpr *CE) const; 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric // Utility methods 1990b57cec5SDimitry Andric std::pair<ProgramStateRef , ProgramStateRef > 2000b57cec5SDimitry Andric static assumeZero(CheckerContext &C, 2010b57cec5SDimitry Andric ProgramStateRef state, SVal V, QualType Ty); 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric static ProgramStateRef setCStringLength(ProgramStateRef state, 2040b57cec5SDimitry Andric const MemRegion *MR, 2050b57cec5SDimitry Andric SVal strLength); 2060b57cec5SDimitry Andric static SVal getCStringLengthForRegion(CheckerContext &C, 2070b57cec5SDimitry Andric ProgramStateRef &state, 2080b57cec5SDimitry Andric const Expr *Ex, 2090b57cec5SDimitry Andric const MemRegion *MR, 2100b57cec5SDimitry Andric bool hypothetical); 2110b57cec5SDimitry Andric SVal getCStringLength(CheckerContext &C, 2120b57cec5SDimitry Andric ProgramStateRef &state, 2130b57cec5SDimitry Andric const Expr *Ex, 2140b57cec5SDimitry Andric SVal Buf, 2150b57cec5SDimitry Andric bool hypothetical = false) const; 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric const StringLiteral *getCStringLiteral(CheckerContext &C, 2180b57cec5SDimitry Andric ProgramStateRef &state, 2190b57cec5SDimitry Andric const Expr *expr, 2200b57cec5SDimitry Andric SVal val) const; 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric static ProgramStateRef InvalidateBuffer(CheckerContext &C, 2230b57cec5SDimitry Andric ProgramStateRef state, 2240b57cec5SDimitry Andric const Expr *Ex, SVal V, 2250b57cec5SDimitry Andric bool IsSourceBuffer, 2260b57cec5SDimitry Andric const Expr *Size); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, 2290b57cec5SDimitry Andric const MemRegion *MR); 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric static bool memsetAux(const Expr *DstBuffer, SVal CharE, 2320b57cec5SDimitry Andric const Expr *Size, CheckerContext &C, 2330b57cec5SDimitry Andric ProgramStateRef &State); 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric // Re-usable checks 2365ffd83dbSDimitry Andric ProgramStateRef checkNonNull(CheckerContext &C, ProgramStateRef State, 2375ffd83dbSDimitry Andric AnyArgExpr Arg, SVal l) const; 2385ffd83dbSDimitry Andric ProgramStateRef CheckLocation(CheckerContext &C, ProgramStateRef state, 2395ffd83dbSDimitry Andric AnyArgExpr Buffer, SVal Element, 2405ffd83dbSDimitry Andric AccessKind Access) const; 2415ffd83dbSDimitry Andric ProgramStateRef CheckBufferAccess(CheckerContext &C, ProgramStateRef State, 2425ffd83dbSDimitry Andric AnyArgExpr Buffer, SizeArgExpr Size, 2435ffd83dbSDimitry Andric AccessKind Access) const; 2445ffd83dbSDimitry Andric ProgramStateRef CheckOverlap(CheckerContext &C, ProgramStateRef state, 2455ffd83dbSDimitry Andric SizeArgExpr Size, AnyArgExpr First, 2465ffd83dbSDimitry Andric AnyArgExpr Second) const; 2470b57cec5SDimitry Andric void emitOverlapBug(CheckerContext &C, 2480b57cec5SDimitry Andric ProgramStateRef state, 2490b57cec5SDimitry Andric const Stmt *First, 2500b57cec5SDimitry Andric const Stmt *Second) const; 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric void emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, 2530b57cec5SDimitry Andric StringRef WarningMsg) const; 2540b57cec5SDimitry Andric void emitOutOfBoundsBug(CheckerContext &C, ProgramStateRef State, 2550b57cec5SDimitry Andric const Stmt *S, StringRef WarningMsg) const; 2560b57cec5SDimitry Andric void emitNotCStringBug(CheckerContext &C, ProgramStateRef State, 2570b57cec5SDimitry Andric const Stmt *S, StringRef WarningMsg) const; 2580b57cec5SDimitry Andric void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const; 2590b57cec5SDimitry Andric 2600b57cec5SDimitry Andric ProgramStateRef checkAdditionOverflow(CheckerContext &C, 2610b57cec5SDimitry Andric ProgramStateRef state, 2620b57cec5SDimitry Andric NonLoc left, 2630b57cec5SDimitry Andric NonLoc right) const; 2640b57cec5SDimitry Andric 2650b57cec5SDimitry Andric // Return true if the destination buffer of the copy function may be in bound. 2660b57cec5SDimitry Andric // Expects SVal of Size to be positive and unsigned. 2670b57cec5SDimitry Andric // Expects SVal of FirstBuf to be a FieldRegion. 2680b57cec5SDimitry Andric static bool IsFirstBufInBound(CheckerContext &C, 2690b57cec5SDimitry Andric ProgramStateRef state, 2700b57cec5SDimitry Andric const Expr *FirstBuf, 2710b57cec5SDimitry Andric const Expr *Size); 2720b57cec5SDimitry Andric }; 2730b57cec5SDimitry Andric 2740b57cec5SDimitry Andric } //end anonymous namespace 2750b57cec5SDimitry Andric 2760b57cec5SDimitry Andric REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal) 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2790b57cec5SDimitry Andric // Individual checks and utility methods. 2800b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric std::pair<ProgramStateRef , ProgramStateRef > 2830b57cec5SDimitry Andric CStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V, 2840b57cec5SDimitry Andric QualType Ty) { 2850b57cec5SDimitry Andric Optional<DefinedSVal> val = V.getAs<DefinedSVal>(); 2860b57cec5SDimitry Andric if (!val) 2870b57cec5SDimitry Andric return std::pair<ProgramStateRef , ProgramStateRef >(state, state); 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 2900b57cec5SDimitry Andric DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty); 2910b57cec5SDimitry Andric return state->assume(svalBuilder.evalEQ(state, *val, zero)); 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, 2955ffd83dbSDimitry Andric ProgramStateRef State, 2965ffd83dbSDimitry Andric AnyArgExpr Arg, SVal l) const { 2970b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 2985ffd83dbSDimitry Andric if (!State) 2990b57cec5SDimitry Andric return nullptr; 3000b57cec5SDimitry Andric 3010b57cec5SDimitry Andric ProgramStateRef stateNull, stateNonNull; 3025ffd83dbSDimitry Andric std::tie(stateNull, stateNonNull) = 3035ffd83dbSDimitry Andric assumeZero(C, State, l, Arg.Expression->getType()); 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric if (stateNull && !stateNonNull) { 3060b57cec5SDimitry Andric if (Filter.CheckCStringNullArg) { 3070b57cec5SDimitry Andric SmallString<80> buf; 308a7dea167SDimitry Andric llvm::raw_svector_ostream OS(buf); 3090b57cec5SDimitry Andric assert(CurrentFunctionDescription); 3105ffd83dbSDimitry Andric OS << "Null pointer passed as " << (Arg.ArgumentIndex + 1) 3115ffd83dbSDimitry Andric << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) << " argument to " 312480093f4SDimitry Andric << CurrentFunctionDescription; 3130b57cec5SDimitry Andric 3145ffd83dbSDimitry Andric emitNullArgBug(C, stateNull, Arg.Expression, OS.str()); 3150b57cec5SDimitry Andric } 3160b57cec5SDimitry Andric return nullptr; 3170b57cec5SDimitry Andric } 3180b57cec5SDimitry Andric 3190b57cec5SDimitry Andric // From here on, assume that the value is non-null. 3200b57cec5SDimitry Andric assert(stateNonNull); 3210b57cec5SDimitry Andric return stateNonNull; 3220b57cec5SDimitry Andric } 3230b57cec5SDimitry Andric 3240b57cec5SDimitry Andric // FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor? 3250b57cec5SDimitry Andric ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, 3260b57cec5SDimitry Andric ProgramStateRef state, 3275ffd83dbSDimitry Andric AnyArgExpr Buffer, SVal Element, 3285ffd83dbSDimitry Andric AccessKind Access) const { 3295ffd83dbSDimitry Andric 3300b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 3310b57cec5SDimitry Andric if (!state) 3320b57cec5SDimitry Andric return nullptr; 3330b57cec5SDimitry Andric 3340b57cec5SDimitry Andric // Check for out of bound array element access. 3355ffd83dbSDimitry Andric const MemRegion *R = Element.getAsRegion(); 3360b57cec5SDimitry Andric if (!R) 3370b57cec5SDimitry Andric return state; 3380b57cec5SDimitry Andric 3395ffd83dbSDimitry Andric const auto *ER = dyn_cast<ElementRegion>(R); 3400b57cec5SDimitry Andric if (!ER) 3410b57cec5SDimitry Andric return state; 3420b57cec5SDimitry Andric 3430b57cec5SDimitry Andric if (ER->getValueType() != C.getASTContext().CharTy) 3440b57cec5SDimitry Andric return state; 3450b57cec5SDimitry Andric 3460b57cec5SDimitry Andric // Get the size of the array. 3475ffd83dbSDimitry Andric const auto *superReg = cast<SubRegion>(ER->getSuperRegion()); 3485ffd83dbSDimitry Andric DefinedOrUnknownSVal Size = 349*fe6060f1SDimitry Andric getDynamicExtent(state, superReg, C.getSValBuilder()); 3500b57cec5SDimitry Andric 3510b57cec5SDimitry Andric // Get the index of the accessed element. 3520b57cec5SDimitry Andric DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 3530b57cec5SDimitry Andric 3540b57cec5SDimitry Andric ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true); 3550b57cec5SDimitry Andric ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false); 3560b57cec5SDimitry Andric if (StOutBound && !StInBound) { 3570b57cec5SDimitry Andric // These checks are either enabled by the CString out-of-bounds checker 3580b57cec5SDimitry Andric // explicitly or implicitly by the Malloc checker. 3590b57cec5SDimitry Andric // In the latter case we only do modeling but do not emit warning. 3600b57cec5SDimitry Andric if (!Filter.CheckCStringOutOfBounds) 3610b57cec5SDimitry Andric return nullptr; 3620b57cec5SDimitry Andric 3635ffd83dbSDimitry Andric // Emit a bug report. 3645ffd83dbSDimitry Andric ErrorMessage Message = 3655ffd83dbSDimitry Andric createOutOfBoundErrorMsg(CurrentFunctionDescription, Access); 3665ffd83dbSDimitry Andric emitOutOfBoundsBug(C, StOutBound, Buffer.Expression, Message); 3670b57cec5SDimitry Andric return nullptr; 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric // Array bound check succeeded. From this point forward the array bound 3710b57cec5SDimitry Andric // should always succeed. 3720b57cec5SDimitry Andric return StInBound; 3730b57cec5SDimitry Andric } 3740b57cec5SDimitry Andric 3750b57cec5SDimitry Andric ProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, 3765ffd83dbSDimitry Andric ProgramStateRef State, 3775ffd83dbSDimitry Andric AnyArgExpr Buffer, 3785ffd83dbSDimitry Andric SizeArgExpr Size, 3795ffd83dbSDimitry Andric AccessKind Access) const { 3800b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 3815ffd83dbSDimitry Andric if (!State) 3820b57cec5SDimitry Andric return nullptr; 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 3850b57cec5SDimitry Andric ASTContext &Ctx = svalBuilder.getContext(); 3860b57cec5SDimitry Andric 3875ffd83dbSDimitry Andric QualType SizeTy = Size.Expression->getType(); 3880b57cec5SDimitry Andric QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); 3890b57cec5SDimitry Andric 3900b57cec5SDimitry Andric // Check that the first buffer is non-null. 3915ffd83dbSDimitry Andric SVal BufVal = C.getSVal(Buffer.Expression); 3925ffd83dbSDimitry Andric State = checkNonNull(C, State, Buffer, BufVal); 3935ffd83dbSDimitry Andric if (!State) 3940b57cec5SDimitry Andric return nullptr; 3950b57cec5SDimitry Andric 3960b57cec5SDimitry Andric // If out-of-bounds checking is turned off, skip the rest. 3970b57cec5SDimitry Andric if (!Filter.CheckCStringOutOfBounds) 3985ffd83dbSDimitry Andric return State; 3990b57cec5SDimitry Andric 4000b57cec5SDimitry Andric // Get the access length and make sure it is known. 4010b57cec5SDimitry Andric // FIXME: This assumes the caller has already checked that the access length 4020b57cec5SDimitry Andric // is positive. And that it's unsigned. 4035ffd83dbSDimitry Andric SVal LengthVal = C.getSVal(Size.Expression); 4040b57cec5SDimitry Andric Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 4050b57cec5SDimitry Andric if (!Length) 4065ffd83dbSDimitry Andric return State; 4070b57cec5SDimitry Andric 4080b57cec5SDimitry Andric // Compute the offset of the last element to be accessed: size-1. 4095ffd83dbSDimitry Andric NonLoc One = svalBuilder.makeIntVal(1, SizeTy).castAs<NonLoc>(); 4105ffd83dbSDimitry Andric SVal Offset = svalBuilder.evalBinOpNN(State, BO_Sub, *Length, One, SizeTy); 4110b57cec5SDimitry Andric if (Offset.isUnknown()) 4120b57cec5SDimitry Andric return nullptr; 4130b57cec5SDimitry Andric NonLoc LastOffset = Offset.castAs<NonLoc>(); 4140b57cec5SDimitry Andric 4150b57cec5SDimitry Andric // Check that the first buffer is sufficiently long. 4165ffd83dbSDimitry Andric SVal BufStart = 4175ffd83dbSDimitry Andric svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType()); 4180b57cec5SDimitry Andric if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { 4190b57cec5SDimitry Andric 4205ffd83dbSDimitry Andric SVal BufEnd = 4215ffd83dbSDimitry Andric svalBuilder.evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy); 4225ffd83dbSDimitry Andric 4235ffd83dbSDimitry Andric State = CheckLocation(C, State, Buffer, BufEnd, Access); 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric // If the buffer isn't large enough, abort. 4265ffd83dbSDimitry Andric if (!State) 4270b57cec5SDimitry Andric return nullptr; 4280b57cec5SDimitry Andric } 4290b57cec5SDimitry Andric 4300b57cec5SDimitry Andric // Large enough or not, return this state! 4315ffd83dbSDimitry Andric return State; 4320b57cec5SDimitry Andric } 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric ProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, 4350b57cec5SDimitry Andric ProgramStateRef state, 4365ffd83dbSDimitry Andric SizeArgExpr Size, AnyArgExpr First, 4375ffd83dbSDimitry Andric AnyArgExpr Second) const { 4380b57cec5SDimitry Andric if (!Filter.CheckCStringBufferOverlap) 4390b57cec5SDimitry Andric return state; 4400b57cec5SDimitry Andric 4410b57cec5SDimitry Andric // Do a simple check for overlap: if the two arguments are from the same 4420b57cec5SDimitry Andric // buffer, see if the end of the first is greater than the start of the second 4430b57cec5SDimitry Andric // or vice versa. 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 4460b57cec5SDimitry Andric if (!state) 4470b57cec5SDimitry Andric return nullptr; 4480b57cec5SDimitry Andric 4490b57cec5SDimitry Andric ProgramStateRef stateTrue, stateFalse; 4500b57cec5SDimitry Andric 4510b57cec5SDimitry Andric // Get the buffer values and make sure they're known locations. 4520b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 4535ffd83dbSDimitry Andric SVal firstVal = state->getSVal(First.Expression, LCtx); 4545ffd83dbSDimitry Andric SVal secondVal = state->getSVal(Second.Expression, LCtx); 4550b57cec5SDimitry Andric 4560b57cec5SDimitry Andric Optional<Loc> firstLoc = firstVal.getAs<Loc>(); 4570b57cec5SDimitry Andric if (!firstLoc) 4580b57cec5SDimitry Andric return state; 4590b57cec5SDimitry Andric 4600b57cec5SDimitry Andric Optional<Loc> secondLoc = secondVal.getAs<Loc>(); 4610b57cec5SDimitry Andric if (!secondLoc) 4620b57cec5SDimitry Andric return state; 4630b57cec5SDimitry Andric 4640b57cec5SDimitry Andric // Are the two values the same? 4650b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 4660b57cec5SDimitry Andric std::tie(stateTrue, stateFalse) = 4670b57cec5SDimitry Andric state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc)); 4680b57cec5SDimitry Andric 4690b57cec5SDimitry Andric if (stateTrue && !stateFalse) { 4700b57cec5SDimitry Andric // If the values are known to be equal, that's automatically an overlap. 4715ffd83dbSDimitry Andric emitOverlapBug(C, stateTrue, First.Expression, Second.Expression); 4720b57cec5SDimitry Andric return nullptr; 4730b57cec5SDimitry Andric } 4740b57cec5SDimitry Andric 4750b57cec5SDimitry Andric // assume the two expressions are not equal. 4760b57cec5SDimitry Andric assert(stateFalse); 4770b57cec5SDimitry Andric state = stateFalse; 4780b57cec5SDimitry Andric 4790b57cec5SDimitry Andric // Which value comes first? 4800b57cec5SDimitry Andric QualType cmpTy = svalBuilder.getConditionType(); 4815ffd83dbSDimitry Andric SVal reverse = 4825ffd83dbSDimitry Andric svalBuilder.evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy); 4830b57cec5SDimitry Andric Optional<DefinedOrUnknownSVal> reverseTest = 4840b57cec5SDimitry Andric reverse.getAs<DefinedOrUnknownSVal>(); 4850b57cec5SDimitry Andric if (!reverseTest) 4860b57cec5SDimitry Andric return state; 4870b57cec5SDimitry Andric 4880b57cec5SDimitry Andric std::tie(stateTrue, stateFalse) = state->assume(*reverseTest); 4890b57cec5SDimitry Andric if (stateTrue) { 4900b57cec5SDimitry Andric if (stateFalse) { 4910b57cec5SDimitry Andric // If we don't know which one comes first, we can't perform this test. 4920b57cec5SDimitry Andric return state; 4930b57cec5SDimitry Andric } else { 4940b57cec5SDimitry Andric // Switch the values so that firstVal is before secondVal. 4950b57cec5SDimitry Andric std::swap(firstLoc, secondLoc); 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric // Switch the Exprs as well, so that they still correspond. 4980b57cec5SDimitry Andric std::swap(First, Second); 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric } 5010b57cec5SDimitry Andric 5020b57cec5SDimitry Andric // Get the length, and make sure it too is known. 5035ffd83dbSDimitry Andric SVal LengthVal = state->getSVal(Size.Expression, LCtx); 5040b57cec5SDimitry Andric Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 5050b57cec5SDimitry Andric if (!Length) 5060b57cec5SDimitry Andric return state; 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric // Convert the first buffer's start address to char*. 5090b57cec5SDimitry Andric // Bail out if the cast fails. 5100b57cec5SDimitry Andric ASTContext &Ctx = svalBuilder.getContext(); 5110b57cec5SDimitry Andric QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); 5125ffd83dbSDimitry Andric SVal FirstStart = 5135ffd83dbSDimitry Andric svalBuilder.evalCast(*firstLoc, CharPtrTy, First.Expression->getType()); 5140b57cec5SDimitry Andric Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>(); 5150b57cec5SDimitry Andric if (!FirstStartLoc) 5160b57cec5SDimitry Andric return state; 5170b57cec5SDimitry Andric 5180b57cec5SDimitry Andric // Compute the end of the first buffer. Bail out if THAT fails. 5195ffd83dbSDimitry Andric SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, *FirstStartLoc, 5205ffd83dbSDimitry Andric *Length, CharPtrTy); 5210b57cec5SDimitry Andric Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>(); 5220b57cec5SDimitry Andric if (!FirstEndLoc) 5230b57cec5SDimitry Andric return state; 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric // Is the end of the first buffer past the start of the second buffer? 5265ffd83dbSDimitry Andric SVal Overlap = 5275ffd83dbSDimitry Andric svalBuilder.evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy); 5280b57cec5SDimitry Andric Optional<DefinedOrUnknownSVal> OverlapTest = 5290b57cec5SDimitry Andric Overlap.getAs<DefinedOrUnknownSVal>(); 5300b57cec5SDimitry Andric if (!OverlapTest) 5310b57cec5SDimitry Andric return state; 5320b57cec5SDimitry Andric 5330b57cec5SDimitry Andric std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest); 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric if (stateTrue && !stateFalse) { 5360b57cec5SDimitry Andric // Overlap! 5375ffd83dbSDimitry Andric emitOverlapBug(C, stateTrue, First.Expression, Second.Expression); 5380b57cec5SDimitry Andric return nullptr; 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric // assume the two expressions don't overlap. 5420b57cec5SDimitry Andric assert(stateFalse); 5430b57cec5SDimitry Andric return stateFalse; 5440b57cec5SDimitry Andric } 5450b57cec5SDimitry Andric 5460b57cec5SDimitry Andric void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, 5470b57cec5SDimitry Andric const Stmt *First, const Stmt *Second) const { 5480b57cec5SDimitry Andric ExplodedNode *N = C.generateErrorNode(state); 5490b57cec5SDimitry Andric if (!N) 5500b57cec5SDimitry Andric return; 5510b57cec5SDimitry Andric 5520b57cec5SDimitry Andric if (!BT_Overlap) 5530b57cec5SDimitry Andric BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap, 5540b57cec5SDimitry Andric categories::UnixAPI, "Improper arguments")); 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric // Generate a report for this bug. 557a7dea167SDimitry Andric auto report = std::make_unique<PathSensitiveBugReport>( 5580b57cec5SDimitry Andric *BT_Overlap, "Arguments must not be overlapping buffers", N); 5590b57cec5SDimitry Andric report->addRange(First->getSourceRange()); 5600b57cec5SDimitry Andric report->addRange(Second->getSourceRange()); 5610b57cec5SDimitry Andric 5620b57cec5SDimitry Andric C.emitReport(std::move(report)); 5630b57cec5SDimitry Andric } 5640b57cec5SDimitry Andric 5650b57cec5SDimitry Andric void CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State, 5660b57cec5SDimitry Andric const Stmt *S, StringRef WarningMsg) const { 5670b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode(State)) { 5680b57cec5SDimitry Andric if (!BT_Null) 5690b57cec5SDimitry Andric BT_Null.reset(new BuiltinBug( 5700b57cec5SDimitry Andric Filter.CheckNameCStringNullArg, categories::UnixAPI, 5710b57cec5SDimitry Andric "Null pointer argument in call to byte string function")); 5720b57cec5SDimitry Andric 5730b57cec5SDimitry Andric BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get()); 574a7dea167SDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); 5750b57cec5SDimitry Andric Report->addRange(S->getSourceRange()); 5760b57cec5SDimitry Andric if (const auto *Ex = dyn_cast<Expr>(S)) 5770b57cec5SDimitry Andric bugreporter::trackExpressionValue(N, Ex, *Report); 5780b57cec5SDimitry Andric C.emitReport(std::move(Report)); 5790b57cec5SDimitry Andric } 5800b57cec5SDimitry Andric } 5810b57cec5SDimitry Andric 5820b57cec5SDimitry Andric void CStringChecker::emitOutOfBoundsBug(CheckerContext &C, 5830b57cec5SDimitry Andric ProgramStateRef State, const Stmt *S, 5840b57cec5SDimitry Andric StringRef WarningMsg) const { 5850b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode(State)) { 5860b57cec5SDimitry Andric if (!BT_Bounds) 5870b57cec5SDimitry Andric BT_Bounds.reset(new BuiltinBug( 5880b57cec5SDimitry Andric Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds 5890b57cec5SDimitry Andric : Filter.CheckNameCStringNullArg, 5900b57cec5SDimitry Andric "Out-of-bound array access", 5910b57cec5SDimitry Andric "Byte string function accesses out-of-bound array element")); 5920b57cec5SDimitry Andric 5930b57cec5SDimitry Andric BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Bounds.get()); 5940b57cec5SDimitry Andric 5950b57cec5SDimitry Andric // FIXME: It would be nice to eventually make this diagnostic more clear, 5960b57cec5SDimitry Andric // e.g., by referencing the original declaration or by saying *why* this 5970b57cec5SDimitry Andric // reference is outside the range. 598a7dea167SDimitry Andric auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); 5990b57cec5SDimitry Andric Report->addRange(S->getSourceRange()); 6000b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6010b57cec5SDimitry Andric } 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric 6040b57cec5SDimitry Andric void CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State, 6050b57cec5SDimitry Andric const Stmt *S, 6060b57cec5SDimitry Andric StringRef WarningMsg) const { 6070b57cec5SDimitry Andric if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { 6080b57cec5SDimitry Andric if (!BT_NotCString) 6090b57cec5SDimitry Andric BT_NotCString.reset(new BuiltinBug( 6100b57cec5SDimitry Andric Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, 6110b57cec5SDimitry Andric "Argument is not a null-terminated string.")); 6120b57cec5SDimitry Andric 613a7dea167SDimitry Andric auto Report = 614a7dea167SDimitry Andric std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); 6150b57cec5SDimitry Andric 6160b57cec5SDimitry Andric Report->addRange(S->getSourceRange()); 6170b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6180b57cec5SDimitry Andric } 6190b57cec5SDimitry Andric } 6200b57cec5SDimitry Andric 6210b57cec5SDimitry Andric void CStringChecker::emitAdditionOverflowBug(CheckerContext &C, 6220b57cec5SDimitry Andric ProgramStateRef State) const { 6230b57cec5SDimitry Andric if (ExplodedNode *N = C.generateErrorNode(State)) { 6240b57cec5SDimitry Andric if (!BT_NotCString) 6250b57cec5SDimitry Andric BT_NotCString.reset( 6260b57cec5SDimitry Andric new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API", 6270b57cec5SDimitry Andric "Sum of expressions causes overflow.")); 6280b57cec5SDimitry Andric 6290b57cec5SDimitry Andric // This isn't a great error message, but this should never occur in real 6300b57cec5SDimitry Andric // code anyway -- you'd have to create a buffer longer than a size_t can 6310b57cec5SDimitry Andric // represent, which is sort of a contradiction. 6320b57cec5SDimitry Andric const char *WarningMsg = 6330b57cec5SDimitry Andric "This expression will create a string whose length is too big to " 6340b57cec5SDimitry Andric "be represented as a size_t"; 6350b57cec5SDimitry Andric 636a7dea167SDimitry Andric auto Report = 637a7dea167SDimitry Andric std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); 6380b57cec5SDimitry Andric C.emitReport(std::move(Report)); 6390b57cec5SDimitry Andric } 6400b57cec5SDimitry Andric } 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, 6430b57cec5SDimitry Andric ProgramStateRef state, 6440b57cec5SDimitry Andric NonLoc left, 6450b57cec5SDimitry Andric NonLoc right) const { 6460b57cec5SDimitry Andric // If out-of-bounds checking is turned off, skip the rest. 6470b57cec5SDimitry Andric if (!Filter.CheckCStringOutOfBounds) 6480b57cec5SDimitry Andric return state; 6490b57cec5SDimitry Andric 6500b57cec5SDimitry Andric // If a previous check has failed, propagate the failure. 6510b57cec5SDimitry Andric if (!state) 6520b57cec5SDimitry Andric return nullptr; 6530b57cec5SDimitry Andric 6540b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 6550b57cec5SDimitry Andric BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); 6560b57cec5SDimitry Andric 6570b57cec5SDimitry Andric QualType sizeTy = svalBuilder.getContext().getSizeType(); 6580b57cec5SDimitry Andric const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); 6590b57cec5SDimitry Andric NonLoc maxVal = svalBuilder.makeIntVal(maxValInt); 6600b57cec5SDimitry Andric 6610b57cec5SDimitry Andric SVal maxMinusRight; 6620b57cec5SDimitry Andric if (right.getAs<nonloc::ConcreteInt>()) { 6630b57cec5SDimitry Andric maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right, 6640b57cec5SDimitry Andric sizeTy); 6650b57cec5SDimitry Andric } else { 6660b57cec5SDimitry Andric // Try switching the operands. (The order of these two assignments is 6670b57cec5SDimitry Andric // important!) 6680b57cec5SDimitry Andric maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left, 6690b57cec5SDimitry Andric sizeTy); 6700b57cec5SDimitry Andric left = right; 6710b57cec5SDimitry Andric } 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) { 6740b57cec5SDimitry Andric QualType cmpTy = svalBuilder.getConditionType(); 6750b57cec5SDimitry Andric // If left > max - right, we have an overflow. 6760b57cec5SDimitry Andric SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left, 6770b57cec5SDimitry Andric *maxMinusRightNL, cmpTy); 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric ProgramStateRef stateOverflow, stateOkay; 6800b57cec5SDimitry Andric std::tie(stateOverflow, stateOkay) = 6810b57cec5SDimitry Andric state->assume(willOverflow.castAs<DefinedOrUnknownSVal>()); 6820b57cec5SDimitry Andric 6830b57cec5SDimitry Andric if (stateOverflow && !stateOkay) { 6840b57cec5SDimitry Andric // We have an overflow. Emit a bug report. 6850b57cec5SDimitry Andric emitAdditionOverflowBug(C, stateOverflow); 6860b57cec5SDimitry Andric return nullptr; 6870b57cec5SDimitry Andric } 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric // From now on, assume an overflow didn't occur. 6900b57cec5SDimitry Andric assert(stateOkay); 6910b57cec5SDimitry Andric state = stateOkay; 6920b57cec5SDimitry Andric } 6930b57cec5SDimitry Andric 6940b57cec5SDimitry Andric return state; 6950b57cec5SDimitry Andric } 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric ProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state, 6980b57cec5SDimitry Andric const MemRegion *MR, 6990b57cec5SDimitry Andric SVal strLength) { 7000b57cec5SDimitry Andric assert(!strLength.isUndef() && "Attempt to set an undefined string length"); 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric MR = MR->StripCasts(); 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric switch (MR->getKind()) { 7050b57cec5SDimitry Andric case MemRegion::StringRegionKind: 7060b57cec5SDimitry Andric // FIXME: This can happen if we strcpy() into a string region. This is 7070b57cec5SDimitry Andric // undefined [C99 6.4.5p6], but we should still warn about it. 7080b57cec5SDimitry Andric return state; 7090b57cec5SDimitry Andric 7100b57cec5SDimitry Andric case MemRegion::SymbolicRegionKind: 7110b57cec5SDimitry Andric case MemRegion::AllocaRegionKind: 7125ffd83dbSDimitry Andric case MemRegion::NonParamVarRegionKind: 7135ffd83dbSDimitry Andric case MemRegion::ParamVarRegionKind: 7140b57cec5SDimitry Andric case MemRegion::FieldRegionKind: 7150b57cec5SDimitry Andric case MemRegion::ObjCIvarRegionKind: 7160b57cec5SDimitry Andric // These are the types we can currently track string lengths for. 7170b57cec5SDimitry Andric break; 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric case MemRegion::ElementRegionKind: 7200b57cec5SDimitry Andric // FIXME: Handle element regions by upper-bounding the parent region's 7210b57cec5SDimitry Andric // string length. 7220b57cec5SDimitry Andric return state; 7230b57cec5SDimitry Andric 7240b57cec5SDimitry Andric default: 7250b57cec5SDimitry Andric // Other regions (mostly non-data) can't have a reliable C string length. 7260b57cec5SDimitry Andric // For now, just ignore the change. 7270b57cec5SDimitry Andric // FIXME: These are rare but not impossible. We should output some kind of 7280b57cec5SDimitry Andric // warning for things like strcpy((char[]){'a', 0}, "b"); 7290b57cec5SDimitry Andric return state; 7300b57cec5SDimitry Andric } 7310b57cec5SDimitry Andric 7320b57cec5SDimitry Andric if (strLength.isUnknown()) 7330b57cec5SDimitry Andric return state->remove<CStringLength>(MR); 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric return state->set<CStringLength>(MR, strLength); 7360b57cec5SDimitry Andric } 7370b57cec5SDimitry Andric 7380b57cec5SDimitry Andric SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, 7390b57cec5SDimitry Andric ProgramStateRef &state, 7400b57cec5SDimitry Andric const Expr *Ex, 7410b57cec5SDimitry Andric const MemRegion *MR, 7420b57cec5SDimitry Andric bool hypothetical) { 7430b57cec5SDimitry Andric if (!hypothetical) { 7440b57cec5SDimitry Andric // If there's a recorded length, go ahead and return it. 7450b57cec5SDimitry Andric const SVal *Recorded = state->get<CStringLength>(MR); 7460b57cec5SDimitry Andric if (Recorded) 7470b57cec5SDimitry Andric return *Recorded; 7480b57cec5SDimitry Andric } 7490b57cec5SDimitry Andric 7500b57cec5SDimitry Andric // Otherwise, get a new symbol and update the state. 7510b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 7520b57cec5SDimitry Andric QualType sizeTy = svalBuilder.getContext().getSizeType(); 7530b57cec5SDimitry Andric SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), 7540b57cec5SDimitry Andric MR, Ex, sizeTy, 7550b57cec5SDimitry Andric C.getLocationContext(), 7560b57cec5SDimitry Andric C.blockCount()); 7570b57cec5SDimitry Andric 7580b57cec5SDimitry Andric if (!hypothetical) { 7590b57cec5SDimitry Andric if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) { 7600b57cec5SDimitry Andric // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4 7610b57cec5SDimitry Andric BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); 7620b57cec5SDimitry Andric const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); 7630b57cec5SDimitry Andric llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4); 7640b57cec5SDimitry Andric const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt, 7650b57cec5SDimitry Andric fourInt); 7660b57cec5SDimitry Andric NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt); 7670b57cec5SDimitry Andric SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, 7680b57cec5SDimitry Andric maxLength, sizeTy); 7690b57cec5SDimitry Andric state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true); 7700b57cec5SDimitry Andric } 7710b57cec5SDimitry Andric state = state->set<CStringLength>(MR, strLength); 7720b57cec5SDimitry Andric } 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric return strLength; 7750b57cec5SDimitry Andric } 7760b57cec5SDimitry Andric 7770b57cec5SDimitry Andric SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, 7780b57cec5SDimitry Andric const Expr *Ex, SVal Buf, 7790b57cec5SDimitry Andric bool hypothetical) const { 7800b57cec5SDimitry Andric const MemRegion *MR = Buf.getAsRegion(); 7810b57cec5SDimitry Andric if (!MR) { 7820b57cec5SDimitry Andric // If we can't get a region, see if it's something we /know/ isn't a 7830b57cec5SDimitry Andric // C string. In the context of locations, the only time we can issue such 7840b57cec5SDimitry Andric // a warning is for labels. 7850b57cec5SDimitry Andric if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) { 7860b57cec5SDimitry Andric if (Filter.CheckCStringNotNullTerm) { 7870b57cec5SDimitry Andric SmallString<120> buf; 7880b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 7890b57cec5SDimitry Andric assert(CurrentFunctionDescription); 7900b57cec5SDimitry Andric os << "Argument to " << CurrentFunctionDescription 7910b57cec5SDimitry Andric << " is the address of the label '" << Label->getLabel()->getName() 7920b57cec5SDimitry Andric << "', which is not a null-terminated string"; 7930b57cec5SDimitry Andric 7940b57cec5SDimitry Andric emitNotCStringBug(C, state, Ex, os.str()); 7950b57cec5SDimitry Andric } 7960b57cec5SDimitry Andric return UndefinedVal(); 7970b57cec5SDimitry Andric } 7980b57cec5SDimitry Andric 7990b57cec5SDimitry Andric // If it's not a region and not a label, give up. 8000b57cec5SDimitry Andric return UnknownVal(); 8010b57cec5SDimitry Andric } 8020b57cec5SDimitry Andric 8030b57cec5SDimitry Andric // If we have a region, strip casts from it and see if we can figure out 8040b57cec5SDimitry Andric // its length. For anything we can't figure out, just return UnknownVal. 8050b57cec5SDimitry Andric MR = MR->StripCasts(); 8060b57cec5SDimitry Andric 8070b57cec5SDimitry Andric switch (MR->getKind()) { 8080b57cec5SDimitry Andric case MemRegion::StringRegionKind: { 8090b57cec5SDimitry Andric // Modifying the contents of string regions is undefined [C99 6.4.5p6], 8100b57cec5SDimitry Andric // so we can assume that the byte length is the correct C string length. 8110b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 8120b57cec5SDimitry Andric QualType sizeTy = svalBuilder.getContext().getSizeType(); 8130b57cec5SDimitry Andric const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral(); 8140b57cec5SDimitry Andric return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy); 8150b57cec5SDimitry Andric } 8160b57cec5SDimitry Andric case MemRegion::SymbolicRegionKind: 8170b57cec5SDimitry Andric case MemRegion::AllocaRegionKind: 8185ffd83dbSDimitry Andric case MemRegion::NonParamVarRegionKind: 8195ffd83dbSDimitry Andric case MemRegion::ParamVarRegionKind: 8200b57cec5SDimitry Andric case MemRegion::FieldRegionKind: 8210b57cec5SDimitry Andric case MemRegion::ObjCIvarRegionKind: 8220b57cec5SDimitry Andric return getCStringLengthForRegion(C, state, Ex, MR, hypothetical); 8230b57cec5SDimitry Andric case MemRegion::CompoundLiteralRegionKind: 8240b57cec5SDimitry Andric // FIXME: Can we track this? Is it necessary? 8250b57cec5SDimitry Andric return UnknownVal(); 8260b57cec5SDimitry Andric case MemRegion::ElementRegionKind: 8270b57cec5SDimitry Andric // FIXME: How can we handle this? It's not good enough to subtract the 8280b57cec5SDimitry Andric // offset from the base string length; consider "123\x00567" and &a[5]. 8290b57cec5SDimitry Andric return UnknownVal(); 8300b57cec5SDimitry Andric default: 8310b57cec5SDimitry Andric // Other regions (mostly non-data) can't have a reliable C string length. 8320b57cec5SDimitry Andric // In this case, an error is emitted and UndefinedVal is returned. 8330b57cec5SDimitry Andric // The caller should always be prepared to handle this case. 8340b57cec5SDimitry Andric if (Filter.CheckCStringNotNullTerm) { 8350b57cec5SDimitry Andric SmallString<120> buf; 8360b57cec5SDimitry Andric llvm::raw_svector_ostream os(buf); 8370b57cec5SDimitry Andric 8380b57cec5SDimitry Andric assert(CurrentFunctionDescription); 8390b57cec5SDimitry Andric os << "Argument to " << CurrentFunctionDescription << " is "; 8400b57cec5SDimitry Andric 8410b57cec5SDimitry Andric if (SummarizeRegion(os, C.getASTContext(), MR)) 8420b57cec5SDimitry Andric os << ", which is not a null-terminated string"; 8430b57cec5SDimitry Andric else 8440b57cec5SDimitry Andric os << "not a null-terminated string"; 8450b57cec5SDimitry Andric 8460b57cec5SDimitry Andric emitNotCStringBug(C, state, Ex, os.str()); 8470b57cec5SDimitry Andric } 8480b57cec5SDimitry Andric return UndefinedVal(); 8490b57cec5SDimitry Andric } 8500b57cec5SDimitry Andric } 8510b57cec5SDimitry Andric 8520b57cec5SDimitry Andric const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, 8530b57cec5SDimitry Andric ProgramStateRef &state, const Expr *expr, SVal val) const { 8540b57cec5SDimitry Andric 8550b57cec5SDimitry Andric // Get the memory region pointed to by the val. 8560b57cec5SDimitry Andric const MemRegion *bufRegion = val.getAsRegion(); 8570b57cec5SDimitry Andric if (!bufRegion) 8580b57cec5SDimitry Andric return nullptr; 8590b57cec5SDimitry Andric 8600b57cec5SDimitry Andric // Strip casts off the memory region. 8610b57cec5SDimitry Andric bufRegion = bufRegion->StripCasts(); 8620b57cec5SDimitry Andric 8630b57cec5SDimitry Andric // Cast the memory region to a string region. 8640b57cec5SDimitry Andric const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion); 8650b57cec5SDimitry Andric if (!strRegion) 8660b57cec5SDimitry Andric return nullptr; 8670b57cec5SDimitry Andric 8680b57cec5SDimitry Andric // Return the actual string in the string region. 8690b57cec5SDimitry Andric return strRegion->getStringLiteral(); 8700b57cec5SDimitry Andric } 8710b57cec5SDimitry Andric 8720b57cec5SDimitry Andric bool CStringChecker::IsFirstBufInBound(CheckerContext &C, 8730b57cec5SDimitry Andric ProgramStateRef state, 8740b57cec5SDimitry Andric const Expr *FirstBuf, 8750b57cec5SDimitry Andric const Expr *Size) { 8760b57cec5SDimitry Andric // If we do not know that the buffer is long enough we return 'true'. 8770b57cec5SDimitry Andric // Otherwise the parent region of this field region would also get 8780b57cec5SDimitry Andric // invalidated, which would lead to warnings based on an unknown state. 8790b57cec5SDimitry Andric 8800b57cec5SDimitry Andric // Originally copied from CheckBufferAccess and CheckLocation. 8810b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 8820b57cec5SDimitry Andric ASTContext &Ctx = svalBuilder.getContext(); 8830b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 8840b57cec5SDimitry Andric 8850b57cec5SDimitry Andric QualType sizeTy = Size->getType(); 8860b57cec5SDimitry Andric QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); 8870b57cec5SDimitry Andric SVal BufVal = state->getSVal(FirstBuf, LCtx); 8880b57cec5SDimitry Andric 8890b57cec5SDimitry Andric SVal LengthVal = state->getSVal(Size, LCtx); 8900b57cec5SDimitry Andric Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 8910b57cec5SDimitry Andric if (!Length) 8920b57cec5SDimitry Andric return true; // cf top comment. 8930b57cec5SDimitry Andric 8940b57cec5SDimitry Andric // Compute the offset of the last element to be accessed: size-1. 8950b57cec5SDimitry Andric NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 8960b57cec5SDimitry Andric SVal Offset = svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy); 8970b57cec5SDimitry Andric if (Offset.isUnknown()) 8980b57cec5SDimitry Andric return true; // cf top comment 8990b57cec5SDimitry Andric NonLoc LastOffset = Offset.castAs<NonLoc>(); 9000b57cec5SDimitry Andric 9010b57cec5SDimitry Andric // Check that the first buffer is sufficiently long. 9020b57cec5SDimitry Andric SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); 9030b57cec5SDimitry Andric Optional<Loc> BufLoc = BufStart.getAs<Loc>(); 9040b57cec5SDimitry Andric if (!BufLoc) 9050b57cec5SDimitry Andric return true; // cf top comment. 9060b57cec5SDimitry Andric 9070b57cec5SDimitry Andric SVal BufEnd = 9080b57cec5SDimitry Andric svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, LastOffset, PtrTy); 9090b57cec5SDimitry Andric 9100b57cec5SDimitry Andric // Check for out of bound array element access. 9110b57cec5SDimitry Andric const MemRegion *R = BufEnd.getAsRegion(); 9120b57cec5SDimitry Andric if (!R) 9130b57cec5SDimitry Andric return true; // cf top comment. 9140b57cec5SDimitry Andric 9150b57cec5SDimitry Andric const ElementRegion *ER = dyn_cast<ElementRegion>(R); 9160b57cec5SDimitry Andric if (!ER) 9170b57cec5SDimitry Andric return true; // cf top comment. 9180b57cec5SDimitry Andric 9190b57cec5SDimitry Andric // FIXME: Does this crash when a non-standard definition 9200b57cec5SDimitry Andric // of a library function is encountered? 9210b57cec5SDimitry Andric assert(ER->getValueType() == C.getASTContext().CharTy && 9220b57cec5SDimitry Andric "IsFirstBufInBound should only be called with char* ElementRegions"); 9230b57cec5SDimitry Andric 9240b57cec5SDimitry Andric // Get the size of the array. 9250b57cec5SDimitry Andric const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); 926*fe6060f1SDimitry Andric DefinedOrUnknownSVal SizeDV = getDynamicExtent(state, superReg, svalBuilder); 9270b57cec5SDimitry Andric 9280b57cec5SDimitry Andric // Get the index of the accessed element. 9290b57cec5SDimitry Andric DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 9300b57cec5SDimitry Andric 9315ffd83dbSDimitry Andric ProgramStateRef StInBound = state->assumeInBound(Idx, SizeDV, true); 9320b57cec5SDimitry Andric 9330b57cec5SDimitry Andric return static_cast<bool>(StInBound); 9340b57cec5SDimitry Andric } 9350b57cec5SDimitry Andric 9360b57cec5SDimitry Andric ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, 9370b57cec5SDimitry Andric ProgramStateRef state, 9380b57cec5SDimitry Andric const Expr *E, SVal V, 9390b57cec5SDimitry Andric bool IsSourceBuffer, 9400b57cec5SDimitry Andric const Expr *Size) { 9410b57cec5SDimitry Andric Optional<Loc> L = V.getAs<Loc>(); 9420b57cec5SDimitry Andric if (!L) 9430b57cec5SDimitry Andric return state; 9440b57cec5SDimitry Andric 9450b57cec5SDimitry Andric // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes 9460b57cec5SDimitry Andric // some assumptions about the value that CFRefCount can't. Even so, it should 9470b57cec5SDimitry Andric // probably be refactored. 9480b57cec5SDimitry Andric if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) { 9490b57cec5SDimitry Andric const MemRegion *R = MR->getRegion()->StripCasts(); 9500b57cec5SDimitry Andric 9510b57cec5SDimitry Andric // Are we dealing with an ElementRegion? If so, we should be invalidating 9520b57cec5SDimitry Andric // the super-region. 9530b57cec5SDimitry Andric if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { 9540b57cec5SDimitry Andric R = ER->getSuperRegion(); 9550b57cec5SDimitry Andric // FIXME: What about layers of ElementRegions? 9560b57cec5SDimitry Andric } 9570b57cec5SDimitry Andric 9580b57cec5SDimitry Andric // Invalidate this region. 9590b57cec5SDimitry Andric const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); 9600b57cec5SDimitry Andric 9610b57cec5SDimitry Andric bool CausesPointerEscape = false; 9620b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits ITraits; 9630b57cec5SDimitry Andric // Invalidate and escape only indirect regions accessible through the source 9640b57cec5SDimitry Andric // buffer. 9650b57cec5SDimitry Andric if (IsSourceBuffer) { 9660b57cec5SDimitry Andric ITraits.setTrait(R->getBaseRegion(), 9670b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits::TK_PreserveContents); 9680b57cec5SDimitry Andric ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); 9690b57cec5SDimitry Andric CausesPointerEscape = true; 9700b57cec5SDimitry Andric } else { 9710b57cec5SDimitry Andric const MemRegion::Kind& K = R->getKind(); 9720b57cec5SDimitry Andric if (K == MemRegion::FieldRegionKind) 9730b57cec5SDimitry Andric if (Size && IsFirstBufInBound(C, state, E, Size)) { 9740b57cec5SDimitry Andric // If destination buffer is a field region and access is in bound, 9750b57cec5SDimitry Andric // do not invalidate its super region. 9760b57cec5SDimitry Andric ITraits.setTrait( 9770b57cec5SDimitry Andric R, 9780b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); 9790b57cec5SDimitry Andric } 9800b57cec5SDimitry Andric } 9810b57cec5SDimitry Andric 9820b57cec5SDimitry Andric return state->invalidateRegions(R, E, C.blockCount(), LCtx, 9830b57cec5SDimitry Andric CausesPointerEscape, nullptr, nullptr, 9840b57cec5SDimitry Andric &ITraits); 9850b57cec5SDimitry Andric } 9860b57cec5SDimitry Andric 9870b57cec5SDimitry Andric // If we have a non-region value by chance, just remove the binding. 9880b57cec5SDimitry Andric // FIXME: is this necessary or correct? This handles the non-Region 9890b57cec5SDimitry Andric // cases. Is it ever valid to store to these? 9900b57cec5SDimitry Andric return state->killBinding(*L); 9910b57cec5SDimitry Andric } 9920b57cec5SDimitry Andric 9930b57cec5SDimitry Andric bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, 9940b57cec5SDimitry Andric const MemRegion *MR) { 9950b57cec5SDimitry Andric switch (MR->getKind()) { 9960b57cec5SDimitry Andric case MemRegion::FunctionCodeRegionKind: { 997480093f4SDimitry Andric if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl()) 9980b57cec5SDimitry Andric os << "the address of the function '" << *FD << '\''; 9990b57cec5SDimitry Andric else 10000b57cec5SDimitry Andric os << "the address of a function"; 10010b57cec5SDimitry Andric return true; 10020b57cec5SDimitry Andric } 10030b57cec5SDimitry Andric case MemRegion::BlockCodeRegionKind: 10040b57cec5SDimitry Andric os << "block text"; 10050b57cec5SDimitry Andric return true; 10060b57cec5SDimitry Andric case MemRegion::BlockDataRegionKind: 10070b57cec5SDimitry Andric os << "a block"; 10080b57cec5SDimitry Andric return true; 10090b57cec5SDimitry Andric case MemRegion::CXXThisRegionKind: 10100b57cec5SDimitry Andric case MemRegion::CXXTempObjectRegionKind: 1011480093f4SDimitry Andric os << "a C++ temp object of type " 1012480093f4SDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10130b57cec5SDimitry Andric return true; 10145ffd83dbSDimitry Andric case MemRegion::NonParamVarRegionKind: 1015480093f4SDimitry Andric os << "a variable of type" 1016480093f4SDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10170b57cec5SDimitry Andric return true; 10185ffd83dbSDimitry Andric case MemRegion::ParamVarRegionKind: 10195ffd83dbSDimitry Andric os << "a parameter of type" 10205ffd83dbSDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10215ffd83dbSDimitry Andric return true; 10220b57cec5SDimitry Andric case MemRegion::FieldRegionKind: 1023480093f4SDimitry Andric os << "a field of type " 1024480093f4SDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10250b57cec5SDimitry Andric return true; 10260b57cec5SDimitry Andric case MemRegion::ObjCIvarRegionKind: 1027480093f4SDimitry Andric os << "an instance variable of type " 1028480093f4SDimitry Andric << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 10290b57cec5SDimitry Andric return true; 10300b57cec5SDimitry Andric default: 10310b57cec5SDimitry Andric return false; 10320b57cec5SDimitry Andric } 10330b57cec5SDimitry Andric } 10340b57cec5SDimitry Andric 10350b57cec5SDimitry Andric bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, 10360b57cec5SDimitry Andric const Expr *Size, CheckerContext &C, 10370b57cec5SDimitry Andric ProgramStateRef &State) { 10380b57cec5SDimitry Andric SVal MemVal = C.getSVal(DstBuffer); 10390b57cec5SDimitry Andric SVal SizeVal = C.getSVal(Size); 10400b57cec5SDimitry Andric const MemRegion *MR = MemVal.getAsRegion(); 10410b57cec5SDimitry Andric if (!MR) 10420b57cec5SDimitry Andric return false; 10430b57cec5SDimitry Andric 10440b57cec5SDimitry Andric // We're about to model memset by producing a "default binding" in the Store. 10450b57cec5SDimitry Andric // Our current implementation - RegionStore - doesn't support default bindings 10460b57cec5SDimitry Andric // that don't cover the whole base region. So we should first get the offset 10470b57cec5SDimitry Andric // and the base region to figure out whether the offset of buffer is 0. 10480b57cec5SDimitry Andric RegionOffset Offset = MR->getAsOffset(); 10490b57cec5SDimitry Andric const MemRegion *BR = Offset.getRegion(); 10500b57cec5SDimitry Andric 10510b57cec5SDimitry Andric Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>(); 10520b57cec5SDimitry Andric if (!SizeNL) 10530b57cec5SDimitry Andric return false; 10540b57cec5SDimitry Andric 10550b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 10560b57cec5SDimitry Andric ASTContext &Ctx = C.getASTContext(); 10570b57cec5SDimitry Andric 10580b57cec5SDimitry Andric // void *memset(void *dest, int ch, size_t count); 10590b57cec5SDimitry Andric // For now we can only handle the case of offset is 0 and concrete char value. 10600b57cec5SDimitry Andric if (Offset.isValid() && !Offset.hasSymbolicOffset() && 10610b57cec5SDimitry Andric Offset.getOffset() == 0) { 10625ffd83dbSDimitry Andric // Get the base region's size. 1063*fe6060f1SDimitry Andric DefinedOrUnknownSVal SizeDV = getDynamicExtent(State, BR, svalBuilder); 10640b57cec5SDimitry Andric 10650b57cec5SDimitry Andric ProgramStateRef StateWholeReg, StateNotWholeReg; 10660b57cec5SDimitry Andric std::tie(StateWholeReg, StateNotWholeReg) = 10675ffd83dbSDimitry Andric State->assume(svalBuilder.evalEQ(State, SizeDV, *SizeNL)); 10680b57cec5SDimitry Andric 10690b57cec5SDimitry Andric // With the semantic of 'memset()', we should convert the CharVal to 10700b57cec5SDimitry Andric // unsigned char. 10710b57cec5SDimitry Andric CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy); 10720b57cec5SDimitry Andric 10730b57cec5SDimitry Andric ProgramStateRef StateNullChar, StateNonNullChar; 10740b57cec5SDimitry Andric std::tie(StateNullChar, StateNonNullChar) = 10750b57cec5SDimitry Andric assumeZero(C, State, CharVal, Ctx.UnsignedCharTy); 10760b57cec5SDimitry Andric 10770b57cec5SDimitry Andric if (StateWholeReg && !StateNotWholeReg && StateNullChar && 10780b57cec5SDimitry Andric !StateNonNullChar) { 10790b57cec5SDimitry Andric // If the 'memset()' acts on the whole region of destination buffer and 10800b57cec5SDimitry Andric // the value of the second argument of 'memset()' is zero, bind the second 10810b57cec5SDimitry Andric // argument's value to the destination buffer with 'default binding'. 10820b57cec5SDimitry Andric // FIXME: Since there is no perfect way to bind the non-zero character, we 10830b57cec5SDimitry Andric // can only deal with zero value here. In the future, we need to deal with 10840b57cec5SDimitry Andric // the binding of non-zero value in the case of whole region. 10850b57cec5SDimitry Andric State = State->bindDefaultZero(svalBuilder.makeLoc(BR), 10860b57cec5SDimitry Andric C.getLocationContext()); 10870b57cec5SDimitry Andric } else { 10880b57cec5SDimitry Andric // If the destination buffer's extent is not equal to the value of 10890b57cec5SDimitry Andric // third argument, just invalidate buffer. 10900b57cec5SDimitry Andric State = InvalidateBuffer(C, State, DstBuffer, MemVal, 10910b57cec5SDimitry Andric /*IsSourceBuffer*/ false, Size); 10920b57cec5SDimitry Andric } 10930b57cec5SDimitry Andric 10940b57cec5SDimitry Andric if (StateNullChar && !StateNonNullChar) { 10950b57cec5SDimitry Andric // If the value of the second argument of 'memset()' is zero, set the 10960b57cec5SDimitry Andric // string length of destination buffer to 0 directly. 10970b57cec5SDimitry Andric State = setCStringLength(State, MR, 10980b57cec5SDimitry Andric svalBuilder.makeZeroVal(Ctx.getSizeType())); 10990b57cec5SDimitry Andric } else if (!StateNullChar && StateNonNullChar) { 11000b57cec5SDimitry Andric SVal NewStrLen = svalBuilder.getMetadataSymbolVal( 11010b57cec5SDimitry Andric CStringChecker::getTag(), MR, DstBuffer, Ctx.getSizeType(), 11020b57cec5SDimitry Andric C.getLocationContext(), C.blockCount()); 11030b57cec5SDimitry Andric 11040b57cec5SDimitry Andric // If the value of second argument is not zero, then the string length 11050b57cec5SDimitry Andric // is at least the size argument. 11060b57cec5SDimitry Andric SVal NewStrLenGESize = svalBuilder.evalBinOp( 11070b57cec5SDimitry Andric State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType()); 11080b57cec5SDimitry Andric 11090b57cec5SDimitry Andric State = setCStringLength( 11100b57cec5SDimitry Andric State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(), true), 11110b57cec5SDimitry Andric MR, NewStrLen); 11120b57cec5SDimitry Andric } 11130b57cec5SDimitry Andric } else { 11140b57cec5SDimitry Andric // If the offset is not zero and char value is not concrete, we can do 11150b57cec5SDimitry Andric // nothing but invalidate the buffer. 11160b57cec5SDimitry Andric State = InvalidateBuffer(C, State, DstBuffer, MemVal, 11170b57cec5SDimitry Andric /*IsSourceBuffer*/ false, Size); 11180b57cec5SDimitry Andric } 11190b57cec5SDimitry Andric return true; 11200b57cec5SDimitry Andric } 11210b57cec5SDimitry Andric 11220b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11230b57cec5SDimitry Andric // evaluation of individual function calls. 11240b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 11250b57cec5SDimitry Andric 11265ffd83dbSDimitry Andric void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE, 11275ffd83dbSDimitry Andric ProgramStateRef state, SizeArgExpr Size, 11285ffd83dbSDimitry Andric DestinationArgExpr Dest, 11295ffd83dbSDimitry Andric SourceArgExpr Source, bool Restricted, 11300b57cec5SDimitry Andric bool IsMempcpy) const { 11310b57cec5SDimitry Andric CurrentFunctionDescription = "memory copy function"; 11320b57cec5SDimitry Andric 11330b57cec5SDimitry Andric // See if the size argument is zero. 11340b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 11355ffd83dbSDimitry Andric SVal sizeVal = state->getSVal(Size.Expression, LCtx); 11365ffd83dbSDimitry Andric QualType sizeTy = Size.Expression->getType(); 11370b57cec5SDimitry Andric 11380b57cec5SDimitry Andric ProgramStateRef stateZeroSize, stateNonZeroSize; 11390b57cec5SDimitry Andric std::tie(stateZeroSize, stateNonZeroSize) = 11400b57cec5SDimitry Andric assumeZero(C, state, sizeVal, sizeTy); 11410b57cec5SDimitry Andric 11420b57cec5SDimitry Andric // Get the value of the Dest. 11435ffd83dbSDimitry Andric SVal destVal = state->getSVal(Dest.Expression, LCtx); 11440b57cec5SDimitry Andric 11450b57cec5SDimitry Andric // If the size is zero, there won't be any actual memory access, so 11460b57cec5SDimitry Andric // just bind the return value to the destination buffer and return. 11470b57cec5SDimitry Andric if (stateZeroSize && !stateNonZeroSize) { 11480b57cec5SDimitry Andric stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal); 11490b57cec5SDimitry Andric C.addTransition(stateZeroSize); 11500b57cec5SDimitry Andric return; 11510b57cec5SDimitry Andric } 11520b57cec5SDimitry Andric 11530b57cec5SDimitry Andric // If the size can be nonzero, we have to check the other arguments. 11540b57cec5SDimitry Andric if (stateNonZeroSize) { 11550b57cec5SDimitry Andric state = stateNonZeroSize; 11560b57cec5SDimitry Andric 11570b57cec5SDimitry Andric // Ensure the destination is not null. If it is NULL there will be a 11580b57cec5SDimitry Andric // NULL pointer dereference. 11595ffd83dbSDimitry Andric state = checkNonNull(C, state, Dest, destVal); 11600b57cec5SDimitry Andric if (!state) 11610b57cec5SDimitry Andric return; 11620b57cec5SDimitry Andric 11630b57cec5SDimitry Andric // Get the value of the Src. 11645ffd83dbSDimitry Andric SVal srcVal = state->getSVal(Source.Expression, LCtx); 11650b57cec5SDimitry Andric 11660b57cec5SDimitry Andric // Ensure the source is not null. If it is NULL there will be a 11670b57cec5SDimitry Andric // NULL pointer dereference. 11685ffd83dbSDimitry Andric state = checkNonNull(C, state, Source, srcVal); 11690b57cec5SDimitry Andric if (!state) 11700b57cec5SDimitry Andric return; 11710b57cec5SDimitry Andric 11720b57cec5SDimitry Andric // Ensure the accesses are valid and that the buffers do not overlap. 11735ffd83dbSDimitry Andric state = CheckBufferAccess(C, state, Dest, Size, AccessKind::write); 11745ffd83dbSDimitry Andric state = CheckBufferAccess(C, state, Source, Size, AccessKind::read); 11755ffd83dbSDimitry Andric 11760b57cec5SDimitry Andric if (Restricted) 11770b57cec5SDimitry Andric state = CheckOverlap(C, state, Size, Dest, Source); 11780b57cec5SDimitry Andric 11790b57cec5SDimitry Andric if (!state) 11800b57cec5SDimitry Andric return; 11810b57cec5SDimitry Andric 11820b57cec5SDimitry Andric // If this is mempcpy, get the byte after the last byte copied and 11830b57cec5SDimitry Andric // bind the expr. 11840b57cec5SDimitry Andric if (IsMempcpy) { 11850b57cec5SDimitry Andric // Get the byte after the last byte copied. 11860b57cec5SDimitry Andric SValBuilder &SvalBuilder = C.getSValBuilder(); 11870b57cec5SDimitry Andric ASTContext &Ctx = SvalBuilder.getContext(); 11880b57cec5SDimitry Andric QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); 11890b57cec5SDimitry Andric SVal DestRegCharVal = 11905ffd83dbSDimitry Andric SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType()); 11910b57cec5SDimitry Andric SVal lastElement = C.getSValBuilder().evalBinOp( 11925ffd83dbSDimitry Andric state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType()); 11930b57cec5SDimitry Andric // If we don't know how much we copied, we can at least 11940b57cec5SDimitry Andric // conjure a return value for later. 11950b57cec5SDimitry Andric if (lastElement.isUnknown()) 11960b57cec5SDimitry Andric lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 11970b57cec5SDimitry Andric C.blockCount()); 11980b57cec5SDimitry Andric 11990b57cec5SDimitry Andric // The byte after the last byte copied is the return value. 12000b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, lastElement); 12010b57cec5SDimitry Andric } else { 12020b57cec5SDimitry Andric // All other copies return the destination buffer. 12030b57cec5SDimitry Andric // (Well, bcopy() has a void return type, but this won't hurt.) 12040b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, destVal); 12050b57cec5SDimitry Andric } 12060b57cec5SDimitry Andric 12070b57cec5SDimitry Andric // Invalidate the destination (regular invalidation without pointer-escaping 12080b57cec5SDimitry Andric // the address of the top-level region). 12090b57cec5SDimitry Andric // FIXME: Even if we can't perfectly model the copy, we should see if we 12100b57cec5SDimitry Andric // can use LazyCompoundVals to copy the source values into the destination. 12110b57cec5SDimitry Andric // This would probably remove any existing bindings past the end of the 12120b57cec5SDimitry Andric // copied region, but that's still an improvement over blank invalidation. 12135ffd83dbSDimitry Andric state = 12145ffd83dbSDimitry Andric InvalidateBuffer(C, state, Dest.Expression, C.getSVal(Dest.Expression), 12155ffd83dbSDimitry Andric /*IsSourceBuffer*/ false, Size.Expression); 12160b57cec5SDimitry Andric 12170b57cec5SDimitry Andric // Invalidate the source (const-invalidation without const-pointer-escaping 12180b57cec5SDimitry Andric // the address of the top-level region). 12195ffd83dbSDimitry Andric state = InvalidateBuffer(C, state, Source.Expression, 12205ffd83dbSDimitry Andric C.getSVal(Source.Expression), 12210b57cec5SDimitry Andric /*IsSourceBuffer*/ true, nullptr); 12220b57cec5SDimitry Andric 12230b57cec5SDimitry Andric C.addTransition(state); 12240b57cec5SDimitry Andric } 12250b57cec5SDimitry Andric } 12260b57cec5SDimitry Andric 12270b57cec5SDimitry Andric void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { 12280b57cec5SDimitry Andric // void *memcpy(void *restrict dst, const void *restrict src, size_t n); 12290b57cec5SDimitry Andric // The return value is the address of the destination buffer. 12305ffd83dbSDimitry Andric DestinationArgExpr Dest = {CE->getArg(0), 0}; 12315ffd83dbSDimitry Andric SourceArgExpr Src = {CE->getArg(1), 1}; 12325ffd83dbSDimitry Andric SizeArgExpr Size = {CE->getArg(2), 2}; 12330b57cec5SDimitry Andric 12345ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 12355ffd83dbSDimitry Andric 12365ffd83dbSDimitry Andric constexpr bool IsRestricted = true; 12375ffd83dbSDimitry Andric constexpr bool IsMempcpy = false; 12385ffd83dbSDimitry Andric evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy); 12390b57cec5SDimitry Andric } 12400b57cec5SDimitry Andric 12410b57cec5SDimitry Andric void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { 12420b57cec5SDimitry Andric // void *mempcpy(void *restrict dst, const void *restrict src, size_t n); 12430b57cec5SDimitry Andric // The return value is a pointer to the byte following the last written byte. 12445ffd83dbSDimitry Andric DestinationArgExpr Dest = {CE->getArg(0), 0}; 12455ffd83dbSDimitry Andric SourceArgExpr Src = {CE->getArg(1), 1}; 12465ffd83dbSDimitry Andric SizeArgExpr Size = {CE->getArg(2), 2}; 12470b57cec5SDimitry Andric 12485ffd83dbSDimitry Andric constexpr bool IsRestricted = true; 12495ffd83dbSDimitry Andric constexpr bool IsMempcpy = true; 12505ffd83dbSDimitry Andric evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); 12510b57cec5SDimitry Andric } 12520b57cec5SDimitry Andric 12530b57cec5SDimitry Andric void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { 12540b57cec5SDimitry Andric // void *memmove(void *dst, const void *src, size_t n); 12550b57cec5SDimitry Andric // The return value is the address of the destination buffer. 12565ffd83dbSDimitry Andric DestinationArgExpr Dest = {CE->getArg(0), 0}; 12575ffd83dbSDimitry Andric SourceArgExpr Src = {CE->getArg(1), 1}; 12585ffd83dbSDimitry Andric SizeArgExpr Size = {CE->getArg(2), 2}; 12590b57cec5SDimitry Andric 12605ffd83dbSDimitry Andric constexpr bool IsRestricted = false; 12615ffd83dbSDimitry Andric constexpr bool IsMempcpy = false; 12625ffd83dbSDimitry Andric evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); 12630b57cec5SDimitry Andric } 12640b57cec5SDimitry Andric 12650b57cec5SDimitry Andric void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { 12660b57cec5SDimitry Andric // void bcopy(const void *src, void *dst, size_t n); 12675ffd83dbSDimitry Andric SourceArgExpr Src(CE->getArg(0), 0); 12685ffd83dbSDimitry Andric DestinationArgExpr Dest = {CE->getArg(1), 1}; 12695ffd83dbSDimitry Andric SizeArgExpr Size = {CE->getArg(2), 2}; 12705ffd83dbSDimitry Andric 12715ffd83dbSDimitry Andric constexpr bool IsRestricted = false; 12725ffd83dbSDimitry Andric constexpr bool IsMempcpy = false; 12735ffd83dbSDimitry Andric evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy); 12740b57cec5SDimitry Andric } 12750b57cec5SDimitry Andric 12760b57cec5SDimitry Andric void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { 12770b57cec5SDimitry Andric // int memcmp(const void *s1, const void *s2, size_t n); 12780b57cec5SDimitry Andric CurrentFunctionDescription = "memory comparison function"; 12790b57cec5SDimitry Andric 12805ffd83dbSDimitry Andric AnyArgExpr Left = {CE->getArg(0), 0}; 12815ffd83dbSDimitry Andric AnyArgExpr Right = {CE->getArg(1), 1}; 12825ffd83dbSDimitry Andric SizeArgExpr Size = {CE->getArg(2), 2}; 12830b57cec5SDimitry Andric 12845ffd83dbSDimitry Andric ProgramStateRef State = C.getState(); 12855ffd83dbSDimitry Andric SValBuilder &Builder = C.getSValBuilder(); 12865ffd83dbSDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 12870b57cec5SDimitry Andric 12880b57cec5SDimitry Andric // See if the size argument is zero. 12895ffd83dbSDimitry Andric SVal sizeVal = State->getSVal(Size.Expression, LCtx); 12905ffd83dbSDimitry Andric QualType sizeTy = Size.Expression->getType(); 12910b57cec5SDimitry Andric 12920b57cec5SDimitry Andric ProgramStateRef stateZeroSize, stateNonZeroSize; 12930b57cec5SDimitry Andric std::tie(stateZeroSize, stateNonZeroSize) = 12945ffd83dbSDimitry Andric assumeZero(C, State, sizeVal, sizeTy); 12950b57cec5SDimitry Andric 12960b57cec5SDimitry Andric // If the size can be zero, the result will be 0 in that case, and we don't 12970b57cec5SDimitry Andric // have to check either of the buffers. 12980b57cec5SDimitry Andric if (stateZeroSize) { 12995ffd83dbSDimitry Andric State = stateZeroSize; 13005ffd83dbSDimitry Andric State = State->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType())); 13015ffd83dbSDimitry Andric C.addTransition(State); 13020b57cec5SDimitry Andric } 13030b57cec5SDimitry Andric 13040b57cec5SDimitry Andric // If the size can be nonzero, we have to check the other arguments. 13050b57cec5SDimitry Andric if (stateNonZeroSize) { 13065ffd83dbSDimitry Andric State = stateNonZeroSize; 13070b57cec5SDimitry Andric // If we know the two buffers are the same, we know the result is 0. 13080b57cec5SDimitry Andric // First, get the two buffers' addresses. Another checker will have already 13090b57cec5SDimitry Andric // made sure they're not undefined. 13100b57cec5SDimitry Andric DefinedOrUnknownSVal LV = 13115ffd83dbSDimitry Andric State->getSVal(Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>(); 13120b57cec5SDimitry Andric DefinedOrUnknownSVal RV = 13135ffd83dbSDimitry Andric State->getSVal(Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>(); 13140b57cec5SDimitry Andric 13150b57cec5SDimitry Andric // See if they are the same. 13165ffd83dbSDimitry Andric ProgramStateRef SameBuffer, NotSameBuffer; 13175ffd83dbSDimitry Andric std::tie(SameBuffer, NotSameBuffer) = 13185ffd83dbSDimitry Andric State->assume(Builder.evalEQ(State, LV, RV)); 13190b57cec5SDimitry Andric 1320480093f4SDimitry Andric // If the two arguments are the same buffer, we know the result is 0, 13210b57cec5SDimitry Andric // and we only need to check one size. 13225ffd83dbSDimitry Andric if (SameBuffer && !NotSameBuffer) { 13235ffd83dbSDimitry Andric State = SameBuffer; 13245ffd83dbSDimitry Andric State = CheckBufferAccess(C, State, Left, Size, AccessKind::read); 13255ffd83dbSDimitry Andric if (State) { 13265ffd83dbSDimitry Andric State = 13275ffd83dbSDimitry Andric SameBuffer->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType())); 13285ffd83dbSDimitry Andric C.addTransition(State); 13290b57cec5SDimitry Andric } 1330480093f4SDimitry Andric return; 13310b57cec5SDimitry Andric } 13320b57cec5SDimitry Andric 1333480093f4SDimitry Andric // If the two arguments might be different buffers, we have to check 1334480093f4SDimitry Andric // the size of both of them. 13355ffd83dbSDimitry Andric assert(NotSameBuffer); 13365ffd83dbSDimitry Andric State = CheckBufferAccess(C, State, Right, Size, AccessKind::read); 13375ffd83dbSDimitry Andric State = CheckBufferAccess(C, State, Left, Size, AccessKind::read); 13385ffd83dbSDimitry Andric if (State) { 13390b57cec5SDimitry Andric // The return value is the comparison result, which we don't know. 13405ffd83dbSDimitry Andric SVal CmpV = Builder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 13415ffd83dbSDimitry Andric State = State->BindExpr(CE, LCtx, CmpV); 13425ffd83dbSDimitry Andric C.addTransition(State); 13430b57cec5SDimitry Andric } 13440b57cec5SDimitry Andric } 13450b57cec5SDimitry Andric } 13460b57cec5SDimitry Andric 13470b57cec5SDimitry Andric void CStringChecker::evalstrLength(CheckerContext &C, 13480b57cec5SDimitry Andric const CallExpr *CE) const { 13490b57cec5SDimitry Andric // size_t strlen(const char *s); 13500b57cec5SDimitry Andric evalstrLengthCommon(C, CE, /* IsStrnlen = */ false); 13510b57cec5SDimitry Andric } 13520b57cec5SDimitry Andric 13530b57cec5SDimitry Andric void CStringChecker::evalstrnLength(CheckerContext &C, 13540b57cec5SDimitry Andric const CallExpr *CE) const { 13550b57cec5SDimitry Andric // size_t strnlen(const char *s, size_t maxlen); 13560b57cec5SDimitry Andric evalstrLengthCommon(C, CE, /* IsStrnlen = */ true); 13570b57cec5SDimitry Andric } 13580b57cec5SDimitry Andric 13590b57cec5SDimitry Andric void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, 13600b57cec5SDimitry Andric bool IsStrnlen) const { 13610b57cec5SDimitry Andric CurrentFunctionDescription = "string length function"; 13620b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 13630b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 13640b57cec5SDimitry Andric 13650b57cec5SDimitry Andric if (IsStrnlen) { 13660b57cec5SDimitry Andric const Expr *maxlenExpr = CE->getArg(1); 13670b57cec5SDimitry Andric SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); 13680b57cec5SDimitry Andric 13690b57cec5SDimitry Andric ProgramStateRef stateZeroSize, stateNonZeroSize; 13700b57cec5SDimitry Andric std::tie(stateZeroSize, stateNonZeroSize) = 13710b57cec5SDimitry Andric assumeZero(C, state, maxlenVal, maxlenExpr->getType()); 13720b57cec5SDimitry Andric 13730b57cec5SDimitry Andric // If the size can be zero, the result will be 0 in that case, and we don't 13740b57cec5SDimitry Andric // have to check the string itself. 13750b57cec5SDimitry Andric if (stateZeroSize) { 13760b57cec5SDimitry Andric SVal zero = C.getSValBuilder().makeZeroVal(CE->getType()); 13770b57cec5SDimitry Andric stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero); 13780b57cec5SDimitry Andric C.addTransition(stateZeroSize); 13790b57cec5SDimitry Andric } 13800b57cec5SDimitry Andric 13810b57cec5SDimitry Andric // If the size is GUARANTEED to be zero, we're done! 13820b57cec5SDimitry Andric if (!stateNonZeroSize) 13830b57cec5SDimitry Andric return; 13840b57cec5SDimitry Andric 13850b57cec5SDimitry Andric // Otherwise, record the assumption that the size is nonzero. 13860b57cec5SDimitry Andric state = stateNonZeroSize; 13870b57cec5SDimitry Andric } 13880b57cec5SDimitry Andric 13890b57cec5SDimitry Andric // Check that the string argument is non-null. 13905ffd83dbSDimitry Andric AnyArgExpr Arg = {CE->getArg(0), 0}; 13915ffd83dbSDimitry Andric SVal ArgVal = state->getSVal(Arg.Expression, LCtx); 13925ffd83dbSDimitry Andric state = checkNonNull(C, state, Arg, ArgVal); 13930b57cec5SDimitry Andric 13940b57cec5SDimitry Andric if (!state) 13950b57cec5SDimitry Andric return; 13960b57cec5SDimitry Andric 13975ffd83dbSDimitry Andric SVal strLength = getCStringLength(C, state, Arg.Expression, ArgVal); 13980b57cec5SDimitry Andric 13990b57cec5SDimitry Andric // If the argument isn't a valid C string, there's no valid state to 14000b57cec5SDimitry Andric // transition to. 14010b57cec5SDimitry Andric if (strLength.isUndef()) 14020b57cec5SDimitry Andric return; 14030b57cec5SDimitry Andric 14040b57cec5SDimitry Andric DefinedOrUnknownSVal result = UnknownVal(); 14050b57cec5SDimitry Andric 14060b57cec5SDimitry Andric // If the check is for strnlen() then bind the return value to no more than 14070b57cec5SDimitry Andric // the maxlen value. 14080b57cec5SDimitry Andric if (IsStrnlen) { 14090b57cec5SDimitry Andric QualType cmpTy = C.getSValBuilder().getConditionType(); 14100b57cec5SDimitry Andric 14110b57cec5SDimitry Andric // It's a little unfortunate to be getting this again, 14120b57cec5SDimitry Andric // but it's not that expensive... 14130b57cec5SDimitry Andric const Expr *maxlenExpr = CE->getArg(1); 14140b57cec5SDimitry Andric SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); 14150b57cec5SDimitry Andric 14160b57cec5SDimitry Andric Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); 14170b57cec5SDimitry Andric Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>(); 14180b57cec5SDimitry Andric 14190b57cec5SDimitry Andric if (strLengthNL && maxlenValNL) { 14200b57cec5SDimitry Andric ProgramStateRef stateStringTooLong, stateStringNotTooLong; 14210b57cec5SDimitry Andric 14220b57cec5SDimitry Andric // Check if the strLength is greater than the maxlen. 14230b57cec5SDimitry Andric std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume( 14240b57cec5SDimitry Andric C.getSValBuilder() 14250b57cec5SDimitry Andric .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy) 14260b57cec5SDimitry Andric .castAs<DefinedOrUnknownSVal>()); 14270b57cec5SDimitry Andric 14280b57cec5SDimitry Andric if (stateStringTooLong && !stateStringNotTooLong) { 14290b57cec5SDimitry Andric // If the string is longer than maxlen, return maxlen. 14300b57cec5SDimitry Andric result = *maxlenValNL; 14310b57cec5SDimitry Andric } else if (stateStringNotTooLong && !stateStringTooLong) { 14320b57cec5SDimitry Andric // If the string is shorter than maxlen, return its length. 14330b57cec5SDimitry Andric result = *strLengthNL; 14340b57cec5SDimitry Andric } 14350b57cec5SDimitry Andric } 14360b57cec5SDimitry Andric 14370b57cec5SDimitry Andric if (result.isUnknown()) { 14380b57cec5SDimitry Andric // If we don't have enough information for a comparison, there's 14390b57cec5SDimitry Andric // no guarantee the full string length will actually be returned. 14400b57cec5SDimitry Andric // All we know is the return value is the min of the string length 14410b57cec5SDimitry Andric // and the limit. This is better than nothing. 14420b57cec5SDimitry Andric result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 14430b57cec5SDimitry Andric C.blockCount()); 14440b57cec5SDimitry Andric NonLoc resultNL = result.castAs<NonLoc>(); 14450b57cec5SDimitry Andric 14460b57cec5SDimitry Andric if (strLengthNL) { 14470b57cec5SDimitry Andric state = state->assume(C.getSValBuilder().evalBinOpNN( 14480b57cec5SDimitry Andric state, BO_LE, resultNL, *strLengthNL, cmpTy) 14490b57cec5SDimitry Andric .castAs<DefinedOrUnknownSVal>(), true); 14500b57cec5SDimitry Andric } 14510b57cec5SDimitry Andric 14520b57cec5SDimitry Andric if (maxlenValNL) { 14530b57cec5SDimitry Andric state = state->assume(C.getSValBuilder().evalBinOpNN( 14540b57cec5SDimitry Andric state, BO_LE, resultNL, *maxlenValNL, cmpTy) 14550b57cec5SDimitry Andric .castAs<DefinedOrUnknownSVal>(), true); 14560b57cec5SDimitry Andric } 14570b57cec5SDimitry Andric } 14580b57cec5SDimitry Andric 14590b57cec5SDimitry Andric } else { 14600b57cec5SDimitry Andric // This is a plain strlen(), not strnlen(). 14610b57cec5SDimitry Andric result = strLength.castAs<DefinedOrUnknownSVal>(); 14620b57cec5SDimitry Andric 14630b57cec5SDimitry Andric // If we don't know the length of the string, conjure a return 14640b57cec5SDimitry Andric // value, so it can be used in constraints, at least. 14650b57cec5SDimitry Andric if (result.isUnknown()) { 14660b57cec5SDimitry Andric result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 14670b57cec5SDimitry Andric C.blockCount()); 14680b57cec5SDimitry Andric } 14690b57cec5SDimitry Andric } 14700b57cec5SDimitry Andric 14710b57cec5SDimitry Andric // Bind the return value. 14720b57cec5SDimitry Andric assert(!result.isUnknown() && "Should have conjured a value by now"); 14730b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, result); 14740b57cec5SDimitry Andric C.addTransition(state); 14750b57cec5SDimitry Andric } 14760b57cec5SDimitry Andric 14770b57cec5SDimitry Andric void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { 14780b57cec5SDimitry Andric // char *strcpy(char *restrict dst, const char *restrict src); 14790b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1480480093f4SDimitry Andric /* ReturnEnd = */ false, 1481480093f4SDimitry Andric /* IsBounded = */ false, 1482480093f4SDimitry Andric /* appendK = */ ConcatFnKind::none); 14830b57cec5SDimitry Andric } 14840b57cec5SDimitry Andric 14850b57cec5SDimitry Andric void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { 14860b57cec5SDimitry Andric // char *strncpy(char *restrict dst, const char *restrict src, size_t n); 14870b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1488480093f4SDimitry Andric /* ReturnEnd = */ false, 1489480093f4SDimitry Andric /* IsBounded = */ true, 1490480093f4SDimitry Andric /* appendK = */ ConcatFnKind::none); 14910b57cec5SDimitry Andric } 14920b57cec5SDimitry Andric 14930b57cec5SDimitry Andric void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const { 14940b57cec5SDimitry Andric // char *stpcpy(char *restrict dst, const char *restrict src); 14950b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1496480093f4SDimitry Andric /* ReturnEnd = */ true, 1497480093f4SDimitry Andric /* IsBounded = */ false, 1498480093f4SDimitry Andric /* appendK = */ ConcatFnKind::none); 14990b57cec5SDimitry Andric } 15000b57cec5SDimitry Andric 15010b57cec5SDimitry Andric void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const { 1502480093f4SDimitry Andric // size_t strlcpy(char *dest, const char *src, size_t size); 15030b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1504480093f4SDimitry Andric /* ReturnEnd = */ true, 1505480093f4SDimitry Andric /* IsBounded = */ true, 1506480093f4SDimitry Andric /* appendK = */ ConcatFnKind::none, 15070b57cec5SDimitry Andric /* returnPtr = */ false); 15080b57cec5SDimitry Andric } 15090b57cec5SDimitry Andric 15100b57cec5SDimitry Andric void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { 15110b57cec5SDimitry Andric // char *strcat(char *restrict s1, const char *restrict s2); 15120b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1513480093f4SDimitry Andric /* ReturnEnd = */ false, 1514480093f4SDimitry Andric /* IsBounded = */ false, 1515480093f4SDimitry Andric /* appendK = */ ConcatFnKind::strcat); 15160b57cec5SDimitry Andric } 15170b57cec5SDimitry Andric 15180b57cec5SDimitry Andric void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const { 15190b57cec5SDimitry Andric //char *strncat(char *restrict s1, const char *restrict s2, size_t n); 15200b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1521480093f4SDimitry Andric /* ReturnEnd = */ false, 1522480093f4SDimitry Andric /* IsBounded = */ true, 1523480093f4SDimitry Andric /* appendK = */ ConcatFnKind::strcat); 15240b57cec5SDimitry Andric } 15250b57cec5SDimitry Andric 15260b57cec5SDimitry Andric void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const { 1527480093f4SDimitry Andric // size_t strlcat(char *dst, const char *src, size_t size); 1528480093f4SDimitry Andric // It will append at most size - strlen(dst) - 1 bytes, 1529480093f4SDimitry Andric // NULL-terminating the result. 15300b57cec5SDimitry Andric evalStrcpyCommon(C, CE, 1531480093f4SDimitry Andric /* ReturnEnd = */ false, 1532480093f4SDimitry Andric /* IsBounded = */ true, 1533480093f4SDimitry Andric /* appendK = */ ConcatFnKind::strlcat, 15340b57cec5SDimitry Andric /* returnPtr = */ false); 15350b57cec5SDimitry Andric } 15360b57cec5SDimitry Andric 15370b57cec5SDimitry Andric void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, 1538480093f4SDimitry Andric bool ReturnEnd, bool IsBounded, 1539480093f4SDimitry Andric ConcatFnKind appendK, 1540480093f4SDimitry Andric bool returnPtr) const { 1541480093f4SDimitry Andric if (appendK == ConcatFnKind::none) 15420b57cec5SDimitry Andric CurrentFunctionDescription = "string copy function"; 1543480093f4SDimitry Andric else 1544480093f4SDimitry Andric CurrentFunctionDescription = "string concatenation function"; 15455ffd83dbSDimitry Andric 15460b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 15470b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 15480b57cec5SDimitry Andric 15490b57cec5SDimitry Andric // Check that the destination is non-null. 15505ffd83dbSDimitry Andric DestinationArgExpr Dst = {CE->getArg(0), 0}; 15515ffd83dbSDimitry Andric SVal DstVal = state->getSVal(Dst.Expression, LCtx); 15525ffd83dbSDimitry Andric state = checkNonNull(C, state, Dst, DstVal); 15530b57cec5SDimitry Andric if (!state) 15540b57cec5SDimitry Andric return; 15550b57cec5SDimitry Andric 15560b57cec5SDimitry Andric // Check that the source is non-null. 15575ffd83dbSDimitry Andric SourceArgExpr srcExpr = {CE->getArg(1), 1}; 15585ffd83dbSDimitry Andric SVal srcVal = state->getSVal(srcExpr.Expression, LCtx); 15595ffd83dbSDimitry Andric state = checkNonNull(C, state, srcExpr, srcVal); 15600b57cec5SDimitry Andric if (!state) 15610b57cec5SDimitry Andric return; 15620b57cec5SDimitry Andric 15630b57cec5SDimitry Andric // Get the string length of the source. 15645ffd83dbSDimitry Andric SVal strLength = getCStringLength(C, state, srcExpr.Expression, srcVal); 1565480093f4SDimitry Andric Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); 1566480093f4SDimitry Andric 1567480093f4SDimitry Andric // Get the string length of the destination buffer. 15685ffd83dbSDimitry Andric SVal dstStrLength = getCStringLength(C, state, Dst.Expression, DstVal); 1569480093f4SDimitry Andric Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); 15700b57cec5SDimitry Andric 15710b57cec5SDimitry Andric // If the source isn't a valid C string, give up. 15720b57cec5SDimitry Andric if (strLength.isUndef()) 15730b57cec5SDimitry Andric return; 15740b57cec5SDimitry Andric 15750b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 15760b57cec5SDimitry Andric QualType cmpTy = svalBuilder.getConditionType(); 15770b57cec5SDimitry Andric QualType sizeTy = svalBuilder.getContext().getSizeType(); 15780b57cec5SDimitry Andric 15790b57cec5SDimitry Andric // These two values allow checking two kinds of errors: 15800b57cec5SDimitry Andric // - actual overflows caused by a source that doesn't fit in the destination 15810b57cec5SDimitry Andric // - potential overflows caused by a bound that could exceed the destination 15820b57cec5SDimitry Andric SVal amountCopied = UnknownVal(); 15830b57cec5SDimitry Andric SVal maxLastElementIndex = UnknownVal(); 15840b57cec5SDimitry Andric const char *boundWarning = nullptr; 15850b57cec5SDimitry Andric 15865ffd83dbSDimitry Andric // FIXME: Why do we choose the srcExpr if the access has no size? 15875ffd83dbSDimitry Andric // Note that the 3rd argument of the call would be the size parameter. 15885ffd83dbSDimitry Andric SizeArgExpr SrcExprAsSizeDummy = {srcExpr.Expression, srcExpr.ArgumentIndex}; 15895ffd83dbSDimitry Andric state = CheckOverlap( 15905ffd83dbSDimitry Andric C, state, 15915ffd83dbSDimitry Andric (IsBounded ? SizeArgExpr{CE->getArg(2), 2} : SrcExprAsSizeDummy), Dst, 1592480093f4SDimitry Andric srcExpr); 15930b57cec5SDimitry Andric 15940b57cec5SDimitry Andric if (!state) 15950b57cec5SDimitry Andric return; 15960b57cec5SDimitry Andric 15970b57cec5SDimitry Andric // If the function is strncpy, strncat, etc... it is bounded. 1598480093f4SDimitry Andric if (IsBounded) { 15990b57cec5SDimitry Andric // Get the max number of characters to copy. 16005ffd83dbSDimitry Andric SizeArgExpr lenExpr = {CE->getArg(2), 2}; 16015ffd83dbSDimitry Andric SVal lenVal = state->getSVal(lenExpr.Expression, LCtx); 16020b57cec5SDimitry Andric 16030b57cec5SDimitry Andric // Protect against misdeclared strncpy(). 16045ffd83dbSDimitry Andric lenVal = 16055ffd83dbSDimitry Andric svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType()); 16060b57cec5SDimitry Andric 16070b57cec5SDimitry Andric Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>(); 16080b57cec5SDimitry Andric 16090b57cec5SDimitry Andric // If we know both values, we might be able to figure out how much 16100b57cec5SDimitry Andric // we're copying. 16110b57cec5SDimitry Andric if (strLengthNL && lenValNL) { 1612480093f4SDimitry Andric switch (appendK) { 1613480093f4SDimitry Andric case ConcatFnKind::none: 1614480093f4SDimitry Andric case ConcatFnKind::strcat: { 16150b57cec5SDimitry Andric ProgramStateRef stateSourceTooLong, stateSourceNotTooLong; 16160b57cec5SDimitry Andric // Check if the max number to copy is less than the length of the src. 16170b57cec5SDimitry Andric // If the bound is equal to the source length, strncpy won't null- 16180b57cec5SDimitry Andric // terminate the result! 16190b57cec5SDimitry Andric std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( 1620480093f4SDimitry Andric svalBuilder 1621480093f4SDimitry Andric .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) 16220b57cec5SDimitry Andric .castAs<DefinedOrUnknownSVal>()); 16230b57cec5SDimitry Andric 16240b57cec5SDimitry Andric if (stateSourceTooLong && !stateSourceNotTooLong) { 1625480093f4SDimitry Andric // Max number to copy is less than the length of the src, so the 1626480093f4SDimitry Andric // actual strLength copied is the max number arg. 16270b57cec5SDimitry Andric state = stateSourceTooLong; 16280b57cec5SDimitry Andric amountCopied = lenVal; 16290b57cec5SDimitry Andric 16300b57cec5SDimitry Andric } else if (!stateSourceTooLong && stateSourceNotTooLong) { 16310b57cec5SDimitry Andric // The source buffer entirely fits in the bound. 16320b57cec5SDimitry Andric state = stateSourceNotTooLong; 16330b57cec5SDimitry Andric amountCopied = strLength; 16340b57cec5SDimitry Andric } 1635480093f4SDimitry Andric break; 1636480093f4SDimitry Andric } 1637480093f4SDimitry Andric case ConcatFnKind::strlcat: 1638480093f4SDimitry Andric if (!dstStrLengthNL) 1639480093f4SDimitry Andric return; 1640480093f4SDimitry Andric 1641480093f4SDimitry Andric // amountCopied = min (size - dstLen - 1 , srcLen) 1642480093f4SDimitry Andric SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, 1643480093f4SDimitry Andric *dstStrLengthNL, sizeTy); 1644480093f4SDimitry Andric if (!freeSpace.getAs<NonLoc>()) 1645480093f4SDimitry Andric return; 1646480093f4SDimitry Andric freeSpace = 1647480093f4SDimitry Andric svalBuilder.evalBinOp(state, BO_Sub, freeSpace, 1648480093f4SDimitry Andric svalBuilder.makeIntVal(1, sizeTy), sizeTy); 1649480093f4SDimitry Andric Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>(); 1650480093f4SDimitry Andric 1651480093f4SDimitry Andric // While unlikely, it is possible that the subtraction is 1652480093f4SDimitry Andric // too complex to compute, let's check whether it succeeded. 1653480093f4SDimitry Andric if (!freeSpaceNL) 1654480093f4SDimitry Andric return; 1655480093f4SDimitry Andric SVal hasEnoughSpace = svalBuilder.evalBinOpNN( 1656480093f4SDimitry Andric state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy); 1657480093f4SDimitry Andric 1658480093f4SDimitry Andric ProgramStateRef TrueState, FalseState; 1659480093f4SDimitry Andric std::tie(TrueState, FalseState) = 1660480093f4SDimitry Andric state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>()); 1661480093f4SDimitry Andric 1662480093f4SDimitry Andric // srcStrLength <= size - dstStrLength -1 1663480093f4SDimitry Andric if (TrueState && !FalseState) { 1664480093f4SDimitry Andric amountCopied = strLength; 16650b57cec5SDimitry Andric } 16660b57cec5SDimitry Andric 1667480093f4SDimitry Andric // srcStrLength > size - dstStrLength -1 1668480093f4SDimitry Andric if (!TrueState && FalseState) { 1669480093f4SDimitry Andric amountCopied = freeSpace; 1670480093f4SDimitry Andric } 1671480093f4SDimitry Andric 1672480093f4SDimitry Andric if (TrueState && FalseState) 1673480093f4SDimitry Andric amountCopied = UnknownVal(); 1674480093f4SDimitry Andric break; 1675480093f4SDimitry Andric } 1676480093f4SDimitry Andric } 16770b57cec5SDimitry Andric // We still want to know if the bound is known to be too large. 16780b57cec5SDimitry Andric if (lenValNL) { 1679480093f4SDimitry Andric switch (appendK) { 1680480093f4SDimitry Andric case ConcatFnKind::strcat: 16810b57cec5SDimitry Andric // For strncat, the check is strlen(dst) + lenVal < sizeof(dst) 16820b57cec5SDimitry Andric 16830b57cec5SDimitry Andric // Get the string length of the destination. If the destination is 16840b57cec5SDimitry Andric // memory that can't have a string length, we shouldn't be copying 16850b57cec5SDimitry Andric // into it anyway. 16860b57cec5SDimitry Andric if (dstStrLength.isUndef()) 16870b57cec5SDimitry Andric return; 16880b57cec5SDimitry Andric 1689480093f4SDimitry Andric if (dstStrLengthNL) { 1690480093f4SDimitry Andric maxLastElementIndex = svalBuilder.evalBinOpNN( 1691480093f4SDimitry Andric state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy); 1692480093f4SDimitry Andric 16930b57cec5SDimitry Andric boundWarning = "Size argument is greater than the free space in the " 16940b57cec5SDimitry Andric "destination buffer"; 16950b57cec5SDimitry Andric } 1696480093f4SDimitry Andric break; 1697480093f4SDimitry Andric case ConcatFnKind::none: 1698480093f4SDimitry Andric case ConcatFnKind::strlcat: 1699480093f4SDimitry Andric // For strncpy and strlcat, this is just checking 1700480093f4SDimitry Andric // that lenVal <= sizeof(dst). 17010b57cec5SDimitry Andric // (Yes, strncpy and strncat differ in how they treat termination. 17020b57cec5SDimitry Andric // strncat ALWAYS terminates, but strncpy doesn't.) 17030b57cec5SDimitry Andric 17040b57cec5SDimitry Andric // We need a special case for when the copy size is zero, in which 17050b57cec5SDimitry Andric // case strncpy will do no work at all. Our bounds check uses n-1 17060b57cec5SDimitry Andric // as the last element accessed, so n == 0 is problematic. 17070b57cec5SDimitry Andric ProgramStateRef StateZeroSize, StateNonZeroSize; 17080b57cec5SDimitry Andric std::tie(StateZeroSize, StateNonZeroSize) = 17090b57cec5SDimitry Andric assumeZero(C, state, *lenValNL, sizeTy); 17100b57cec5SDimitry Andric 17110b57cec5SDimitry Andric // If the size is known to be zero, we're done. 17120b57cec5SDimitry Andric if (StateZeroSize && !StateNonZeroSize) { 17130b57cec5SDimitry Andric if (returnPtr) { 17140b57cec5SDimitry Andric StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal); 17150b57cec5SDimitry Andric } else { 1716480093f4SDimitry Andric if (appendK == ConcatFnKind::none) { 1717480093f4SDimitry Andric // strlcpy returns strlen(src) 1718480093f4SDimitry Andric StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength); 1719480093f4SDimitry Andric } else { 1720480093f4SDimitry Andric // strlcat returns strlen(src) + strlen(dst) 1721480093f4SDimitry Andric SVal retSize = svalBuilder.evalBinOp( 1722480093f4SDimitry Andric state, BO_Add, strLength, dstStrLength, sizeTy); 1723480093f4SDimitry Andric StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize); 1724480093f4SDimitry Andric } 17250b57cec5SDimitry Andric } 17260b57cec5SDimitry Andric C.addTransition(StateZeroSize); 17270b57cec5SDimitry Andric return; 17280b57cec5SDimitry Andric } 17290b57cec5SDimitry Andric 17300b57cec5SDimitry Andric // Otherwise, go ahead and figure out the last element we'll touch. 17310b57cec5SDimitry Andric // We don't record the non-zero assumption here because we can't 17320b57cec5SDimitry Andric // be sure. We won't warn on a possible zero. 17330b57cec5SDimitry Andric NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 1734480093f4SDimitry Andric maxLastElementIndex = 1735480093f4SDimitry Andric svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy); 17360b57cec5SDimitry Andric boundWarning = "Size argument is greater than the length of the " 17370b57cec5SDimitry Andric "destination buffer"; 1738480093f4SDimitry Andric break; 17390b57cec5SDimitry Andric } 17400b57cec5SDimitry Andric } 17410b57cec5SDimitry Andric } else { 17420b57cec5SDimitry Andric // The function isn't bounded. The amount copied should match the length 17430b57cec5SDimitry Andric // of the source buffer. 17440b57cec5SDimitry Andric amountCopied = strLength; 17450b57cec5SDimitry Andric } 17460b57cec5SDimitry Andric 17470b57cec5SDimitry Andric assert(state); 17480b57cec5SDimitry Andric 17490b57cec5SDimitry Andric // This represents the number of characters copied into the destination 17500b57cec5SDimitry Andric // buffer. (It may not actually be the strlen if the destination buffer 17510b57cec5SDimitry Andric // is not terminated.) 17520b57cec5SDimitry Andric SVal finalStrLength = UnknownVal(); 1753480093f4SDimitry Andric SVal strlRetVal = UnknownVal(); 1754480093f4SDimitry Andric 1755480093f4SDimitry Andric if (appendK == ConcatFnKind::none && !returnPtr) { 1756480093f4SDimitry Andric // strlcpy returns the sizeof(src) 1757480093f4SDimitry Andric strlRetVal = strLength; 1758480093f4SDimitry Andric } 17590b57cec5SDimitry Andric 17600b57cec5SDimitry Andric // If this is an appending function (strcat, strncat...) then set the 17610b57cec5SDimitry Andric // string length to strlen(src) + strlen(dst) since the buffer will 17620b57cec5SDimitry Andric // ultimately contain both. 1763480093f4SDimitry Andric if (appendK != ConcatFnKind::none) { 17640b57cec5SDimitry Andric // Get the string length of the destination. If the destination is memory 17650b57cec5SDimitry Andric // that can't have a string length, we shouldn't be copying into it anyway. 17660b57cec5SDimitry Andric if (dstStrLength.isUndef()) 17670b57cec5SDimitry Andric return; 17680b57cec5SDimitry Andric 1769480093f4SDimitry Andric if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) { 1770480093f4SDimitry Andric strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL, 1771480093f4SDimitry Andric *dstStrLengthNL, sizeTy); 1772480093f4SDimitry Andric } 1773480093f4SDimitry Andric 1774480093f4SDimitry Andric Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>(); 17750b57cec5SDimitry Andric 17760b57cec5SDimitry Andric // If we know both string lengths, we might know the final string length. 1777480093f4SDimitry Andric if (amountCopiedNL && dstStrLengthNL) { 17780b57cec5SDimitry Andric // Make sure the two lengths together don't overflow a size_t. 1779480093f4SDimitry Andric state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL); 17800b57cec5SDimitry Andric if (!state) 17810b57cec5SDimitry Andric return; 17820b57cec5SDimitry Andric 1783480093f4SDimitry Andric finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL, 17840b57cec5SDimitry Andric *dstStrLengthNL, sizeTy); 17850b57cec5SDimitry Andric } 17860b57cec5SDimitry Andric 17870b57cec5SDimitry Andric // If we couldn't get a single value for the final string length, 17880b57cec5SDimitry Andric // we can at least bound it by the individual lengths. 17890b57cec5SDimitry Andric if (finalStrLength.isUnknown()) { 17900b57cec5SDimitry Andric // Try to get a "hypothetical" string length symbol, which we can later 17910b57cec5SDimitry Andric // set as a real value if that turns out to be the case. 17920b57cec5SDimitry Andric finalStrLength = getCStringLength(C, state, CE, DstVal, true); 17930b57cec5SDimitry Andric assert(!finalStrLength.isUndef()); 17940b57cec5SDimitry Andric 17950b57cec5SDimitry Andric if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) { 1796480093f4SDimitry Andric if (amountCopiedNL && appendK == ConcatFnKind::none) { 1797480093f4SDimitry Andric // we overwrite dst string with the src 17980b57cec5SDimitry Andric // finalStrLength >= srcStrLength 1799480093f4SDimitry Andric SVal sourceInResult = svalBuilder.evalBinOpNN( 1800480093f4SDimitry Andric state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy); 18010b57cec5SDimitry Andric state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(), 18020b57cec5SDimitry Andric true); 18030b57cec5SDimitry Andric if (!state) 18040b57cec5SDimitry Andric return; 18050b57cec5SDimitry Andric } 18060b57cec5SDimitry Andric 1807480093f4SDimitry Andric if (dstStrLengthNL && appendK != ConcatFnKind::none) { 1808480093f4SDimitry Andric // we extend the dst string with the src 18090b57cec5SDimitry Andric // finalStrLength >= dstStrLength 18100b57cec5SDimitry Andric SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE, 18110b57cec5SDimitry Andric *finalStrLengthNL, 18120b57cec5SDimitry Andric *dstStrLengthNL, 18130b57cec5SDimitry Andric cmpTy); 18140b57cec5SDimitry Andric state = 18150b57cec5SDimitry Andric state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true); 18160b57cec5SDimitry Andric if (!state) 18170b57cec5SDimitry Andric return; 18180b57cec5SDimitry Andric } 18190b57cec5SDimitry Andric } 18200b57cec5SDimitry Andric } 18210b57cec5SDimitry Andric 18220b57cec5SDimitry Andric } else { 18230b57cec5SDimitry Andric // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and 18240b57cec5SDimitry Andric // the final string length will match the input string length. 18250b57cec5SDimitry Andric finalStrLength = amountCopied; 18260b57cec5SDimitry Andric } 18270b57cec5SDimitry Andric 18280b57cec5SDimitry Andric SVal Result; 18290b57cec5SDimitry Andric 18300b57cec5SDimitry Andric if (returnPtr) { 18310b57cec5SDimitry Andric // The final result of the function will either be a pointer past the last 18320b57cec5SDimitry Andric // copied element, or a pointer to the start of the destination buffer. 1833480093f4SDimitry Andric Result = (ReturnEnd ? UnknownVal() : DstVal); 18340b57cec5SDimitry Andric } else { 1835480093f4SDimitry Andric if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none) 1836480093f4SDimitry Andric //strlcpy, strlcat 1837480093f4SDimitry Andric Result = strlRetVal; 1838480093f4SDimitry Andric else 18390b57cec5SDimitry Andric Result = finalStrLength; 18400b57cec5SDimitry Andric } 18410b57cec5SDimitry Andric 18420b57cec5SDimitry Andric assert(state); 18430b57cec5SDimitry Andric 18440b57cec5SDimitry Andric // If the destination is a MemRegion, try to check for a buffer overflow and 18450b57cec5SDimitry Andric // record the new string length. 18460b57cec5SDimitry Andric if (Optional<loc::MemRegionVal> dstRegVal = 18470b57cec5SDimitry Andric DstVal.getAs<loc::MemRegionVal>()) { 18485ffd83dbSDimitry Andric QualType ptrTy = Dst.Expression->getType(); 18490b57cec5SDimitry Andric 18500b57cec5SDimitry Andric // If we have an exact value on a bounded copy, use that to check for 18510b57cec5SDimitry Andric // overflows, rather than our estimate about how much is actually copied. 18520b57cec5SDimitry Andric if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) { 18535ffd83dbSDimitry Andric SVal maxLastElement = 18545ffd83dbSDimitry Andric svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy); 18555ffd83dbSDimitry Andric 18565ffd83dbSDimitry Andric state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write); 18570b57cec5SDimitry Andric if (!state) 18580b57cec5SDimitry Andric return; 18590b57cec5SDimitry Andric } 18600b57cec5SDimitry Andric 18610b57cec5SDimitry Andric // Then, if the final length is known... 18620b57cec5SDimitry Andric if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) { 18630b57cec5SDimitry Andric SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, 18640b57cec5SDimitry Andric *knownStrLength, ptrTy); 18650b57cec5SDimitry Andric 18660b57cec5SDimitry Andric // ...and we haven't checked the bound, we'll check the actual copy. 18670b57cec5SDimitry Andric if (!boundWarning) { 18685ffd83dbSDimitry Andric state = CheckLocation(C, state, Dst, lastElement, AccessKind::write); 18690b57cec5SDimitry Andric if (!state) 18700b57cec5SDimitry Andric return; 18710b57cec5SDimitry Andric } 18720b57cec5SDimitry Andric 18730b57cec5SDimitry Andric // If this is a stpcpy-style copy, the last element is the return value. 1874480093f4SDimitry Andric if (returnPtr && ReturnEnd) 18750b57cec5SDimitry Andric Result = lastElement; 18760b57cec5SDimitry Andric } 18770b57cec5SDimitry Andric 18780b57cec5SDimitry Andric // Invalidate the destination (regular invalidation without pointer-escaping 18790b57cec5SDimitry Andric // the address of the top-level region). This must happen before we set the 18800b57cec5SDimitry Andric // C string length because invalidation will clear the length. 18810b57cec5SDimitry Andric // FIXME: Even if we can't perfectly model the copy, we should see if we 18820b57cec5SDimitry Andric // can use LazyCompoundVals to copy the source values into the destination. 18830b57cec5SDimitry Andric // This would probably remove any existing bindings past the end of the 18840b57cec5SDimitry Andric // string, but that's still an improvement over blank invalidation. 18855ffd83dbSDimitry Andric state = InvalidateBuffer(C, state, Dst.Expression, *dstRegVal, 18860b57cec5SDimitry Andric /*IsSourceBuffer*/ false, nullptr); 18870b57cec5SDimitry Andric 18880b57cec5SDimitry Andric // Invalidate the source (const-invalidation without const-pointer-escaping 18890b57cec5SDimitry Andric // the address of the top-level region). 18905ffd83dbSDimitry Andric state = InvalidateBuffer(C, state, srcExpr.Expression, srcVal, 18915ffd83dbSDimitry Andric /*IsSourceBuffer*/ true, nullptr); 18920b57cec5SDimitry Andric 18930b57cec5SDimitry Andric // Set the C string length of the destination, if we know it. 1894480093f4SDimitry Andric if (IsBounded && (appendK == ConcatFnKind::none)) { 18950b57cec5SDimitry Andric // strncpy is annoying in that it doesn't guarantee to null-terminate 18960b57cec5SDimitry Andric // the result string. If the original string didn't fit entirely inside 18970b57cec5SDimitry Andric // the bound (including the null-terminator), we don't know how long the 18980b57cec5SDimitry Andric // result is. 18990b57cec5SDimitry Andric if (amountCopied != strLength) 19000b57cec5SDimitry Andric finalStrLength = UnknownVal(); 19010b57cec5SDimitry Andric } 19020b57cec5SDimitry Andric state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength); 19030b57cec5SDimitry Andric } 19040b57cec5SDimitry Andric 19050b57cec5SDimitry Andric assert(state); 19060b57cec5SDimitry Andric 19070b57cec5SDimitry Andric if (returnPtr) { 19080b57cec5SDimitry Andric // If this is a stpcpy-style copy, but we were unable to check for a buffer 19090b57cec5SDimitry Andric // overflow, we still need a result. Conjure a return value. 1910480093f4SDimitry Andric if (ReturnEnd && Result.isUnknown()) { 19110b57cec5SDimitry Andric Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 19120b57cec5SDimitry Andric } 19130b57cec5SDimitry Andric } 19140b57cec5SDimitry Andric // Set the return value. 19150b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, Result); 19160b57cec5SDimitry Andric C.addTransition(state); 19170b57cec5SDimitry Andric } 19180b57cec5SDimitry Andric 19190b57cec5SDimitry Andric void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { 19200b57cec5SDimitry Andric //int strcmp(const char *s1, const char *s2); 1921480093f4SDimitry Andric evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ false); 19220b57cec5SDimitry Andric } 19230b57cec5SDimitry Andric 19240b57cec5SDimitry Andric void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { 19250b57cec5SDimitry Andric //int strncmp(const char *s1, const char *s2, size_t n); 1926480093f4SDimitry Andric evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ false); 19270b57cec5SDimitry Andric } 19280b57cec5SDimitry Andric 19290b57cec5SDimitry Andric void CStringChecker::evalStrcasecmp(CheckerContext &C, 19300b57cec5SDimitry Andric const CallExpr *CE) const { 19310b57cec5SDimitry Andric //int strcasecmp(const char *s1, const char *s2); 1932480093f4SDimitry Andric evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ true); 19330b57cec5SDimitry Andric } 19340b57cec5SDimitry Andric 19350b57cec5SDimitry Andric void CStringChecker::evalStrncasecmp(CheckerContext &C, 19360b57cec5SDimitry Andric const CallExpr *CE) const { 19370b57cec5SDimitry Andric //int strncasecmp(const char *s1, const char *s2, size_t n); 1938480093f4SDimitry Andric evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ true); 19390b57cec5SDimitry Andric } 19400b57cec5SDimitry Andric 19410b57cec5SDimitry Andric void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, 1942480093f4SDimitry Andric bool IsBounded, bool IgnoreCase) const { 19430b57cec5SDimitry Andric CurrentFunctionDescription = "string comparison function"; 19440b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 19450b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 19460b57cec5SDimitry Andric 19470b57cec5SDimitry Andric // Check that the first string is non-null 19485ffd83dbSDimitry Andric AnyArgExpr Left = {CE->getArg(0), 0}; 19495ffd83dbSDimitry Andric SVal LeftVal = state->getSVal(Left.Expression, LCtx); 19505ffd83dbSDimitry Andric state = checkNonNull(C, state, Left, LeftVal); 19510b57cec5SDimitry Andric if (!state) 19520b57cec5SDimitry Andric return; 19530b57cec5SDimitry Andric 19540b57cec5SDimitry Andric // Check that the second string is non-null. 19555ffd83dbSDimitry Andric AnyArgExpr Right = {CE->getArg(1), 1}; 19565ffd83dbSDimitry Andric SVal RightVal = state->getSVal(Right.Expression, LCtx); 19575ffd83dbSDimitry Andric state = checkNonNull(C, state, Right, RightVal); 19580b57cec5SDimitry Andric if (!state) 19590b57cec5SDimitry Andric return; 19600b57cec5SDimitry Andric 19610b57cec5SDimitry Andric // Get the string length of the first string or give up. 19625ffd83dbSDimitry Andric SVal LeftLength = getCStringLength(C, state, Left.Expression, LeftVal); 19635ffd83dbSDimitry Andric if (LeftLength.isUndef()) 19640b57cec5SDimitry Andric return; 19650b57cec5SDimitry Andric 19660b57cec5SDimitry Andric // Get the string length of the second string or give up. 19675ffd83dbSDimitry Andric SVal RightLength = getCStringLength(C, state, Right.Expression, RightVal); 19685ffd83dbSDimitry Andric if (RightLength.isUndef()) 19690b57cec5SDimitry Andric return; 19700b57cec5SDimitry Andric 19710b57cec5SDimitry Andric // If we know the two buffers are the same, we know the result is 0. 19720b57cec5SDimitry Andric // First, get the two buffers' addresses. Another checker will have already 19730b57cec5SDimitry Andric // made sure they're not undefined. 19745ffd83dbSDimitry Andric DefinedOrUnknownSVal LV = LeftVal.castAs<DefinedOrUnknownSVal>(); 19755ffd83dbSDimitry Andric DefinedOrUnknownSVal RV = RightVal.castAs<DefinedOrUnknownSVal>(); 19760b57cec5SDimitry Andric 19770b57cec5SDimitry Andric // See if they are the same. 19780b57cec5SDimitry Andric SValBuilder &svalBuilder = C.getSValBuilder(); 19790b57cec5SDimitry Andric DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); 19800b57cec5SDimitry Andric ProgramStateRef StSameBuf, StNotSameBuf; 19810b57cec5SDimitry Andric std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); 19820b57cec5SDimitry Andric 19830b57cec5SDimitry Andric // If the two arguments might be the same buffer, we know the result is 0, 19840b57cec5SDimitry Andric // and we only need to check one size. 19850b57cec5SDimitry Andric if (StSameBuf) { 19860b57cec5SDimitry Andric StSameBuf = StSameBuf->BindExpr(CE, LCtx, 19870b57cec5SDimitry Andric svalBuilder.makeZeroVal(CE->getType())); 19880b57cec5SDimitry Andric C.addTransition(StSameBuf); 19890b57cec5SDimitry Andric 19900b57cec5SDimitry Andric // If the two arguments are GUARANTEED to be the same, we're done! 19910b57cec5SDimitry Andric if (!StNotSameBuf) 19920b57cec5SDimitry Andric return; 19930b57cec5SDimitry Andric } 19940b57cec5SDimitry Andric 19950b57cec5SDimitry Andric assert(StNotSameBuf); 19960b57cec5SDimitry Andric state = StNotSameBuf; 19970b57cec5SDimitry Andric 19980b57cec5SDimitry Andric // At this point we can go about comparing the two buffers. 19990b57cec5SDimitry Andric // For now, we only do this if they're both known string literals. 20000b57cec5SDimitry Andric 20010b57cec5SDimitry Andric // Attempt to extract string literals from both expressions. 20025ffd83dbSDimitry Andric const StringLiteral *LeftStrLiteral = 20035ffd83dbSDimitry Andric getCStringLiteral(C, state, Left.Expression, LeftVal); 20045ffd83dbSDimitry Andric const StringLiteral *RightStrLiteral = 20055ffd83dbSDimitry Andric getCStringLiteral(C, state, Right.Expression, RightVal); 20060b57cec5SDimitry Andric bool canComputeResult = false; 20070b57cec5SDimitry Andric SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, 20080b57cec5SDimitry Andric C.blockCount()); 20090b57cec5SDimitry Andric 20105ffd83dbSDimitry Andric if (LeftStrLiteral && RightStrLiteral) { 20115ffd83dbSDimitry Andric StringRef LeftStrRef = LeftStrLiteral->getString(); 20125ffd83dbSDimitry Andric StringRef RightStrRef = RightStrLiteral->getString(); 20130b57cec5SDimitry Andric 2014480093f4SDimitry Andric if (IsBounded) { 20150b57cec5SDimitry Andric // Get the max number of characters to compare. 20160b57cec5SDimitry Andric const Expr *lenExpr = CE->getArg(2); 20170b57cec5SDimitry Andric SVal lenVal = state->getSVal(lenExpr, LCtx); 20180b57cec5SDimitry Andric 20190b57cec5SDimitry Andric // If the length is known, we can get the right substrings. 20200b57cec5SDimitry Andric if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) { 20210b57cec5SDimitry Andric // Create substrings of each to compare the prefix. 20225ffd83dbSDimitry Andric LeftStrRef = LeftStrRef.substr(0, (size_t)len->getZExtValue()); 20235ffd83dbSDimitry Andric RightStrRef = RightStrRef.substr(0, (size_t)len->getZExtValue()); 20240b57cec5SDimitry Andric canComputeResult = true; 20250b57cec5SDimitry Andric } 20260b57cec5SDimitry Andric } else { 20270b57cec5SDimitry Andric // This is a normal, unbounded strcmp. 20280b57cec5SDimitry Andric canComputeResult = true; 20290b57cec5SDimitry Andric } 20300b57cec5SDimitry Andric 20310b57cec5SDimitry Andric if (canComputeResult) { 20320b57cec5SDimitry Andric // Real strcmp stops at null characters. 20335ffd83dbSDimitry Andric size_t s1Term = LeftStrRef.find('\0'); 20340b57cec5SDimitry Andric if (s1Term != StringRef::npos) 20355ffd83dbSDimitry Andric LeftStrRef = LeftStrRef.substr(0, s1Term); 20360b57cec5SDimitry Andric 20375ffd83dbSDimitry Andric size_t s2Term = RightStrRef.find('\0'); 20380b57cec5SDimitry Andric if (s2Term != StringRef::npos) 20395ffd83dbSDimitry Andric RightStrRef = RightStrRef.substr(0, s2Term); 20400b57cec5SDimitry Andric 20410b57cec5SDimitry Andric // Use StringRef's comparison methods to compute the actual result. 2042*fe6060f1SDimitry Andric int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef) 20435ffd83dbSDimitry Andric : LeftStrRef.compare(RightStrRef); 20440b57cec5SDimitry Andric 20450b57cec5SDimitry Andric // The strcmp function returns an integer greater than, equal to, or less 20460b57cec5SDimitry Andric // than zero, [c11, p7.24.4.2]. 20470b57cec5SDimitry Andric if (compareRes == 0) { 20480b57cec5SDimitry Andric resultVal = svalBuilder.makeIntVal(compareRes, CE->getType()); 20490b57cec5SDimitry Andric } 20500b57cec5SDimitry Andric else { 20510b57cec5SDimitry Andric DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType()); 20520b57cec5SDimitry Andric // Constrain strcmp's result range based on the result of StringRef's 20530b57cec5SDimitry Andric // comparison methods. 20540b57cec5SDimitry Andric BinaryOperatorKind op = (compareRes == 1) ? BO_GT : BO_LT; 20550b57cec5SDimitry Andric SVal compareWithZero = 20560b57cec5SDimitry Andric svalBuilder.evalBinOp(state, op, resultVal, zeroVal, 20570b57cec5SDimitry Andric svalBuilder.getConditionType()); 20580b57cec5SDimitry Andric DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>(); 20590b57cec5SDimitry Andric state = state->assume(compareWithZeroVal, true); 20600b57cec5SDimitry Andric } 20610b57cec5SDimitry Andric } 20620b57cec5SDimitry Andric } 20630b57cec5SDimitry Andric 20640b57cec5SDimitry Andric state = state->BindExpr(CE, LCtx, resultVal); 20650b57cec5SDimitry Andric 20660b57cec5SDimitry Andric // Record this as a possible path. 20670b57cec5SDimitry Andric C.addTransition(state); 20680b57cec5SDimitry Andric } 20690b57cec5SDimitry Andric 20700b57cec5SDimitry Andric void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { 20710b57cec5SDimitry Andric //char *strsep(char **stringp, const char *delim); 20720b57cec5SDimitry Andric // Sanity: does the search string parameter match the return type? 20735ffd83dbSDimitry Andric SourceArgExpr SearchStrPtr = {CE->getArg(0), 0}; 20745ffd83dbSDimitry Andric 20755ffd83dbSDimitry Andric QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType(); 20760b57cec5SDimitry Andric if (CharPtrTy.isNull() || 20770b57cec5SDimitry Andric CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType()) 20780b57cec5SDimitry Andric return; 20790b57cec5SDimitry Andric 20800b57cec5SDimitry Andric CurrentFunctionDescription = "strsep()"; 20810b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 20820b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 20830b57cec5SDimitry Andric 20840b57cec5SDimitry Andric // Check that the search string pointer is non-null (though it may point to 20850b57cec5SDimitry Andric // a null string). 20865ffd83dbSDimitry Andric SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx); 20875ffd83dbSDimitry Andric State = checkNonNull(C, State, SearchStrPtr, SearchStrVal); 20880b57cec5SDimitry Andric if (!State) 20890b57cec5SDimitry Andric return; 20900b57cec5SDimitry Andric 20910b57cec5SDimitry Andric // Check that the delimiter string is non-null. 20925ffd83dbSDimitry Andric AnyArgExpr DelimStr = {CE->getArg(1), 1}; 20935ffd83dbSDimitry Andric SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx); 20945ffd83dbSDimitry Andric State = checkNonNull(C, State, DelimStr, DelimStrVal); 20950b57cec5SDimitry Andric if (!State) 20960b57cec5SDimitry Andric return; 20970b57cec5SDimitry Andric 20980b57cec5SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 20990b57cec5SDimitry Andric SVal Result; 21000b57cec5SDimitry Andric if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) { 21010b57cec5SDimitry Andric // Get the current value of the search string pointer, as a char*. 21020b57cec5SDimitry Andric Result = State->getSVal(*SearchStrLoc, CharPtrTy); 21030b57cec5SDimitry Andric 21040b57cec5SDimitry Andric // Invalidate the search string, representing the change of one delimiter 21050b57cec5SDimitry Andric // character to NUL. 21065ffd83dbSDimitry Andric State = InvalidateBuffer(C, State, SearchStrPtr.Expression, Result, 21070b57cec5SDimitry Andric /*IsSourceBuffer*/ false, nullptr); 21080b57cec5SDimitry Andric 21090b57cec5SDimitry Andric // Overwrite the search string pointer. The new value is either an address 21100b57cec5SDimitry Andric // further along in the same string, or NULL if there are no more tokens. 21110b57cec5SDimitry Andric State = State->bindLoc(*SearchStrLoc, 21120b57cec5SDimitry Andric SVB.conjureSymbolVal(getTag(), 21130b57cec5SDimitry Andric CE, 21140b57cec5SDimitry Andric LCtx, 21150b57cec5SDimitry Andric CharPtrTy, 21160b57cec5SDimitry Andric C.blockCount()), 21170b57cec5SDimitry Andric LCtx); 21180b57cec5SDimitry Andric } else { 21190b57cec5SDimitry Andric assert(SearchStrVal.isUnknown()); 21200b57cec5SDimitry Andric // Conjure a symbolic value. It's the best we can do. 21210b57cec5SDimitry Andric Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 21220b57cec5SDimitry Andric } 21230b57cec5SDimitry Andric 21240b57cec5SDimitry Andric // Set the return value, and finish. 21250b57cec5SDimitry Andric State = State->BindExpr(CE, LCtx, Result); 21260b57cec5SDimitry Andric C.addTransition(State); 21270b57cec5SDimitry Andric } 21280b57cec5SDimitry Andric 21290b57cec5SDimitry Andric // These should probably be moved into a C++ standard library checker. 21300b57cec5SDimitry Andric void CStringChecker::evalStdCopy(CheckerContext &C, const CallExpr *CE) const { 21310b57cec5SDimitry Andric evalStdCopyCommon(C, CE); 21320b57cec5SDimitry Andric } 21330b57cec5SDimitry Andric 21340b57cec5SDimitry Andric void CStringChecker::evalStdCopyBackward(CheckerContext &C, 21350b57cec5SDimitry Andric const CallExpr *CE) const { 21360b57cec5SDimitry Andric evalStdCopyCommon(C, CE); 21370b57cec5SDimitry Andric } 21380b57cec5SDimitry Andric 21390b57cec5SDimitry Andric void CStringChecker::evalStdCopyCommon(CheckerContext &C, 21400b57cec5SDimitry Andric const CallExpr *CE) const { 21410b57cec5SDimitry Andric if (!CE->getArg(2)->getType()->isPointerType()) 21420b57cec5SDimitry Andric return; 21430b57cec5SDimitry Andric 21440b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 21450b57cec5SDimitry Andric 21460b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 21470b57cec5SDimitry Andric 21480b57cec5SDimitry Andric // template <class _InputIterator, class _OutputIterator> 21490b57cec5SDimitry Andric // _OutputIterator 21500b57cec5SDimitry Andric // copy(_InputIterator __first, _InputIterator __last, 21510b57cec5SDimitry Andric // _OutputIterator __result) 21520b57cec5SDimitry Andric 21530b57cec5SDimitry Andric // Invalidate the destination buffer 21540b57cec5SDimitry Andric const Expr *Dst = CE->getArg(2); 21550b57cec5SDimitry Andric SVal DstVal = State->getSVal(Dst, LCtx); 21560b57cec5SDimitry Andric State = InvalidateBuffer(C, State, Dst, DstVal, /*IsSource=*/false, 21570b57cec5SDimitry Andric /*Size=*/nullptr); 21580b57cec5SDimitry Andric 21590b57cec5SDimitry Andric SValBuilder &SVB = C.getSValBuilder(); 21600b57cec5SDimitry Andric 21610b57cec5SDimitry Andric SVal ResultVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 21620b57cec5SDimitry Andric State = State->BindExpr(CE, LCtx, ResultVal); 21630b57cec5SDimitry Andric 21640b57cec5SDimitry Andric C.addTransition(State); 21650b57cec5SDimitry Andric } 21660b57cec5SDimitry Andric 21670b57cec5SDimitry Andric void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const { 21685ffd83dbSDimitry Andric // void *memset(void *s, int c, size_t n); 21690b57cec5SDimitry Andric CurrentFunctionDescription = "memory set function"; 21700b57cec5SDimitry Andric 21715ffd83dbSDimitry Andric DestinationArgExpr Buffer = {CE->getArg(0), 0}; 21725ffd83dbSDimitry Andric AnyArgExpr CharE = {CE->getArg(1), 1}; 21735ffd83dbSDimitry Andric SizeArgExpr Size = {CE->getArg(2), 2}; 21745ffd83dbSDimitry Andric 21750b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 21760b57cec5SDimitry Andric 21770b57cec5SDimitry Andric // See if the size argument is zero. 21780b57cec5SDimitry Andric const LocationContext *LCtx = C.getLocationContext(); 21795ffd83dbSDimitry Andric SVal SizeVal = C.getSVal(Size.Expression); 21805ffd83dbSDimitry Andric QualType SizeTy = Size.Expression->getType(); 21810b57cec5SDimitry Andric 21825ffd83dbSDimitry Andric ProgramStateRef ZeroSize, NonZeroSize; 21835ffd83dbSDimitry Andric std::tie(ZeroSize, NonZeroSize) = assumeZero(C, State, SizeVal, SizeTy); 21840b57cec5SDimitry Andric 21850b57cec5SDimitry Andric // Get the value of the memory area. 21865ffd83dbSDimitry Andric SVal BufferPtrVal = C.getSVal(Buffer.Expression); 21870b57cec5SDimitry Andric 21880b57cec5SDimitry Andric // If the size is zero, there won't be any actual memory access, so 21895ffd83dbSDimitry Andric // just bind the return value to the buffer and return. 21905ffd83dbSDimitry Andric if (ZeroSize && !NonZeroSize) { 21915ffd83dbSDimitry Andric ZeroSize = ZeroSize->BindExpr(CE, LCtx, BufferPtrVal); 21925ffd83dbSDimitry Andric C.addTransition(ZeroSize); 21930b57cec5SDimitry Andric return; 21940b57cec5SDimitry Andric } 21950b57cec5SDimitry Andric 21960b57cec5SDimitry Andric // Ensure the memory area is not null. 21970b57cec5SDimitry Andric // If it is NULL there will be a NULL pointer dereference. 21985ffd83dbSDimitry Andric State = checkNonNull(C, NonZeroSize, Buffer, BufferPtrVal); 21990b57cec5SDimitry Andric if (!State) 22000b57cec5SDimitry Andric return; 22010b57cec5SDimitry Andric 22025ffd83dbSDimitry Andric State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write); 22030b57cec5SDimitry Andric if (!State) 22040b57cec5SDimitry Andric return; 22050b57cec5SDimitry Andric 22060b57cec5SDimitry Andric // According to the values of the arguments, bind the value of the second 22070b57cec5SDimitry Andric // argument to the destination buffer and set string length, or just 22080b57cec5SDimitry Andric // invalidate the destination buffer. 22095ffd83dbSDimitry Andric if (!memsetAux(Buffer.Expression, C.getSVal(CharE.Expression), 22105ffd83dbSDimitry Andric Size.Expression, C, State)) 22110b57cec5SDimitry Andric return; 22120b57cec5SDimitry Andric 22135ffd83dbSDimitry Andric State = State->BindExpr(CE, LCtx, BufferPtrVal); 22140b57cec5SDimitry Andric C.addTransition(State); 22150b57cec5SDimitry Andric } 22160b57cec5SDimitry Andric 22170b57cec5SDimitry Andric void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const { 22180b57cec5SDimitry Andric CurrentFunctionDescription = "memory clearance function"; 22190b57cec5SDimitry Andric 22205ffd83dbSDimitry Andric DestinationArgExpr Buffer = {CE->getArg(0), 0}; 22215ffd83dbSDimitry Andric SizeArgExpr Size = {CE->getArg(1), 1}; 22220b57cec5SDimitry Andric SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy); 22230b57cec5SDimitry Andric 22240b57cec5SDimitry Andric ProgramStateRef State = C.getState(); 22250b57cec5SDimitry Andric 22260b57cec5SDimitry Andric // See if the size argument is zero. 22275ffd83dbSDimitry Andric SVal SizeVal = C.getSVal(Size.Expression); 22285ffd83dbSDimitry Andric QualType SizeTy = Size.Expression->getType(); 22290b57cec5SDimitry Andric 22300b57cec5SDimitry Andric ProgramStateRef StateZeroSize, StateNonZeroSize; 22310b57cec5SDimitry Andric std::tie(StateZeroSize, StateNonZeroSize) = 22320b57cec5SDimitry Andric assumeZero(C, State, SizeVal, SizeTy); 22330b57cec5SDimitry Andric 22340b57cec5SDimitry Andric // If the size is zero, there won't be any actual memory access, 22350b57cec5SDimitry Andric // In this case we just return. 22360b57cec5SDimitry Andric if (StateZeroSize && !StateNonZeroSize) { 22370b57cec5SDimitry Andric C.addTransition(StateZeroSize); 22380b57cec5SDimitry Andric return; 22390b57cec5SDimitry Andric } 22400b57cec5SDimitry Andric 22410b57cec5SDimitry Andric // Get the value of the memory area. 22425ffd83dbSDimitry Andric SVal MemVal = C.getSVal(Buffer.Expression); 22430b57cec5SDimitry Andric 22440b57cec5SDimitry Andric // Ensure the memory area is not null. 22450b57cec5SDimitry Andric // If it is NULL there will be a NULL pointer dereference. 22465ffd83dbSDimitry Andric State = checkNonNull(C, StateNonZeroSize, Buffer, MemVal); 22470b57cec5SDimitry Andric if (!State) 22480b57cec5SDimitry Andric return; 22490b57cec5SDimitry Andric 22505ffd83dbSDimitry Andric State = CheckBufferAccess(C, State, Buffer, Size, AccessKind::write); 22510b57cec5SDimitry Andric if (!State) 22520b57cec5SDimitry Andric return; 22530b57cec5SDimitry Andric 22545ffd83dbSDimitry Andric if (!memsetAux(Buffer.Expression, Zero, Size.Expression, C, State)) 22550b57cec5SDimitry Andric return; 22560b57cec5SDimitry Andric 22570b57cec5SDimitry Andric C.addTransition(State); 22580b57cec5SDimitry Andric } 22590b57cec5SDimitry Andric 22600b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 22610b57cec5SDimitry Andric // The driver method, and other Checker callbacks. 22620b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 22630b57cec5SDimitry Andric 22640b57cec5SDimitry Andric CStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call, 22650b57cec5SDimitry Andric CheckerContext &C) const { 22660b57cec5SDimitry Andric const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 22670b57cec5SDimitry Andric if (!CE) 22680b57cec5SDimitry Andric return nullptr; 22690b57cec5SDimitry Andric 22700b57cec5SDimitry Andric const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 22710b57cec5SDimitry Andric if (!FD) 22720b57cec5SDimitry Andric return nullptr; 22730b57cec5SDimitry Andric 22740b57cec5SDimitry Andric if (Call.isCalled(StdCopy)) { 22750b57cec5SDimitry Andric return &CStringChecker::evalStdCopy; 22760b57cec5SDimitry Andric } else if (Call.isCalled(StdCopyBackward)) { 22770b57cec5SDimitry Andric return &CStringChecker::evalStdCopyBackward; 22780b57cec5SDimitry Andric } 22790b57cec5SDimitry Andric 22800b57cec5SDimitry Andric // Pro-actively check that argument types are safe to do arithmetic upon. 22810b57cec5SDimitry Andric // We do not want to crash if someone accidentally passes a structure 22820b57cec5SDimitry Andric // into, say, a C++ overload of any of these functions. We could not check 22830b57cec5SDimitry Andric // that for std::copy because they may have arguments of other types. 22840b57cec5SDimitry Andric for (auto I : CE->arguments()) { 22850b57cec5SDimitry Andric QualType T = I->getType(); 22860b57cec5SDimitry Andric if (!T->isIntegralOrEnumerationType() && !T->isPointerType()) 22870b57cec5SDimitry Andric return nullptr; 22880b57cec5SDimitry Andric } 22890b57cec5SDimitry Andric 22900b57cec5SDimitry Andric const FnCheck *Callback = Callbacks.lookup(Call); 22910b57cec5SDimitry Andric if (Callback) 22920b57cec5SDimitry Andric return *Callback; 22930b57cec5SDimitry Andric 22940b57cec5SDimitry Andric return nullptr; 22950b57cec5SDimitry Andric } 22960b57cec5SDimitry Andric 22970b57cec5SDimitry Andric bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { 22980b57cec5SDimitry Andric FnCheck Callback = identifyCall(Call, C); 22990b57cec5SDimitry Andric 23000b57cec5SDimitry Andric // If the callee isn't a string function, let another checker handle it. 23010b57cec5SDimitry Andric if (!Callback) 23020b57cec5SDimitry Andric return false; 23030b57cec5SDimitry Andric 23040b57cec5SDimitry Andric // Check and evaluate the call. 23050b57cec5SDimitry Andric const auto *CE = cast<CallExpr>(Call.getOriginExpr()); 23060b57cec5SDimitry Andric (this->*Callback)(C, CE); 23070b57cec5SDimitry Andric 23080b57cec5SDimitry Andric // If the evaluate call resulted in no change, chain to the next eval call 23090b57cec5SDimitry Andric // handler. 23100b57cec5SDimitry Andric // Note, the custom CString evaluation calls assume that basic safety 23110b57cec5SDimitry Andric // properties are held. However, if the user chooses to turn off some of these 23120b57cec5SDimitry Andric // checks, we ignore the issues and leave the call evaluation to a generic 23130b57cec5SDimitry Andric // handler. 23140b57cec5SDimitry Andric return C.isDifferent(); 23150b57cec5SDimitry Andric } 23160b57cec5SDimitry Andric 23170b57cec5SDimitry Andric void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 23180b57cec5SDimitry Andric // Record string length for char a[] = "abc"; 23190b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 23200b57cec5SDimitry Andric 23210b57cec5SDimitry Andric for (const auto *I : DS->decls()) { 23220b57cec5SDimitry Andric const VarDecl *D = dyn_cast<VarDecl>(I); 23230b57cec5SDimitry Andric if (!D) 23240b57cec5SDimitry Andric continue; 23250b57cec5SDimitry Andric 23260b57cec5SDimitry Andric // FIXME: Handle array fields of structs. 23270b57cec5SDimitry Andric if (!D->getType()->isArrayType()) 23280b57cec5SDimitry Andric continue; 23290b57cec5SDimitry Andric 23300b57cec5SDimitry Andric const Expr *Init = D->getInit(); 23310b57cec5SDimitry Andric if (!Init) 23320b57cec5SDimitry Andric continue; 23330b57cec5SDimitry Andric if (!isa<StringLiteral>(Init)) 23340b57cec5SDimitry Andric continue; 23350b57cec5SDimitry Andric 23360b57cec5SDimitry Andric Loc VarLoc = state->getLValue(D, C.getLocationContext()); 23370b57cec5SDimitry Andric const MemRegion *MR = VarLoc.getAsRegion(); 23380b57cec5SDimitry Andric if (!MR) 23390b57cec5SDimitry Andric continue; 23400b57cec5SDimitry Andric 23410b57cec5SDimitry Andric SVal StrVal = C.getSVal(Init); 23420b57cec5SDimitry Andric assert(StrVal.isValid() && "Initializer string is unknown or undefined"); 23430b57cec5SDimitry Andric DefinedOrUnknownSVal strLength = 23440b57cec5SDimitry Andric getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>(); 23450b57cec5SDimitry Andric 23460b57cec5SDimitry Andric state = state->set<CStringLength>(MR, strLength); 23470b57cec5SDimitry Andric } 23480b57cec5SDimitry Andric 23490b57cec5SDimitry Andric C.addTransition(state); 23500b57cec5SDimitry Andric } 23510b57cec5SDimitry Andric 23520b57cec5SDimitry Andric ProgramStateRef 23530b57cec5SDimitry Andric CStringChecker::checkRegionChanges(ProgramStateRef state, 23540b57cec5SDimitry Andric const InvalidatedSymbols *, 23550b57cec5SDimitry Andric ArrayRef<const MemRegion *> ExplicitRegions, 23560b57cec5SDimitry Andric ArrayRef<const MemRegion *> Regions, 23570b57cec5SDimitry Andric const LocationContext *LCtx, 23580b57cec5SDimitry Andric const CallEvent *Call) const { 23590b57cec5SDimitry Andric CStringLengthTy Entries = state->get<CStringLength>(); 23600b57cec5SDimitry Andric if (Entries.isEmpty()) 23610b57cec5SDimitry Andric return state; 23620b57cec5SDimitry Andric 23630b57cec5SDimitry Andric llvm::SmallPtrSet<const MemRegion *, 8> Invalidated; 23640b57cec5SDimitry Andric llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions; 23650b57cec5SDimitry Andric 23660b57cec5SDimitry Andric // First build sets for the changed regions and their super-regions. 23670b57cec5SDimitry Andric for (ArrayRef<const MemRegion *>::iterator 23680b57cec5SDimitry Andric I = Regions.begin(), E = Regions.end(); I != E; ++I) { 23690b57cec5SDimitry Andric const MemRegion *MR = *I; 23700b57cec5SDimitry Andric Invalidated.insert(MR); 23710b57cec5SDimitry Andric 23720b57cec5SDimitry Andric SuperRegions.insert(MR); 23730b57cec5SDimitry Andric while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) { 23740b57cec5SDimitry Andric MR = SR->getSuperRegion(); 23750b57cec5SDimitry Andric SuperRegions.insert(MR); 23760b57cec5SDimitry Andric } 23770b57cec5SDimitry Andric } 23780b57cec5SDimitry Andric 23790b57cec5SDimitry Andric CStringLengthTy::Factory &F = state->get_context<CStringLength>(); 23800b57cec5SDimitry Andric 23810b57cec5SDimitry Andric // Then loop over the entries in the current state. 23820b57cec5SDimitry Andric for (CStringLengthTy::iterator I = Entries.begin(), 23830b57cec5SDimitry Andric E = Entries.end(); I != E; ++I) { 23840b57cec5SDimitry Andric const MemRegion *MR = I.getKey(); 23850b57cec5SDimitry Andric 23860b57cec5SDimitry Andric // Is this entry for a super-region of a changed region? 23870b57cec5SDimitry Andric if (SuperRegions.count(MR)) { 23880b57cec5SDimitry Andric Entries = F.remove(Entries, MR); 23890b57cec5SDimitry Andric continue; 23900b57cec5SDimitry Andric } 23910b57cec5SDimitry Andric 23920b57cec5SDimitry Andric // Is this entry for a sub-region of a changed region? 23930b57cec5SDimitry Andric const MemRegion *Super = MR; 23940b57cec5SDimitry Andric while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) { 23950b57cec5SDimitry Andric Super = SR->getSuperRegion(); 23960b57cec5SDimitry Andric if (Invalidated.count(Super)) { 23970b57cec5SDimitry Andric Entries = F.remove(Entries, MR); 23980b57cec5SDimitry Andric break; 23990b57cec5SDimitry Andric } 24000b57cec5SDimitry Andric } 24010b57cec5SDimitry Andric } 24020b57cec5SDimitry Andric 24030b57cec5SDimitry Andric return state->set<CStringLength>(Entries); 24040b57cec5SDimitry Andric } 24050b57cec5SDimitry Andric 24060b57cec5SDimitry Andric void CStringChecker::checkLiveSymbols(ProgramStateRef state, 24070b57cec5SDimitry Andric SymbolReaper &SR) const { 24080b57cec5SDimitry Andric // Mark all symbols in our string length map as valid. 24090b57cec5SDimitry Andric CStringLengthTy Entries = state->get<CStringLength>(); 24100b57cec5SDimitry Andric 24110b57cec5SDimitry Andric for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); 24120b57cec5SDimitry Andric I != E; ++I) { 24130b57cec5SDimitry Andric SVal Len = I.getData(); 24140b57cec5SDimitry Andric 24150b57cec5SDimitry Andric for (SymExpr::symbol_iterator si = Len.symbol_begin(), 24160b57cec5SDimitry Andric se = Len.symbol_end(); si != se; ++si) 24170b57cec5SDimitry Andric SR.markInUse(*si); 24180b57cec5SDimitry Andric } 24190b57cec5SDimitry Andric } 24200b57cec5SDimitry Andric 24210b57cec5SDimitry Andric void CStringChecker::checkDeadSymbols(SymbolReaper &SR, 24220b57cec5SDimitry Andric CheckerContext &C) const { 24230b57cec5SDimitry Andric ProgramStateRef state = C.getState(); 24240b57cec5SDimitry Andric CStringLengthTy Entries = state->get<CStringLength>(); 24250b57cec5SDimitry Andric if (Entries.isEmpty()) 24260b57cec5SDimitry Andric return; 24270b57cec5SDimitry Andric 24280b57cec5SDimitry Andric CStringLengthTy::Factory &F = state->get_context<CStringLength>(); 24290b57cec5SDimitry Andric for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); 24300b57cec5SDimitry Andric I != E; ++I) { 24310b57cec5SDimitry Andric SVal Len = I.getData(); 24320b57cec5SDimitry Andric if (SymbolRef Sym = Len.getAsSymbol()) { 24330b57cec5SDimitry Andric if (SR.isDead(Sym)) 24340b57cec5SDimitry Andric Entries = F.remove(Entries, I.getKey()); 24350b57cec5SDimitry Andric } 24360b57cec5SDimitry Andric } 24370b57cec5SDimitry Andric 24380b57cec5SDimitry Andric state = state->set<CStringLength>(Entries); 24390b57cec5SDimitry Andric C.addTransition(state); 24400b57cec5SDimitry Andric } 24410b57cec5SDimitry Andric 24420b57cec5SDimitry Andric void ento::registerCStringModeling(CheckerManager &Mgr) { 24430b57cec5SDimitry Andric Mgr.registerChecker<CStringChecker>(); 24440b57cec5SDimitry Andric } 24450b57cec5SDimitry Andric 24465ffd83dbSDimitry Andric bool ento::shouldRegisterCStringModeling(const CheckerManager &mgr) { 24470b57cec5SDimitry Andric return true; 24480b57cec5SDimitry Andric } 24490b57cec5SDimitry Andric 24500b57cec5SDimitry Andric #define REGISTER_CHECKER(name) \ 24510b57cec5SDimitry Andric void ento::register##name(CheckerManager &mgr) { \ 24520b57cec5SDimitry Andric CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ 24530b57cec5SDimitry Andric checker->Filter.Check##name = true; \ 2454a7dea167SDimitry Andric checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ 24550b57cec5SDimitry Andric } \ 24560b57cec5SDimitry Andric \ 24575ffd83dbSDimitry Andric bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; } 24580b57cec5SDimitry Andric 24590b57cec5SDimitry Andric REGISTER_CHECKER(CStringNullArg) 24600b57cec5SDimitry Andric REGISTER_CHECKER(CStringOutOfBounds) 24610b57cec5SDimitry Andric REGISTER_CHECKER(CStringBufferOverlap) 24620b57cec5SDimitry Andric REGISTER_CHECKER(CStringNotNullTerm) 2463