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