1226633Sdim//= CStringChecker.cpp - Checks calls to C string functions --------*- C++ -*-// 2218887Sdim// 3218887Sdim// The LLVM Compiler Infrastructure 4218887Sdim// 5218887Sdim// This file is distributed under the University of Illinois Open Source 6218887Sdim// License. See LICENSE.TXT for details. 7218887Sdim// 8218887Sdim//===----------------------------------------------------------------------===// 9218887Sdim// 10218887Sdim// This defines CStringChecker, which is an assortment of checks on calls 11218887Sdim// to functions in <string.h>. 12218887Sdim// 13218887Sdim//===----------------------------------------------------------------------===// 14218887Sdim 15218887Sdim#include "ClangSACheckers.h" 16234353Sdim#include "InterCheckerAPI.h" 17249423Sdim#include "clang/Basic/CharInfo.h" 18249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 19221345Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 20218887Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 21219077Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 22226633Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 23249423Sdim#include "llvm/ADT/STLExtras.h" 24234353Sdim#include "llvm/ADT/SmallString.h" 25218887Sdim#include "llvm/ADT/StringSwitch.h" 26249423Sdim#include "llvm/Support/raw_ostream.h" 27218887Sdim 28218887Sdimusing namespace clang; 29218887Sdimusing namespace ento; 30218887Sdim 31218887Sdimnamespace { 32221345Sdimclass CStringChecker : public Checker< eval::Call, 33219077Sdim check::PreStmt<DeclStmt>, 34219077Sdim check::LiveSymbols, 35219077Sdim check::DeadSymbols, 36219077Sdim check::RegionChanges 37219077Sdim > { 38234353Sdim mutable OwningPtr<BugType> BT_Null, 39234353Sdim BT_Bounds, 40234353Sdim BT_Overlap, 41234353Sdim BT_NotCString, 42234353Sdim BT_AdditionOverflow; 43234353Sdim 44224145Sdim mutable const char *CurrentFunctionDescription; 45224145Sdim 46218887Sdimpublic: 47234353Sdim /// The filter is used to filter out the diagnostics which are not enabled by 48234353Sdim /// the user. 49234353Sdim struct CStringChecksFilter { 50234353Sdim DefaultBool CheckCStringNullArg; 51234353Sdim DefaultBool CheckCStringOutOfBounds; 52234353Sdim DefaultBool CheckCStringBufferOverlap; 53234353Sdim DefaultBool CheckCStringNotNullTerm; 54234353Sdim }; 55234353Sdim 56234353Sdim CStringChecksFilter Filter; 57234353Sdim 58218887Sdim static void *getTag() { static int tag; return &tag; } 59218887Sdim 60219077Sdim bool evalCall(const CallExpr *CE, CheckerContext &C) const; 61219077Sdim void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 62234353Sdim void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const; 63219077Sdim void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 64234353Sdim bool wantsRegionChangeUpdate(ProgramStateRef state) const; 65218887Sdim 66234353Sdim ProgramStateRef 67234353Sdim checkRegionChanges(ProgramStateRef state, 68249423Sdim const InvalidatedSymbols *, 69226633Sdim ArrayRef<const MemRegion *> ExplicitRegions, 70234353Sdim ArrayRef<const MemRegion *> Regions, 71239462Sdim const CallEvent *Call) const; 72218887Sdim 73219077Sdim typedef void (CStringChecker::*FnCheck)(CheckerContext &, 74219077Sdim const CallExpr *) const; 75218887Sdim 76219077Sdim void evalMemcpy(CheckerContext &C, const CallExpr *CE) const; 77221345Sdim void evalMempcpy(CheckerContext &C, const CallExpr *CE) const; 78219077Sdim void evalMemmove(CheckerContext &C, const CallExpr *CE) const; 79219077Sdim void evalBcopy(CheckerContext &C, const CallExpr *CE) const; 80221345Sdim void evalCopyCommon(CheckerContext &C, const CallExpr *CE, 81234353Sdim ProgramStateRef state, 82226633Sdim const Expr *Size, 83226633Sdim const Expr *Source, 84226633Sdim const Expr *Dest, 85221345Sdim bool Restricted = false, 86221345Sdim bool IsMempcpy = false) const; 87218887Sdim 88219077Sdim void evalMemcmp(CheckerContext &C, const CallExpr *CE) const; 89218887Sdim 90219077Sdim void evalstrLength(CheckerContext &C, const CallExpr *CE) const; 91219077Sdim void evalstrnLength(CheckerContext &C, const CallExpr *CE) const; 92226633Sdim void evalstrLengthCommon(CheckerContext &C, 93226633Sdim const CallExpr *CE, 94219077Sdim bool IsStrnlen = false) const; 95218887Sdim 96219077Sdim void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; 97219077Sdim void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; 98219077Sdim void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; 99226633Sdim void evalStrcpyCommon(CheckerContext &C, 100226633Sdim const CallExpr *CE, 101226633Sdim bool returnEnd, 102226633Sdim bool isBounded, 103226633Sdim bool isAppending) const; 104218887Sdim 105221345Sdim void evalStrcat(CheckerContext &C, const CallExpr *CE) const; 106221345Sdim void evalStrncat(CheckerContext &C, const CallExpr *CE) const; 107221345Sdim 108221345Sdim void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; 109221345Sdim void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; 110221345Sdim void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; 111223017Sdim void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; 112226633Sdim void evalStrcmpCommon(CheckerContext &C, 113226633Sdim const CallExpr *CE, 114226633Sdim bool isBounded = false, 115226633Sdim bool ignoreCase = false) const; 116221345Sdim 117251662Sdim void evalStrsep(CheckerContext &C, const CallExpr *CE) const; 118251662Sdim 119218887Sdim // Utility methods 120234353Sdim std::pair<ProgramStateRef , ProgramStateRef > 121219077Sdim static assumeZero(CheckerContext &C, 122234353Sdim ProgramStateRef state, SVal V, QualType Ty); 123218887Sdim 124234353Sdim static ProgramStateRef setCStringLength(ProgramStateRef state, 125226633Sdim const MemRegion *MR, 126226633Sdim SVal strLength); 127219077Sdim static SVal getCStringLengthForRegion(CheckerContext &C, 128234353Sdim ProgramStateRef &state, 129226633Sdim const Expr *Ex, 130226633Sdim const MemRegion *MR, 131224145Sdim bool hypothetical); 132226633Sdim SVal getCStringLength(CheckerContext &C, 133234353Sdim ProgramStateRef &state, 134226633Sdim const Expr *Ex, 135226633Sdim SVal Buf, 136224145Sdim bool hypothetical = false) const; 137218887Sdim 138221345Sdim const StringLiteral *getCStringLiteral(CheckerContext &C, 139234353Sdim ProgramStateRef &state, 140221345Sdim const Expr *expr, 141221345Sdim SVal val) const; 142221345Sdim 143234353Sdim static ProgramStateRef InvalidateBuffer(CheckerContext &C, 144263508Sdim ProgramStateRef state, 145263508Sdim const Expr *Ex, SVal V, 146263508Sdim bool IsSourceBuffer); 147218887Sdim 148226633Sdim static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, 149219077Sdim const MemRegion *MR); 150218887Sdim 151218887Sdim // Re-usable checks 152234353Sdim ProgramStateRef checkNonNull(CheckerContext &C, 153234353Sdim ProgramStateRef state, 154226633Sdim const Expr *S, 155226633Sdim SVal l) const; 156234353Sdim ProgramStateRef CheckLocation(CheckerContext &C, 157234353Sdim ProgramStateRef state, 158226633Sdim const Expr *S, 159226633Sdim SVal l, 160226633Sdim const char *message = NULL) const; 161234353Sdim ProgramStateRef CheckBufferAccess(CheckerContext &C, 162234353Sdim ProgramStateRef state, 163226633Sdim const Expr *Size, 164226633Sdim const Expr *FirstBuf, 165226633Sdim const Expr *SecondBuf, 166226633Sdim const char *firstMessage = NULL, 167226633Sdim const char *secondMessage = NULL, 168226633Sdim bool WarnAboutSize = false) const; 169226633Sdim 170234353Sdim ProgramStateRef CheckBufferAccess(CheckerContext &C, 171234353Sdim ProgramStateRef state, 172226633Sdim const Expr *Size, 173226633Sdim const Expr *Buf, 174226633Sdim const char *message = NULL, 175226633Sdim bool WarnAboutSize = false) const { 176224145Sdim // This is a convenience override. 177224145Sdim return CheckBufferAccess(C, state, Size, Buf, NULL, message, NULL, 178224145Sdim WarnAboutSize); 179224145Sdim } 180234353Sdim ProgramStateRef CheckOverlap(CheckerContext &C, 181234353Sdim ProgramStateRef state, 182226633Sdim const Expr *Size, 183226633Sdim const Expr *First, 184226633Sdim const Expr *Second) const; 185226633Sdim void emitOverlapBug(CheckerContext &C, 186234353Sdim ProgramStateRef state, 187226633Sdim const Stmt *First, 188226633Sdim const Stmt *Second) const; 189226633Sdim 190234353Sdim ProgramStateRef checkAdditionOverflow(CheckerContext &C, 191234353Sdim ProgramStateRef state, 192226633Sdim NonLoc left, 193226633Sdim NonLoc right) const; 194218887Sdim}; 195218887Sdim 196218887Sdim} //end anonymous namespace 197218887Sdim 198243830SdimREGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal) 199218887Sdim 200218887Sdim//===----------------------------------------------------------------------===// 201218887Sdim// Individual checks and utility methods. 202218887Sdim//===----------------------------------------------------------------------===// 203218887Sdim 204234353Sdimstd::pair<ProgramStateRef , ProgramStateRef > 205234353SdimCStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V, 206218887Sdim QualType Ty) { 207249423Sdim Optional<DefinedSVal> val = V.getAs<DefinedSVal>(); 208218887Sdim if (!val) 209234353Sdim return std::pair<ProgramStateRef , ProgramStateRef >(state, state); 210218887Sdim 211218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 212218887Sdim DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty); 213218887Sdim return state->assume(svalBuilder.evalEQ(state, *val, zero)); 214218887Sdim} 215218887Sdim 216234353SdimProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, 217234353Sdim ProgramStateRef state, 218219077Sdim const Expr *S, SVal l) const { 219218887Sdim // If a previous check has failed, propagate the failure. 220218887Sdim if (!state) 221218887Sdim return NULL; 222218887Sdim 223234353Sdim ProgramStateRef stateNull, stateNonNull; 224218887Sdim llvm::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType()); 225218887Sdim 226218887Sdim if (stateNull && !stateNonNull) { 227234353Sdim if (!Filter.CheckCStringNullArg) 228234353Sdim return NULL; 229234353Sdim 230218887Sdim ExplodedNode *N = C.generateSink(stateNull); 231218887Sdim if (!N) 232218887Sdim return NULL; 233218887Sdim 234218887Sdim if (!BT_Null) 235263508Sdim BT_Null.reset(new BuiltinBug(categories::UnixAPI, 236219077Sdim "Null pointer argument in call to byte string function")); 237218887Sdim 238234353Sdim SmallString<80> buf; 239224145Sdim llvm::raw_svector_ostream os(buf); 240224145Sdim assert(CurrentFunctionDescription); 241224145Sdim os << "Null pointer argument in call to " << CurrentFunctionDescription; 242224145Sdim 243218887Sdim // Generate a report for this bug. 244219077Sdim BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null.get()); 245226633Sdim BugReport *report = new BugReport(*BT, os.str(), N); 246218887Sdim 247218887Sdim report->addRange(S->getSourceRange()); 248243830Sdim bugreporter::trackNullOrUndefValue(N, S, *report); 249243830Sdim C.emitReport(report); 250218887Sdim return NULL; 251218887Sdim } 252218887Sdim 253218887Sdim // From here on, assume that the value is non-null. 254218887Sdim assert(stateNonNull); 255218887Sdim return stateNonNull; 256218887Sdim} 257218887Sdim 258218887Sdim// FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor? 259234353SdimProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, 260234353Sdim ProgramStateRef state, 261218887Sdim const Expr *S, SVal l, 262224145Sdim const char *warningMsg) const { 263218887Sdim // If a previous check has failed, propagate the failure. 264218887Sdim if (!state) 265218887Sdim return NULL; 266218887Sdim 267218887Sdim // Check for out of bound array element access. 268218887Sdim const MemRegion *R = l.getAsRegion(); 269218887Sdim if (!R) 270218887Sdim return state; 271218887Sdim 272218887Sdim const ElementRegion *ER = dyn_cast<ElementRegion>(R); 273218887Sdim if (!ER) 274218887Sdim return state; 275218887Sdim 276218887Sdim assert(ER->getValueType() == C.getASTContext().CharTy && 277218887Sdim "CheckLocation should only be called with char* ElementRegions"); 278218887Sdim 279218887Sdim // Get the size of the array. 280218887Sdim const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); 281218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 282224145Sdim SVal Extent = 283224145Sdim svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); 284249423Sdim DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>(); 285218887Sdim 286218887Sdim // Get the index of the accessed element. 287249423Sdim DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 288218887Sdim 289234353Sdim ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true); 290234353Sdim ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false); 291218887Sdim if (StOutBound && !StInBound) { 292218887Sdim ExplodedNode *N = C.generateSink(StOutBound); 293218887Sdim if (!N) 294218887Sdim return NULL; 295218887Sdim 296224145Sdim if (!BT_Bounds) { 297224145Sdim BT_Bounds.reset(new BuiltinBug("Out-of-bound array access", 298224145Sdim "Byte string function accesses out-of-bound array element")); 299224145Sdim } 300224145Sdim BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Bounds.get()); 301224145Sdim 302224145Sdim // Generate a report for this bug. 303226633Sdim BugReport *report; 304224145Sdim if (warningMsg) { 305226633Sdim report = new BugReport(*BT, warningMsg, N); 306218887Sdim } else { 307224145Sdim assert(CurrentFunctionDescription); 308224145Sdim assert(CurrentFunctionDescription[0] != '\0'); 309224145Sdim 310234353Sdim SmallString<80> buf; 311224145Sdim llvm::raw_svector_ostream os(buf); 312249423Sdim os << toUppercase(CurrentFunctionDescription[0]) 313224145Sdim << &CurrentFunctionDescription[1] 314224145Sdim << " accesses out-of-bound array element"; 315226633Sdim report = new BugReport(*BT, os.str(), N); 316218887Sdim } 317218887Sdim 318218887Sdim // FIXME: It would be nice to eventually make this diagnostic more clear, 319218887Sdim // e.g., by referencing the original declaration or by saying *why* this 320218887Sdim // reference is outside the range. 321218887Sdim 322218887Sdim report->addRange(S->getSourceRange()); 323243830Sdim C.emitReport(report); 324218887Sdim return NULL; 325218887Sdim } 326218887Sdim 327218887Sdim // Array bound check succeeded. From this point forward the array bound 328218887Sdim // should always succeed. 329218887Sdim return StInBound; 330218887Sdim} 331218887Sdim 332234353SdimProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, 333234353Sdim ProgramStateRef state, 334218887Sdim const Expr *Size, 335218887Sdim const Expr *FirstBuf, 336218887Sdim const Expr *SecondBuf, 337224145Sdim const char *firstMessage, 338224145Sdim const char *secondMessage, 339224145Sdim bool WarnAboutSize) const { 340218887Sdim // If a previous check has failed, propagate the failure. 341218887Sdim if (!state) 342218887Sdim return NULL; 343218887Sdim 344218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 345224145Sdim ASTContext &Ctx = svalBuilder.getContext(); 346234353Sdim const LocationContext *LCtx = C.getLocationContext(); 347218887Sdim 348218887Sdim QualType sizeTy = Size->getType(); 349218887Sdim QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); 350218887Sdim 351218887Sdim // Check that the first buffer is non-null. 352234353Sdim SVal BufVal = state->getSVal(FirstBuf, LCtx); 353218887Sdim state = checkNonNull(C, state, FirstBuf, BufVal); 354218887Sdim if (!state) 355218887Sdim return NULL; 356218887Sdim 357234353Sdim // If out-of-bounds checking is turned off, skip the rest. 358234353Sdim if (!Filter.CheckCStringOutOfBounds) 359234353Sdim return state; 360234353Sdim 361218887Sdim // Get the access length and make sure it is known. 362224145Sdim // FIXME: This assumes the caller has already checked that the access length 363224145Sdim // is positive. And that it's unsigned. 364234353Sdim SVal LengthVal = state->getSVal(Size, LCtx); 365249423Sdim Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 366218887Sdim if (!Length) 367218887Sdim return state; 368218887Sdim 369218887Sdim // Compute the offset of the last element to be accessed: size-1. 370249423Sdim NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 371249423Sdim NonLoc LastOffset = svalBuilder 372249423Sdim .evalBinOpNN(state, BO_Sub, *Length, One, sizeTy).castAs<NonLoc>(); 373218887Sdim 374221345Sdim // Check that the first buffer is sufficiently long. 375218887Sdim SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); 376249423Sdim if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { 377224145Sdim const Expr *warningExpr = (WarnAboutSize ? Size : FirstBuf); 378224145Sdim 379218887Sdim SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, 380218887Sdim LastOffset, PtrTy); 381224145Sdim state = CheckLocation(C, state, warningExpr, BufEnd, firstMessage); 382218887Sdim 383218887Sdim // If the buffer isn't large enough, abort. 384218887Sdim if (!state) 385218887Sdim return NULL; 386218887Sdim } 387218887Sdim 388218887Sdim // If there's a second buffer, check it as well. 389218887Sdim if (SecondBuf) { 390234353Sdim BufVal = state->getSVal(SecondBuf, LCtx); 391218887Sdim state = checkNonNull(C, state, SecondBuf, BufVal); 392218887Sdim if (!state) 393218887Sdim return NULL; 394218887Sdim 395218887Sdim BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType()); 396249423Sdim if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { 397224145Sdim const Expr *warningExpr = (WarnAboutSize ? Size : SecondBuf); 398224145Sdim 399218887Sdim SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, 400218887Sdim LastOffset, PtrTy); 401224145Sdim state = CheckLocation(C, state, warningExpr, BufEnd, secondMessage); 402218887Sdim } 403218887Sdim } 404218887Sdim 405218887Sdim // Large enough or not, return this state! 406218887Sdim return state; 407218887Sdim} 408218887Sdim 409234353SdimProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, 410234353Sdim ProgramStateRef state, 411218887Sdim const Expr *Size, 412218887Sdim const Expr *First, 413219077Sdim const Expr *Second) const { 414234353Sdim if (!Filter.CheckCStringBufferOverlap) 415234353Sdim return state; 416234353Sdim 417218887Sdim // Do a simple check for overlap: if the two arguments are from the same 418218887Sdim // buffer, see if the end of the first is greater than the start of the second 419218887Sdim // or vice versa. 420218887Sdim 421218887Sdim // If a previous check has failed, propagate the failure. 422218887Sdim if (!state) 423218887Sdim return NULL; 424218887Sdim 425234353Sdim ProgramStateRef stateTrue, stateFalse; 426218887Sdim 427218887Sdim // Get the buffer values and make sure they're known locations. 428234353Sdim const LocationContext *LCtx = C.getLocationContext(); 429234353Sdim SVal firstVal = state->getSVal(First, LCtx); 430234353Sdim SVal secondVal = state->getSVal(Second, LCtx); 431218887Sdim 432249423Sdim Optional<Loc> firstLoc = firstVal.getAs<Loc>(); 433218887Sdim if (!firstLoc) 434218887Sdim return state; 435218887Sdim 436249423Sdim Optional<Loc> secondLoc = secondVal.getAs<Loc>(); 437218887Sdim if (!secondLoc) 438218887Sdim return state; 439218887Sdim 440218887Sdim // Are the two values the same? 441218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 442218887Sdim llvm::tie(stateTrue, stateFalse) = 443218887Sdim state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc)); 444218887Sdim 445218887Sdim if (stateTrue && !stateFalse) { 446218887Sdim // If the values are known to be equal, that's automatically an overlap. 447218887Sdim emitOverlapBug(C, stateTrue, First, Second); 448218887Sdim return NULL; 449218887Sdim } 450218887Sdim 451218887Sdim // assume the two expressions are not equal. 452218887Sdim assert(stateFalse); 453218887Sdim state = stateFalse; 454218887Sdim 455218887Sdim // Which value comes first? 456224145Sdim QualType cmpTy = svalBuilder.getConditionType(); 457218887Sdim SVal reverse = svalBuilder.evalBinOpLL(state, BO_GT, 458218887Sdim *firstLoc, *secondLoc, cmpTy); 459249423Sdim Optional<DefinedOrUnknownSVal> reverseTest = 460249423Sdim reverse.getAs<DefinedOrUnknownSVal>(); 461218887Sdim if (!reverseTest) 462218887Sdim return state; 463218887Sdim 464218887Sdim llvm::tie(stateTrue, stateFalse) = state->assume(*reverseTest); 465218887Sdim if (stateTrue) { 466218887Sdim if (stateFalse) { 467218887Sdim // If we don't know which one comes first, we can't perform this test. 468218887Sdim return state; 469218887Sdim } else { 470218887Sdim // Switch the values so that firstVal is before secondVal. 471249423Sdim std::swap(firstLoc, secondLoc); 472218887Sdim 473218887Sdim // Switch the Exprs as well, so that they still correspond. 474249423Sdim std::swap(First, Second); 475218887Sdim } 476218887Sdim } 477218887Sdim 478218887Sdim // Get the length, and make sure it too is known. 479234353Sdim SVal LengthVal = state->getSVal(Size, LCtx); 480249423Sdim Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 481218887Sdim if (!Length) 482218887Sdim return state; 483218887Sdim 484218887Sdim // Convert the first buffer's start address to char*. 485218887Sdim // Bail out if the cast fails. 486224145Sdim ASTContext &Ctx = svalBuilder.getContext(); 487218887Sdim QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); 488224145Sdim SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy, 489224145Sdim First->getType()); 490249423Sdim Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>(); 491218887Sdim if (!FirstStartLoc) 492218887Sdim return state; 493218887Sdim 494218887Sdim // Compute the end of the first buffer. Bail out if THAT fails. 495218887Sdim SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, 496218887Sdim *FirstStartLoc, *Length, CharPtrTy); 497249423Sdim Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>(); 498218887Sdim if (!FirstEndLoc) 499218887Sdim return state; 500218887Sdim 501218887Sdim // Is the end of the first buffer past the start of the second buffer? 502218887Sdim SVal Overlap = svalBuilder.evalBinOpLL(state, BO_GT, 503218887Sdim *FirstEndLoc, *secondLoc, cmpTy); 504249423Sdim Optional<DefinedOrUnknownSVal> OverlapTest = 505249423Sdim Overlap.getAs<DefinedOrUnknownSVal>(); 506218887Sdim if (!OverlapTest) 507218887Sdim return state; 508218887Sdim 509218887Sdim llvm::tie(stateTrue, stateFalse) = state->assume(*OverlapTest); 510218887Sdim 511218887Sdim if (stateTrue && !stateFalse) { 512218887Sdim // Overlap! 513218887Sdim emitOverlapBug(C, stateTrue, First, Second); 514218887Sdim return NULL; 515218887Sdim } 516218887Sdim 517218887Sdim // assume the two expressions don't overlap. 518218887Sdim assert(stateFalse); 519218887Sdim return stateFalse; 520218887Sdim} 521218887Sdim 522234353Sdimvoid CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, 523219077Sdim const Stmt *First, const Stmt *Second) const { 524218887Sdim ExplodedNode *N = C.generateSink(state); 525218887Sdim if (!N) 526218887Sdim return; 527218887Sdim 528218887Sdim if (!BT_Overlap) 529263508Sdim BT_Overlap.reset(new BugType(categories::UnixAPI, "Improper arguments")); 530218887Sdim 531218887Sdim // Generate a report for this bug. 532226633Sdim BugReport *report = 533226633Sdim new BugReport(*BT_Overlap, 534218887Sdim "Arguments must not be overlapping buffers", N); 535218887Sdim report->addRange(First->getSourceRange()); 536218887Sdim report->addRange(Second->getSourceRange()); 537218887Sdim 538243830Sdim C.emitReport(report); 539218887Sdim} 540218887Sdim 541234353SdimProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, 542234353Sdim ProgramStateRef state, 543224145Sdim NonLoc left, 544224145Sdim NonLoc right) const { 545234353Sdim // If out-of-bounds checking is turned off, skip the rest. 546234353Sdim if (!Filter.CheckCStringOutOfBounds) 547234353Sdim return state; 548234353Sdim 549224145Sdim // If a previous check has failed, propagate the failure. 550224145Sdim if (!state) 551224145Sdim return NULL; 552224145Sdim 553224145Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 554224145Sdim BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); 555224145Sdim 556224145Sdim QualType sizeTy = svalBuilder.getContext().getSizeType(); 557224145Sdim const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); 558224145Sdim NonLoc maxVal = svalBuilder.makeIntVal(maxValInt); 559224145Sdim 560234353Sdim SVal maxMinusRight; 561249423Sdim if (right.getAs<nonloc::ConcreteInt>()) { 562234353Sdim maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right, 563234353Sdim sizeTy); 564234353Sdim } else { 565224145Sdim // Try switching the operands. (The order of these two assignments is 566224145Sdim // important!) 567224145Sdim maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left, 568224145Sdim sizeTy); 569224145Sdim left = right; 570224145Sdim } 571224145Sdim 572249423Sdim if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) { 573224145Sdim QualType cmpTy = svalBuilder.getConditionType(); 574224145Sdim // If left > max - right, we have an overflow. 575224145Sdim SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left, 576224145Sdim *maxMinusRightNL, cmpTy); 577224145Sdim 578234353Sdim ProgramStateRef stateOverflow, stateOkay; 579224145Sdim llvm::tie(stateOverflow, stateOkay) = 580249423Sdim state->assume(willOverflow.castAs<DefinedOrUnknownSVal>()); 581224145Sdim 582224145Sdim if (stateOverflow && !stateOkay) { 583224145Sdim // We have an overflow. Emit a bug report. 584224145Sdim ExplodedNode *N = C.generateSink(stateOverflow); 585224145Sdim if (!N) 586224145Sdim return NULL; 587224145Sdim 588224145Sdim if (!BT_AdditionOverflow) 589224145Sdim BT_AdditionOverflow.reset(new BuiltinBug("API", 590224145Sdim "Sum of expressions causes overflow")); 591224145Sdim 592224145Sdim // This isn't a great error message, but this should never occur in real 593224145Sdim // code anyway -- you'd have to create a buffer longer than a size_t can 594224145Sdim // represent, which is sort of a contradiction. 595224145Sdim const char *warning = 596224145Sdim "This expression will create a string whose length is too big to " 597224145Sdim "be represented as a size_t"; 598224145Sdim 599224145Sdim // Generate a report for this bug. 600224145Sdim BugReport *report = new BugReport(*BT_AdditionOverflow, warning, N); 601243830Sdim C.emitReport(report); 602224145Sdim 603224145Sdim return NULL; 604224145Sdim } 605224145Sdim 606224145Sdim // From now on, assume an overflow didn't occur. 607224145Sdim assert(stateOkay); 608224145Sdim state = stateOkay; 609224145Sdim } 610224145Sdim 611224145Sdim return state; 612224145Sdim} 613224145Sdim 614234353SdimProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state, 615218887Sdim const MemRegion *MR, 616218887Sdim SVal strLength) { 617218887Sdim assert(!strLength.isUndef() && "Attempt to set an undefined string length"); 618218887Sdim 619218887Sdim MR = MR->StripCasts(); 620218887Sdim 621218887Sdim switch (MR->getKind()) { 622218887Sdim case MemRegion::StringRegionKind: 623218887Sdim // FIXME: This can happen if we strcpy() into a string region. This is 624218887Sdim // undefined [C99 6.4.5p6], but we should still warn about it. 625218887Sdim return state; 626218887Sdim 627218887Sdim case MemRegion::SymbolicRegionKind: 628218887Sdim case MemRegion::AllocaRegionKind: 629218887Sdim case MemRegion::VarRegionKind: 630218887Sdim case MemRegion::FieldRegionKind: 631218887Sdim case MemRegion::ObjCIvarRegionKind: 632224145Sdim // These are the types we can currently track string lengths for. 633224145Sdim break; 634218887Sdim 635218887Sdim case MemRegion::ElementRegionKind: 636218887Sdim // FIXME: Handle element regions by upper-bounding the parent region's 637218887Sdim // string length. 638218887Sdim return state; 639218887Sdim 640218887Sdim default: 641218887Sdim // Other regions (mostly non-data) can't have a reliable C string length. 642218887Sdim // For now, just ignore the change. 643218887Sdim // FIXME: These are rare but not impossible. We should output some kind of 644218887Sdim // warning for things like strcpy((char[]){'a', 0}, "b"); 645218887Sdim return state; 646218887Sdim } 647224145Sdim 648224145Sdim if (strLength.isUnknown()) 649224145Sdim return state->remove<CStringLength>(MR); 650224145Sdim 651224145Sdim return state->set<CStringLength>(MR, strLength); 652218887Sdim} 653218887Sdim 654218887SdimSVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, 655234353Sdim ProgramStateRef &state, 656218887Sdim const Expr *Ex, 657224145Sdim const MemRegion *MR, 658224145Sdim bool hypothetical) { 659224145Sdim if (!hypothetical) { 660224145Sdim // If there's a recorded length, go ahead and return it. 661224145Sdim const SVal *Recorded = state->get<CStringLength>(MR); 662224145Sdim if (Recorded) 663224145Sdim return *Recorded; 664224145Sdim } 665263508Sdim 666218887Sdim // Otherwise, get a new symbol and update the state. 667218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 668218887Sdim QualType sizeTy = svalBuilder.getContext().getSizeType(); 669219077Sdim SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), 670243830Sdim MR, Ex, sizeTy, 671243830Sdim C.blockCount()); 672224145Sdim 673263508Sdim if (!hypothetical) { 674263508Sdim if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) { 675263508Sdim // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4 676263508Sdim BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); 677263508Sdim const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); 678263508Sdim llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4); 679263508Sdim const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt, 680263508Sdim fourInt); 681263508Sdim NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt); 682263508Sdim SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, 683263508Sdim maxLength, sizeTy); 684263508Sdim state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true); 685263508Sdim } 686224145Sdim state = state->set<CStringLength>(MR, strLength); 687263508Sdim } 688224145Sdim 689218887Sdim return strLength; 690218887Sdim} 691218887Sdim 692234353SdimSVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, 693224145Sdim const Expr *Ex, SVal Buf, 694224145Sdim bool hypothetical) const { 695218887Sdim const MemRegion *MR = Buf.getAsRegion(); 696218887Sdim if (!MR) { 697218887Sdim // If we can't get a region, see if it's something we /know/ isn't a 698218887Sdim // C string. In the context of locations, the only time we can issue such 699218887Sdim // a warning is for labels. 700249423Sdim if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) { 701234353Sdim if (!Filter.CheckCStringNotNullTerm) 702234353Sdim return UndefinedVal(); 703234353Sdim 704234353Sdim if (ExplodedNode *N = C.addTransition(state)) { 705218887Sdim if (!BT_NotCString) 706263508Sdim BT_NotCString.reset(new BuiltinBug(categories::UnixAPI, 707219077Sdim "Argument is not a null-terminated string.")); 708218887Sdim 709234353Sdim SmallString<120> buf; 710218887Sdim llvm::raw_svector_ostream os(buf); 711224145Sdim assert(CurrentFunctionDescription); 712224145Sdim os << "Argument to " << CurrentFunctionDescription 713224145Sdim << " is the address of the label '" << Label->getLabel()->getName() 714218887Sdim << "', which is not a null-terminated string"; 715218887Sdim 716218887Sdim // Generate a report for this bug. 717226633Sdim BugReport *report = new BugReport(*BT_NotCString, 718218887Sdim os.str(), N); 719218887Sdim 720218887Sdim report->addRange(Ex->getSourceRange()); 721243830Sdim C.emitReport(report); 722218887Sdim } 723234353Sdim return UndefinedVal(); 724218887Sdim 725218887Sdim } 726218887Sdim 727218887Sdim // If it's not a region and not a label, give up. 728218887Sdim return UnknownVal(); 729218887Sdim } 730218887Sdim 731218887Sdim // If we have a region, strip casts from it and see if we can figure out 732218887Sdim // its length. For anything we can't figure out, just return UnknownVal. 733218887Sdim MR = MR->StripCasts(); 734218887Sdim 735218887Sdim switch (MR->getKind()) { 736218887Sdim case MemRegion::StringRegionKind: { 737218887Sdim // Modifying the contents of string regions is undefined [C99 6.4.5p6], 738218887Sdim // so we can assume that the byte length is the correct C string length. 739218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 740218887Sdim QualType sizeTy = svalBuilder.getContext().getSizeType(); 741218887Sdim const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral(); 742218887Sdim return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy); 743218887Sdim } 744218887Sdim case MemRegion::SymbolicRegionKind: 745218887Sdim case MemRegion::AllocaRegionKind: 746218887Sdim case MemRegion::VarRegionKind: 747218887Sdim case MemRegion::FieldRegionKind: 748218887Sdim case MemRegion::ObjCIvarRegionKind: 749224145Sdim return getCStringLengthForRegion(C, state, Ex, MR, hypothetical); 750218887Sdim case MemRegion::CompoundLiteralRegionKind: 751218887Sdim // FIXME: Can we track this? Is it necessary? 752218887Sdim return UnknownVal(); 753218887Sdim case MemRegion::ElementRegionKind: 754218887Sdim // FIXME: How can we handle this? It's not good enough to subtract the 755218887Sdim // offset from the base string length; consider "123\x00567" and &a[5]. 756218887Sdim return UnknownVal(); 757218887Sdim default: 758218887Sdim // Other regions (mostly non-data) can't have a reliable C string length. 759218887Sdim // In this case, an error is emitted and UndefinedVal is returned. 760218887Sdim // The caller should always be prepared to handle this case. 761234353Sdim if (!Filter.CheckCStringNotNullTerm) 762234353Sdim return UndefinedVal(); 763234353Sdim 764234353Sdim if (ExplodedNode *N = C.addTransition(state)) { 765218887Sdim if (!BT_NotCString) 766263508Sdim BT_NotCString.reset(new BuiltinBug(categories::UnixAPI, 767219077Sdim "Argument is not a null-terminated string.")); 768218887Sdim 769234353Sdim SmallString<120> buf; 770218887Sdim llvm::raw_svector_ostream os(buf); 771218887Sdim 772224145Sdim assert(CurrentFunctionDescription); 773224145Sdim os << "Argument to " << CurrentFunctionDescription << " is "; 774218887Sdim 775218887Sdim if (SummarizeRegion(os, C.getASTContext(), MR)) 776218887Sdim os << ", which is not a null-terminated string"; 777218887Sdim else 778218887Sdim os << "not a null-terminated string"; 779218887Sdim 780218887Sdim // Generate a report for this bug. 781226633Sdim BugReport *report = new BugReport(*BT_NotCString, 782218887Sdim os.str(), N); 783218887Sdim 784218887Sdim report->addRange(Ex->getSourceRange()); 785243830Sdim C.emitReport(report); 786218887Sdim } 787218887Sdim 788218887Sdim return UndefinedVal(); 789218887Sdim } 790218887Sdim} 791218887Sdim 792221345Sdimconst StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, 793234353Sdim ProgramStateRef &state, const Expr *expr, SVal val) const { 794221345Sdim 795221345Sdim // Get the memory region pointed to by the val. 796221345Sdim const MemRegion *bufRegion = val.getAsRegion(); 797221345Sdim if (!bufRegion) 798221345Sdim return NULL; 799221345Sdim 800221345Sdim // Strip casts off the memory region. 801221345Sdim bufRegion = bufRegion->StripCasts(); 802221345Sdim 803221345Sdim // Cast the memory region to a string region. 804221345Sdim const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion); 805221345Sdim if (!strRegion) 806221345Sdim return NULL; 807221345Sdim 808221345Sdim // Return the actual string in the string region. 809221345Sdim return strRegion->getStringLiteral(); 810221345Sdim} 811221345Sdim 812234353SdimProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, 813263508Sdim ProgramStateRef state, 814263508Sdim const Expr *E, SVal V, 815263508Sdim bool IsSourceBuffer) { 816249423Sdim Optional<Loc> L = V.getAs<Loc>(); 817218887Sdim if (!L) 818218887Sdim return state; 819218887Sdim 820218887Sdim // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes 821218887Sdim // some assumptions about the value that CFRefCount can't. Even so, it should 822218887Sdim // probably be refactored. 823249423Sdim if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) { 824218887Sdim const MemRegion *R = MR->getRegion()->StripCasts(); 825218887Sdim 826218887Sdim // Are we dealing with an ElementRegion? If so, we should be invalidating 827218887Sdim // the super-region. 828218887Sdim if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { 829218887Sdim R = ER->getSuperRegion(); 830218887Sdim // FIXME: What about layers of ElementRegions? 831218887Sdim } 832218887Sdim 833218887Sdim // Invalidate this region. 834234353Sdim const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); 835263508Sdim 836263508Sdim bool CausesPointerEscape = false; 837263508Sdim RegionAndSymbolInvalidationTraits ITraits; 838263508Sdim // Invalidate and escape only indirect regions accessible through the source 839263508Sdim // buffer. 840263508Sdim if (IsSourceBuffer) { 841263508Sdim ITraits.setTrait(R, 842263508Sdim RegionAndSymbolInvalidationTraits::TK_PreserveContents); 843263508Sdim ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); 844263508Sdim CausesPointerEscape = true; 845263508Sdim } 846263508Sdim 847263508Sdim return state->invalidateRegions(R, E, C.blockCount(), LCtx, 848263508Sdim CausesPointerEscape, 0, 0, &ITraits); 849218887Sdim } 850218887Sdim 851218887Sdim // If we have a non-region value by chance, just remove the binding. 852218887Sdim // FIXME: is this necessary or correct? This handles the non-Region 853218887Sdim // cases. Is it ever valid to store to these? 854243830Sdim return state->killBinding(*L); 855218887Sdim} 856218887Sdim 857226633Sdimbool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, 858218887Sdim const MemRegion *MR) { 859226633Sdim const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR); 860218887Sdim 861226633Sdim switch (MR->getKind()) { 862218887Sdim case MemRegion::FunctionTextRegionKind: { 863243830Sdim const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); 864218887Sdim if (FD) 865226633Sdim os << "the address of the function '" << *FD << '\''; 866218887Sdim else 867218887Sdim os << "the address of a function"; 868218887Sdim return true; 869218887Sdim } 870218887Sdim case MemRegion::BlockTextRegionKind: 871218887Sdim os << "block text"; 872218887Sdim return true; 873218887Sdim case MemRegion::BlockDataRegionKind: 874218887Sdim os << "a block"; 875218887Sdim return true; 876218887Sdim case MemRegion::CXXThisRegionKind: 877218887Sdim case MemRegion::CXXTempObjectRegionKind: 878226633Sdim os << "a C++ temp object of type " << TVR->getValueType().getAsString(); 879218887Sdim return true; 880218887Sdim case MemRegion::VarRegionKind: 881226633Sdim os << "a variable of type" << TVR->getValueType().getAsString(); 882218887Sdim return true; 883218887Sdim case MemRegion::FieldRegionKind: 884226633Sdim os << "a field of type " << TVR->getValueType().getAsString(); 885218887Sdim return true; 886218887Sdim case MemRegion::ObjCIvarRegionKind: 887226633Sdim os << "an instance variable of type " << TVR->getValueType().getAsString(); 888218887Sdim return true; 889218887Sdim default: 890218887Sdim return false; 891218887Sdim } 892218887Sdim} 893218887Sdim 894218887Sdim//===----------------------------------------------------------------------===// 895218887Sdim// evaluation of individual function calls. 896218887Sdim//===----------------------------------------------------------------------===// 897218887Sdim 898221345Sdimvoid CStringChecker::evalCopyCommon(CheckerContext &C, 899221345Sdim const CallExpr *CE, 900234353Sdim ProgramStateRef state, 901218887Sdim const Expr *Size, const Expr *Dest, 902221345Sdim const Expr *Source, bool Restricted, 903221345Sdim bool IsMempcpy) const { 904224145Sdim CurrentFunctionDescription = "memory copy function"; 905224145Sdim 906218887Sdim // See if the size argument is zero. 907234353Sdim const LocationContext *LCtx = C.getLocationContext(); 908234353Sdim SVal sizeVal = state->getSVal(Size, LCtx); 909218887Sdim QualType sizeTy = Size->getType(); 910218887Sdim 911234353Sdim ProgramStateRef stateZeroSize, stateNonZeroSize; 912224145Sdim llvm::tie(stateZeroSize, stateNonZeroSize) = 913224145Sdim assumeZero(C, state, sizeVal, sizeTy); 914218887Sdim 915221345Sdim // Get the value of the Dest. 916234353Sdim SVal destVal = state->getSVal(Dest, LCtx); 917221345Sdim 918221345Sdim // If the size is zero, there won't be any actual memory access, so 919221345Sdim // just bind the return value to the destination buffer and return. 920239462Sdim if (stateZeroSize && !stateNonZeroSize) { 921234353Sdim stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal); 922218887Sdim C.addTransition(stateZeroSize); 923239462Sdim return; 924221345Sdim } 925218887Sdim 926218887Sdim // If the size can be nonzero, we have to check the other arguments. 927218887Sdim if (stateNonZeroSize) { 928223017Sdim state = stateNonZeroSize; 929221345Sdim 930221345Sdim // Ensure the destination is not null. If it is NULL there will be a 931221345Sdim // NULL pointer dereference. 932221345Sdim state = checkNonNull(C, state, Dest, destVal); 933221345Sdim if (!state) 934221345Sdim return; 935221345Sdim 936221345Sdim // Get the value of the Src. 937234353Sdim SVal srcVal = state->getSVal(Source, LCtx); 938221345Sdim 939221345Sdim // Ensure the source is not null. If it is NULL there will be a 940221345Sdim // NULL pointer dereference. 941221345Sdim state = checkNonNull(C, state, Source, srcVal); 942221345Sdim if (!state) 943221345Sdim return; 944221345Sdim 945223017Sdim // Ensure the accesses are valid and that the buffers do not overlap. 946224145Sdim const char * const writeWarning = 947224145Sdim "Memory copy function overflows destination buffer"; 948218887Sdim state = CheckBufferAccess(C, state, Size, Dest, Source, 949224145Sdim writeWarning, /* sourceWarning = */ NULL); 950218887Sdim if (Restricted) 951218887Sdim state = CheckOverlap(C, state, Size, Dest, Source); 952218887Sdim 953223017Sdim if (!state) 954223017Sdim return; 955221345Sdim 956223017Sdim // If this is mempcpy, get the byte after the last byte copied and 957223017Sdim // bind the expr. 958223017Sdim if (IsMempcpy) { 959249423Sdim loc::MemRegionVal destRegVal = destVal.castAs<loc::MemRegionVal>(); 960223017Sdim 961223017Sdim // Get the length to copy. 962249423Sdim if (Optional<NonLoc> lenValNonLoc = sizeVal.getAs<NonLoc>()) { 963221345Sdim // Get the byte after the last byte copied. 964221345Sdim SVal lastElement = C.getSValBuilder().evalBinOpLN(state, BO_Add, 965249423Sdim destRegVal, 966221345Sdim *lenValNonLoc, 967221345Sdim Dest->getType()); 968223017Sdim 969221345Sdim // The byte after the last byte copied is the return value. 970234353Sdim state = state->BindExpr(CE, LCtx, lastElement); 971223017Sdim } else { 972223017Sdim // If we don't know how much we copied, we can at least 973223017Sdim // conjure a return value for later. 974243830Sdim SVal result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, 975243830Sdim C.blockCount()); 976234353Sdim state = state->BindExpr(CE, LCtx, result); 977221345Sdim } 978221345Sdim 979223017Sdim } else { 980223017Sdim // All other copies return the destination buffer. 981223017Sdim // (Well, bcopy() has a void return type, but this won't hurt.) 982234353Sdim state = state->BindExpr(CE, LCtx, destVal); 983218887Sdim } 984223017Sdim 985263508Sdim // Invalidate the destination (regular invalidation without pointer-escaping 986263508Sdim // the address of the top-level region). 987223017Sdim // FIXME: Even if we can't perfectly model the copy, we should see if we 988223017Sdim // can use LazyCompoundVals to copy the source values into the destination. 989223017Sdim // This would probably remove any existing bindings past the end of the 990223017Sdim // copied region, but that's still an improvement over blank invalidation. 991263508Sdim state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest), 992263508Sdim /*IsSourceBuffer*/false); 993263508Sdim 994263508Sdim // Invalidate the source (const-invalidation without const-pointer-escaping 995263508Sdim // the address of the top-level region). 996263508Sdim state = InvalidateBuffer(C, state, Source, C.getSVal(Source), 997263508Sdim /*IsSourceBuffer*/true); 998263508Sdim 999223017Sdim C.addTransition(state); 1000218887Sdim } 1001218887Sdim} 1002218887Sdim 1003218887Sdim 1004219077Sdimvoid CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { 1005234353Sdim if (CE->getNumArgs() < 3) 1006234353Sdim return; 1007234353Sdim 1008218887Sdim // void *memcpy(void *restrict dst, const void *restrict src, size_t n); 1009218887Sdim // The return value is the address of the destination buffer. 1010218887Sdim const Expr *Dest = CE->getArg(0); 1011234353Sdim ProgramStateRef state = C.getState(); 1012223017Sdim 1013221345Sdim evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true); 1014218887Sdim} 1015218887Sdim 1016221345Sdimvoid CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { 1017234353Sdim if (CE->getNumArgs() < 3) 1018234353Sdim return; 1019234353Sdim 1020221345Sdim // void *mempcpy(void *restrict dst, const void *restrict src, size_t n); 1021221345Sdim // The return value is a pointer to the byte following the last written byte. 1022221345Sdim const Expr *Dest = CE->getArg(0); 1023234353Sdim ProgramStateRef state = C.getState(); 1024221345Sdim 1025221345Sdim evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true); 1026221345Sdim} 1027221345Sdim 1028219077Sdimvoid CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { 1029234353Sdim if (CE->getNumArgs() < 3) 1030234353Sdim return; 1031234353Sdim 1032218887Sdim // void *memmove(void *dst, const void *src, size_t n); 1033218887Sdim // The return value is the address of the destination buffer. 1034218887Sdim const Expr *Dest = CE->getArg(0); 1035234353Sdim ProgramStateRef state = C.getState(); 1036223017Sdim 1037221345Sdim evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1)); 1038218887Sdim} 1039218887Sdim 1040219077Sdimvoid CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { 1041234353Sdim if (CE->getNumArgs() < 3) 1042234353Sdim return; 1043234353Sdim 1044218887Sdim // void bcopy(const void *src, void *dst, size_t n); 1045221345Sdim evalCopyCommon(C, CE, C.getState(), 1046221345Sdim CE->getArg(2), CE->getArg(1), CE->getArg(0)); 1047218887Sdim} 1048218887Sdim 1049219077Sdimvoid CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { 1050234353Sdim if (CE->getNumArgs() < 3) 1051234353Sdim return; 1052234353Sdim 1053218887Sdim // int memcmp(const void *s1, const void *s2, size_t n); 1054224145Sdim CurrentFunctionDescription = "memory comparison function"; 1055224145Sdim 1056218887Sdim const Expr *Left = CE->getArg(0); 1057218887Sdim const Expr *Right = CE->getArg(1); 1058218887Sdim const Expr *Size = CE->getArg(2); 1059218887Sdim 1060234353Sdim ProgramStateRef state = C.getState(); 1061218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 1062218887Sdim 1063218887Sdim // See if the size argument is zero. 1064234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1065234353Sdim SVal sizeVal = state->getSVal(Size, LCtx); 1066218887Sdim QualType sizeTy = Size->getType(); 1067218887Sdim 1068234353Sdim ProgramStateRef stateZeroSize, stateNonZeroSize; 1069218887Sdim llvm::tie(stateZeroSize, stateNonZeroSize) = 1070218887Sdim assumeZero(C, state, sizeVal, sizeTy); 1071218887Sdim 1072218887Sdim // If the size can be zero, the result will be 0 in that case, and we don't 1073218887Sdim // have to check either of the buffers. 1074218887Sdim if (stateZeroSize) { 1075218887Sdim state = stateZeroSize; 1076234353Sdim state = state->BindExpr(CE, LCtx, 1077234353Sdim svalBuilder.makeZeroVal(CE->getType())); 1078218887Sdim C.addTransition(state); 1079218887Sdim } 1080218887Sdim 1081218887Sdim // If the size can be nonzero, we have to check the other arguments. 1082218887Sdim if (stateNonZeroSize) { 1083218887Sdim state = stateNonZeroSize; 1084218887Sdim // If we know the two buffers are the same, we know the result is 0. 1085218887Sdim // First, get the two buffers' addresses. Another checker will have already 1086218887Sdim // made sure they're not undefined. 1087234353Sdim DefinedOrUnknownSVal LV = 1088249423Sdim state->getSVal(Left, LCtx).castAs<DefinedOrUnknownSVal>(); 1089234353Sdim DefinedOrUnknownSVal RV = 1090249423Sdim state->getSVal(Right, LCtx).castAs<DefinedOrUnknownSVal>(); 1091218887Sdim 1092218887Sdim // See if they are the same. 1093218887Sdim DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); 1094234353Sdim ProgramStateRef StSameBuf, StNotSameBuf; 1095218887Sdim llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); 1096218887Sdim 1097224145Sdim // If the two arguments might be the same buffer, we know the result is 0, 1098218887Sdim // and we only need to check one size. 1099218887Sdim if (StSameBuf) { 1100218887Sdim state = StSameBuf; 1101218887Sdim state = CheckBufferAccess(C, state, Size, Left); 1102218887Sdim if (state) { 1103234353Sdim state = StSameBuf->BindExpr(CE, LCtx, 1104234353Sdim svalBuilder.makeZeroVal(CE->getType())); 1105234353Sdim C.addTransition(state); 1106218887Sdim } 1107218887Sdim } 1108218887Sdim 1109218887Sdim // If the two arguments might be different buffers, we have to check the 1110218887Sdim // size of both of them. 1111218887Sdim if (StNotSameBuf) { 1112218887Sdim state = StNotSameBuf; 1113218887Sdim state = CheckBufferAccess(C, state, Size, Left, Right); 1114218887Sdim if (state) { 1115218887Sdim // The return value is the comparison result, which we don't know. 1116243830Sdim SVal CmpV = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); 1117234353Sdim state = state->BindExpr(CE, LCtx, CmpV); 1118218887Sdim C.addTransition(state); 1119218887Sdim } 1120218887Sdim } 1121218887Sdim } 1122218887Sdim} 1123218887Sdim 1124219077Sdimvoid CStringChecker::evalstrLength(CheckerContext &C, 1125219077Sdim const CallExpr *CE) const { 1126234353Sdim if (CE->getNumArgs() < 1) 1127234353Sdim return; 1128234353Sdim 1129218887Sdim // size_t strlen(const char *s); 1130219077Sdim evalstrLengthCommon(C, CE, /* IsStrnlen = */ false); 1131219077Sdim} 1132219077Sdim 1133219077Sdimvoid CStringChecker::evalstrnLength(CheckerContext &C, 1134219077Sdim const CallExpr *CE) const { 1135234353Sdim if (CE->getNumArgs() < 2) 1136234353Sdim return; 1137234353Sdim 1138219077Sdim // size_t strnlen(const char *s, size_t maxlen); 1139219077Sdim evalstrLengthCommon(C, CE, /* IsStrnlen = */ true); 1140219077Sdim} 1141219077Sdim 1142219077Sdimvoid CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, 1143219077Sdim bool IsStrnlen) const { 1144224145Sdim CurrentFunctionDescription = "string length function"; 1145234353Sdim ProgramStateRef state = C.getState(); 1146234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1147224145Sdim 1148224145Sdim if (IsStrnlen) { 1149224145Sdim const Expr *maxlenExpr = CE->getArg(1); 1150234353Sdim SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); 1151224145Sdim 1152234353Sdim ProgramStateRef stateZeroSize, stateNonZeroSize; 1153224145Sdim llvm::tie(stateZeroSize, stateNonZeroSize) = 1154224145Sdim assumeZero(C, state, maxlenVal, maxlenExpr->getType()); 1155224145Sdim 1156224145Sdim // If the size can be zero, the result will be 0 in that case, and we don't 1157224145Sdim // have to check the string itself. 1158224145Sdim if (stateZeroSize) { 1159224145Sdim SVal zero = C.getSValBuilder().makeZeroVal(CE->getType()); 1160234353Sdim stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero); 1161224145Sdim C.addTransition(stateZeroSize); 1162224145Sdim } 1163224145Sdim 1164224145Sdim // If the size is GUARANTEED to be zero, we're done! 1165224145Sdim if (!stateNonZeroSize) 1166224145Sdim return; 1167224145Sdim 1168224145Sdim // Otherwise, record the assumption that the size is nonzero. 1169224145Sdim state = stateNonZeroSize; 1170224145Sdim } 1171224145Sdim 1172224145Sdim // Check that the string argument is non-null. 1173218887Sdim const Expr *Arg = CE->getArg(0); 1174234353Sdim SVal ArgVal = state->getSVal(Arg, LCtx); 1175218887Sdim 1176218887Sdim state = checkNonNull(C, state, Arg, ArgVal); 1177218887Sdim 1178224145Sdim if (!state) 1179224145Sdim return; 1180218887Sdim 1181224145Sdim SVal strLength = getCStringLength(C, state, Arg, ArgVal); 1182218887Sdim 1183224145Sdim // If the argument isn't a valid C string, there's no valid state to 1184224145Sdim // transition to. 1185224145Sdim if (strLength.isUndef()) 1186224145Sdim return; 1187219077Sdim 1188224145Sdim DefinedOrUnknownSVal result = UnknownVal(); 1189224145Sdim 1190224145Sdim // If the check is for strnlen() then bind the return value to no more than 1191224145Sdim // the maxlen value. 1192224145Sdim if (IsStrnlen) { 1193224145Sdim QualType cmpTy = C.getSValBuilder().getConditionType(); 1194224145Sdim 1195224145Sdim // It's a little unfortunate to be getting this again, 1196224145Sdim // but it's not that expensive... 1197224145Sdim const Expr *maxlenExpr = CE->getArg(1); 1198234353Sdim SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); 1199224145Sdim 1200249423Sdim Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); 1201249423Sdim Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>(); 1202224145Sdim 1203224145Sdim if (strLengthNL && maxlenValNL) { 1204234353Sdim ProgramStateRef stateStringTooLong, stateStringNotTooLong; 1205224145Sdim 1206224145Sdim // Check if the strLength is greater than the maxlen. 1207224145Sdim llvm::tie(stateStringTooLong, stateStringNotTooLong) = 1208249423Sdim state->assume(C.getSValBuilder().evalBinOpNN( 1209249423Sdim state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy) 1210249423Sdim .castAs<DefinedOrUnknownSVal>()); 1211219077Sdim 1212224145Sdim if (stateStringTooLong && !stateStringNotTooLong) { 1213224145Sdim // If the string is longer than maxlen, return maxlen. 1214224145Sdim result = *maxlenValNL; 1215224145Sdim } else if (stateStringNotTooLong && !stateStringTooLong) { 1216224145Sdim // If the string is shorter than maxlen, return its length. 1217224145Sdim result = *strLengthNL; 1218219077Sdim } 1219219077Sdim } 1220219077Sdim 1221224145Sdim if (result.isUnknown()) { 1222224145Sdim // If we don't have enough information for a comparison, there's 1223224145Sdim // no guarantee the full string length will actually be returned. 1224224145Sdim // All we know is the return value is the min of the string length 1225224145Sdim // and the limit. This is better than nothing. 1226243830Sdim result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount()); 1227249423Sdim NonLoc resultNL = result.castAs<NonLoc>(); 1228224145Sdim 1229224145Sdim if (strLengthNL) { 1230249423Sdim state = state->assume(C.getSValBuilder().evalBinOpNN( 1231249423Sdim state, BO_LE, resultNL, *strLengthNL, cmpTy) 1232249423Sdim .castAs<DefinedOrUnknownSVal>(), true); 1233224145Sdim } 1234224145Sdim 1235224145Sdim if (maxlenValNL) { 1236249423Sdim state = state->assume(C.getSValBuilder().evalBinOpNN( 1237249423Sdim state, BO_LE, resultNL, *maxlenValNL, cmpTy) 1238249423Sdim .castAs<DefinedOrUnknownSVal>(), true); 1239224145Sdim } 1240224145Sdim } 1241224145Sdim 1242224145Sdim } else { 1243224145Sdim // This is a plain strlen(), not strnlen(). 1244249423Sdim result = strLength.castAs<DefinedOrUnknownSVal>(); 1245224145Sdim 1246224145Sdim // If we don't know the length of the string, conjure a return 1247218887Sdim // value, so it can be used in constraints, at least. 1248224145Sdim if (result.isUnknown()) { 1249243830Sdim result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount()); 1250218887Sdim } 1251224145Sdim } 1252218887Sdim 1253224145Sdim // Bind the return value. 1254224145Sdim assert(!result.isUnknown() && "Should have conjured a value by now"); 1255234353Sdim state = state->BindExpr(CE, LCtx, result); 1256224145Sdim C.addTransition(state); 1257218887Sdim} 1258218887Sdim 1259219077Sdimvoid CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { 1260234353Sdim if (CE->getNumArgs() < 2) 1261234353Sdim return; 1262234353Sdim 1263218887Sdim // char *strcpy(char *restrict dst, const char *restrict src); 1264221345Sdim evalStrcpyCommon(C, CE, 1265221345Sdim /* returnEnd = */ false, 1266221345Sdim /* isBounded = */ false, 1267221345Sdim /* isAppending = */ false); 1268218887Sdim} 1269218887Sdim 1270219077Sdimvoid CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { 1271234353Sdim if (CE->getNumArgs() < 3) 1272234353Sdim return; 1273234353Sdim 1274223017Sdim // char *strncpy(char *restrict dst, const char *restrict src, size_t n); 1275221345Sdim evalStrcpyCommon(C, CE, 1276221345Sdim /* returnEnd = */ false, 1277221345Sdim /* isBounded = */ true, 1278221345Sdim /* isAppending = */ false); 1279219077Sdim} 1280219077Sdim 1281219077Sdimvoid CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const { 1282234353Sdim if (CE->getNumArgs() < 2) 1283234353Sdim return; 1284234353Sdim 1285218887Sdim // char *stpcpy(char *restrict dst, const char *restrict src); 1286221345Sdim evalStrcpyCommon(C, CE, 1287221345Sdim /* returnEnd = */ true, 1288221345Sdim /* isBounded = */ false, 1289221345Sdim /* isAppending = */ false); 1290218887Sdim} 1291218887Sdim 1292221345Sdimvoid CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { 1293234353Sdim if (CE->getNumArgs() < 2) 1294234353Sdim return; 1295234353Sdim 1296221345Sdim //char *strcat(char *restrict s1, const char *restrict s2); 1297221345Sdim evalStrcpyCommon(C, CE, 1298221345Sdim /* returnEnd = */ false, 1299221345Sdim /* isBounded = */ false, 1300221345Sdim /* isAppending = */ true); 1301221345Sdim} 1302221345Sdim 1303221345Sdimvoid CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const { 1304234353Sdim if (CE->getNumArgs() < 3) 1305234353Sdim return; 1306234353Sdim 1307221345Sdim //char *strncat(char *restrict s1, const char *restrict s2, size_t n); 1308221345Sdim evalStrcpyCommon(C, CE, 1309221345Sdim /* returnEnd = */ false, 1310221345Sdim /* isBounded = */ true, 1311221345Sdim /* isAppending = */ true); 1312221345Sdim} 1313221345Sdim 1314218887Sdimvoid CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, 1315221345Sdim bool returnEnd, bool isBounded, 1316221345Sdim bool isAppending) const { 1317224145Sdim CurrentFunctionDescription = "string copy function"; 1318234353Sdim ProgramStateRef state = C.getState(); 1319234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1320218887Sdim 1321221345Sdim // Check that the destination is non-null. 1322218887Sdim const Expr *Dst = CE->getArg(0); 1323234353Sdim SVal DstVal = state->getSVal(Dst, LCtx); 1324218887Sdim 1325218887Sdim state = checkNonNull(C, state, Dst, DstVal); 1326218887Sdim if (!state) 1327218887Sdim return; 1328218887Sdim 1329218887Sdim // Check that the source is non-null. 1330218887Sdim const Expr *srcExpr = CE->getArg(1); 1331234353Sdim SVal srcVal = state->getSVal(srcExpr, LCtx); 1332218887Sdim state = checkNonNull(C, state, srcExpr, srcVal); 1333218887Sdim if (!state) 1334218887Sdim return; 1335218887Sdim 1336218887Sdim // Get the string length of the source. 1337218887Sdim SVal strLength = getCStringLength(C, state, srcExpr, srcVal); 1338218887Sdim 1339218887Sdim // If the source isn't a valid C string, give up. 1340218887Sdim if (strLength.isUndef()) 1341218887Sdim return; 1342218887Sdim 1343224145Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 1344224145Sdim QualType cmpTy = svalBuilder.getConditionType(); 1345224145Sdim QualType sizeTy = svalBuilder.getContext().getSizeType(); 1346224145Sdim 1347224145Sdim // These two values allow checking two kinds of errors: 1348224145Sdim // - actual overflows caused by a source that doesn't fit in the destination 1349224145Sdim // - potential overflows caused by a bound that could exceed the destination 1350224145Sdim SVal amountCopied = UnknownVal(); 1351224145Sdim SVal maxLastElementIndex = UnknownVal(); 1352224145Sdim const char *boundWarning = NULL; 1353224145Sdim 1354221345Sdim // If the function is strncpy, strncat, etc... it is bounded. 1355221345Sdim if (isBounded) { 1356221345Sdim // Get the max number of characters to copy. 1357219077Sdim const Expr *lenExpr = CE->getArg(2); 1358234353Sdim SVal lenVal = state->getSVal(lenExpr, LCtx); 1359219077Sdim 1360224145Sdim // Protect against misdeclared strncpy(). 1361224145Sdim lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType()); 1362224145Sdim 1363249423Sdim Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); 1364249423Sdim Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>(); 1365219077Sdim 1366224145Sdim // If we know both values, we might be able to figure out how much 1367224145Sdim // we're copying. 1368224145Sdim if (strLengthNL && lenValNL) { 1369234353Sdim ProgramStateRef stateSourceTooLong, stateSourceNotTooLong; 1370219077Sdim 1371224145Sdim // Check if the max number to copy is less than the length of the src. 1372224145Sdim // If the bound is equal to the source length, strncpy won't null- 1373224145Sdim // terminate the result! 1374249423Sdim llvm::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( 1375249423Sdim svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) 1376249423Sdim .castAs<DefinedOrUnknownSVal>()); 1377224145Sdim 1378224145Sdim if (stateSourceTooLong && !stateSourceNotTooLong) { 1379224145Sdim // Max number to copy is less than the length of the src, so the actual 1380224145Sdim // strLength copied is the max number arg. 1381224145Sdim state = stateSourceTooLong; 1382224145Sdim amountCopied = lenVal; 1383224145Sdim 1384224145Sdim } else if (!stateSourceTooLong && stateSourceNotTooLong) { 1385224145Sdim // The source buffer entirely fits in the bound. 1386224145Sdim state = stateSourceNotTooLong; 1387224145Sdim amountCopied = strLength; 1388224145Sdim } 1389224145Sdim } 1390224145Sdim 1391224145Sdim // We still want to know if the bound is known to be too large. 1392224145Sdim if (lenValNL) { 1393224145Sdim if (isAppending) { 1394224145Sdim // For strncat, the check is strlen(dst) + lenVal < sizeof(dst) 1395224145Sdim 1396224145Sdim // Get the string length of the destination. If the destination is 1397224145Sdim // memory that can't have a string length, we shouldn't be copying 1398224145Sdim // into it anyway. 1399224145Sdim SVal dstStrLength = getCStringLength(C, state, Dst, DstVal); 1400224145Sdim if (dstStrLength.isUndef()) 1401224145Sdim return; 1402224145Sdim 1403249423Sdim if (Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>()) { 1404224145Sdim maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Add, 1405224145Sdim *lenValNL, 1406224145Sdim *dstStrLengthNL, 1407224145Sdim sizeTy); 1408224145Sdim boundWarning = "Size argument is greater than the free space in the " 1409224145Sdim "destination buffer"; 1410224145Sdim } 1411224145Sdim 1412224145Sdim } else { 1413224145Sdim // For strncpy, this is just checking that lenVal <= sizeof(dst) 1414224145Sdim // (Yes, strncpy and strncat differ in how they treat termination. 1415224145Sdim // strncat ALWAYS terminates, but strncpy doesn't.) 1416239462Sdim 1417239462Sdim // We need a special case for when the copy size is zero, in which 1418239462Sdim // case strncpy will do no work at all. Our bounds check uses n-1 1419239462Sdim // as the last element accessed, so n == 0 is problematic. 1420239462Sdim ProgramStateRef StateZeroSize, StateNonZeroSize; 1421239462Sdim llvm::tie(StateZeroSize, StateNonZeroSize) = 1422239462Sdim assumeZero(C, state, *lenValNL, sizeTy); 1423239462Sdim 1424239462Sdim // If the size is known to be zero, we're done. 1425239462Sdim if (StateZeroSize && !StateNonZeroSize) { 1426239462Sdim StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal); 1427239462Sdim C.addTransition(StateZeroSize); 1428239462Sdim return; 1429239462Sdim } 1430239462Sdim 1431239462Sdim // Otherwise, go ahead and figure out the last element we'll touch. 1432239462Sdim // We don't record the non-zero assumption here because we can't 1433239462Sdim // be sure. We won't warn on a possible zero. 1434249423Sdim NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 1435224145Sdim maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, 1436224145Sdim one, sizeTy); 1437224145Sdim boundWarning = "Size argument is greater than the length of the " 1438224145Sdim "destination buffer"; 1439224145Sdim } 1440224145Sdim } 1441224145Sdim 1442224145Sdim // If we couldn't pin down the copy length, at least bound it. 1443224145Sdim // FIXME: We should actually run this code path for append as well, but 1444224145Sdim // right now it creates problems with constraints (since we can end up 1445224145Sdim // trying to pass constraints from symbol to symbol). 1446224145Sdim if (amountCopied.isUnknown() && !isAppending) { 1447224145Sdim // Try to get a "hypothetical" string length symbol, which we can later 1448224145Sdim // set as a real value if that turns out to be the case. 1449224145Sdim amountCopied = getCStringLength(C, state, lenExpr, srcVal, true); 1450224145Sdim assert(!amountCopied.isUndef()); 1451224145Sdim 1452249423Sdim if (Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>()) { 1453224145Sdim if (lenValNL) { 1454224145Sdim // amountCopied <= lenVal 1455224145Sdim SVal copiedLessThanBound = svalBuilder.evalBinOpNN(state, BO_LE, 1456224145Sdim *amountCopiedNL, 1457224145Sdim *lenValNL, 1458224145Sdim cmpTy); 1459249423Sdim state = state->assume( 1460249423Sdim copiedLessThanBound.castAs<DefinedOrUnknownSVal>(), true); 1461224145Sdim if (!state) 1462224145Sdim return; 1463224145Sdim } 1464224145Sdim 1465224145Sdim if (strLengthNL) { 1466224145Sdim // amountCopied <= strlen(source) 1467224145Sdim SVal copiedLessThanSrc = svalBuilder.evalBinOpNN(state, BO_LE, 1468224145Sdim *amountCopiedNL, 1469224145Sdim *strLengthNL, 1470224145Sdim cmpTy); 1471249423Sdim state = state->assume( 1472249423Sdim copiedLessThanSrc.castAs<DefinedOrUnknownSVal>(), true); 1473224145Sdim if (!state) 1474224145Sdim return; 1475224145Sdim } 1476224145Sdim } 1477224145Sdim } 1478224145Sdim 1479224145Sdim } else { 1480224145Sdim // The function isn't bounded. The amount copied should match the length 1481224145Sdim // of the source buffer. 1482224145Sdim amountCopied = strLength; 1483219077Sdim } 1484219077Sdim 1485224145Sdim assert(state); 1486224145Sdim 1487224145Sdim // This represents the number of characters copied into the destination 1488224145Sdim // buffer. (It may not actually be the strlen if the destination buffer 1489224145Sdim // is not terminated.) 1490224145Sdim SVal finalStrLength = UnknownVal(); 1491224145Sdim 1492221345Sdim // If this is an appending function (strcat, strncat...) then set the 1493221345Sdim // string length to strlen(src) + strlen(dst) since the buffer will 1494221345Sdim // ultimately contain both. 1495221345Sdim if (isAppending) { 1496224145Sdim // Get the string length of the destination. If the destination is memory 1497224145Sdim // that can't have a string length, we shouldn't be copying into it anyway. 1498221345Sdim SVal dstStrLength = getCStringLength(C, state, Dst, DstVal); 1499221345Sdim if (dstStrLength.isUndef()) 1500221345Sdim return; 1501221345Sdim 1502249423Sdim Optional<NonLoc> srcStrLengthNL = amountCopied.getAs<NonLoc>(); 1503249423Sdim Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); 1504221345Sdim 1505224145Sdim // If we know both string lengths, we might know the final string length. 1506224145Sdim if (srcStrLengthNL && dstStrLengthNL) { 1507224145Sdim // Make sure the two lengths together don't overflow a size_t. 1508224145Sdim state = checkAdditionOverflow(C, state, *srcStrLengthNL, *dstStrLengthNL); 1509224145Sdim if (!state) 1510224145Sdim return; 1511221345Sdim 1512224145Sdim finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *srcStrLengthNL, 1513224145Sdim *dstStrLengthNL, sizeTy); 1514224145Sdim } 1515221345Sdim 1516224145Sdim // If we couldn't get a single value for the final string length, 1517224145Sdim // we can at least bound it by the individual lengths. 1518224145Sdim if (finalStrLength.isUnknown()) { 1519224145Sdim // Try to get a "hypothetical" string length symbol, which we can later 1520224145Sdim // set as a real value if that turns out to be the case. 1521224145Sdim finalStrLength = getCStringLength(C, state, CE, DstVal, true); 1522224145Sdim assert(!finalStrLength.isUndef()); 1523224145Sdim 1524249423Sdim if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) { 1525224145Sdim if (srcStrLengthNL) { 1526224145Sdim // finalStrLength >= srcStrLength 1527224145Sdim SVal sourceInResult = svalBuilder.evalBinOpNN(state, BO_GE, 1528224145Sdim *finalStrLengthNL, 1529224145Sdim *srcStrLengthNL, 1530224145Sdim cmpTy); 1531249423Sdim state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(), 1532224145Sdim true); 1533224145Sdim if (!state) 1534224145Sdim return; 1535224145Sdim } 1536224145Sdim 1537224145Sdim if (dstStrLengthNL) { 1538224145Sdim // finalStrLength >= dstStrLength 1539224145Sdim SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE, 1540224145Sdim *finalStrLengthNL, 1541224145Sdim *dstStrLengthNL, 1542224145Sdim cmpTy); 1543249423Sdim state = 1544249423Sdim state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true); 1545224145Sdim if (!state) 1546224145Sdim return; 1547224145Sdim } 1548224145Sdim } 1549224145Sdim } 1550224145Sdim 1551224145Sdim } else { 1552224145Sdim // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and 1553224145Sdim // the final string length will match the input string length. 1554224145Sdim finalStrLength = amountCopied; 1555221345Sdim } 1556221345Sdim 1557224145Sdim // The final result of the function will either be a pointer past the last 1558224145Sdim // copied element, or a pointer to the start of the destination buffer. 1559218887Sdim SVal Result = (returnEnd ? UnknownVal() : DstVal); 1560218887Sdim 1561224145Sdim assert(state); 1562224145Sdim 1563218887Sdim // If the destination is a MemRegion, try to check for a buffer overflow and 1564218887Sdim // record the new string length. 1565249423Sdim if (Optional<loc::MemRegionVal> dstRegVal = 1566249423Sdim DstVal.getAs<loc::MemRegionVal>()) { 1567224145Sdim QualType ptrTy = Dst->getType(); 1568218887Sdim 1569224145Sdim // If we have an exact value on a bounded copy, use that to check for 1570224145Sdim // overflows, rather than our estimate about how much is actually copied. 1571224145Sdim if (boundWarning) { 1572249423Sdim if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) { 1573224145Sdim SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, 1574224145Sdim *maxLastNL, ptrTy); 1575224145Sdim state = CheckLocation(C, state, CE->getArg(2), maxLastElement, 1576224145Sdim boundWarning); 1577224145Sdim if (!state) 1578224145Sdim return; 1579224145Sdim } 1580224145Sdim } 1581218887Sdim 1582224145Sdim // Then, if the final length is known... 1583249423Sdim if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) { 1584224145Sdim SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, 1585224145Sdim *knownStrLength, ptrTy); 1586224145Sdim 1587224145Sdim // ...and we haven't checked the bound, we'll check the actual copy. 1588224145Sdim if (!boundWarning) { 1589224145Sdim const char * const warningMsg = 1590224145Sdim "String copy function overflows destination buffer"; 1591224145Sdim state = CheckLocation(C, state, Dst, lastElement, warningMsg); 1592224145Sdim if (!state) 1593224145Sdim return; 1594224145Sdim } 1595224145Sdim 1596218887Sdim // If this is a stpcpy-style copy, the last element is the return value. 1597218887Sdim if (returnEnd) 1598218887Sdim Result = lastElement; 1599218887Sdim } 1600218887Sdim 1601263508Sdim // Invalidate the destination (regular invalidation without pointer-escaping 1602263508Sdim // the address of the top-level region). This must happen before we set the 1603263508Sdim // C string length because invalidation will clear the length. 1604218887Sdim // FIXME: Even if we can't perfectly model the copy, we should see if we 1605218887Sdim // can use LazyCompoundVals to copy the source values into the destination. 1606218887Sdim // This would probably remove any existing bindings past the end of the 1607218887Sdim // string, but that's still an improvement over blank invalidation. 1608263508Sdim state = InvalidateBuffer(C, state, Dst, *dstRegVal, 1609263508Sdim /*IsSourceBuffer*/false); 1610218887Sdim 1611263508Sdim // Invalidate the source (const-invalidation without const-pointer-escaping 1612263508Sdim // the address of the top-level region). 1613263508Sdim state = InvalidateBuffer(C, state, srcExpr, srcVal, /*IsSourceBuffer*/true); 1614263508Sdim 1615224145Sdim // Set the C string length of the destination, if we know it. 1616224145Sdim if (isBounded && !isAppending) { 1617224145Sdim // strncpy is annoying in that it doesn't guarantee to null-terminate 1618224145Sdim // the result string. If the original string didn't fit entirely inside 1619224145Sdim // the bound (including the null-terminator), we don't know how long the 1620224145Sdim // result is. 1621224145Sdim if (amountCopied != strLength) 1622224145Sdim finalStrLength = UnknownVal(); 1623224145Sdim } 1624224145Sdim state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength); 1625218887Sdim } 1626218887Sdim 1627224145Sdim assert(state); 1628224145Sdim 1629218887Sdim // If this is a stpcpy-style copy, but we were unable to check for a buffer 1630218887Sdim // overflow, we still need a result. Conjure a return value. 1631218887Sdim if (returnEnd && Result.isUnknown()) { 1632243830Sdim Result = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); 1633218887Sdim } 1634218887Sdim 1635218887Sdim // Set the return value. 1636234353Sdim state = state->BindExpr(CE, LCtx, Result); 1637218887Sdim C.addTransition(state); 1638218887Sdim} 1639218887Sdim 1640221345Sdimvoid CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { 1641234353Sdim if (CE->getNumArgs() < 2) 1642234353Sdim return; 1643234353Sdim 1644224145Sdim //int strcmp(const char *s1, const char *s2); 1645221345Sdim evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ false); 1646221345Sdim} 1647221345Sdim 1648221345Sdimvoid CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { 1649234353Sdim if (CE->getNumArgs() < 3) 1650234353Sdim return; 1651234353Sdim 1652224145Sdim //int strncmp(const char *s1, const char *s2, size_t n); 1653221345Sdim evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false); 1654221345Sdim} 1655221345Sdim 1656221345Sdimvoid CStringChecker::evalStrcasecmp(CheckerContext &C, 1657221345Sdim const CallExpr *CE) const { 1658234353Sdim if (CE->getNumArgs() < 2) 1659234353Sdim return; 1660234353Sdim 1661224145Sdim //int strcasecmp(const char *s1, const char *s2); 1662221345Sdim evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true); 1663221345Sdim} 1664221345Sdim 1665223017Sdimvoid CStringChecker::evalStrncasecmp(CheckerContext &C, 1666223017Sdim const CallExpr *CE) const { 1667234353Sdim if (CE->getNumArgs() < 3) 1668234353Sdim return; 1669234353Sdim 1670224145Sdim //int strncasecmp(const char *s1, const char *s2, size_t n); 1671223017Sdim evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true); 1672223017Sdim} 1673223017Sdim 1674221345Sdimvoid CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, 1675221345Sdim bool isBounded, bool ignoreCase) const { 1676224145Sdim CurrentFunctionDescription = "string comparison function"; 1677234353Sdim ProgramStateRef state = C.getState(); 1678234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1679221345Sdim 1680221345Sdim // Check that the first string is non-null 1681221345Sdim const Expr *s1 = CE->getArg(0); 1682234353Sdim SVal s1Val = state->getSVal(s1, LCtx); 1683221345Sdim state = checkNonNull(C, state, s1, s1Val); 1684221345Sdim if (!state) 1685221345Sdim return; 1686221345Sdim 1687221345Sdim // Check that the second string is non-null. 1688221345Sdim const Expr *s2 = CE->getArg(1); 1689234353Sdim SVal s2Val = state->getSVal(s2, LCtx); 1690221345Sdim state = checkNonNull(C, state, s2, s2Val); 1691221345Sdim if (!state) 1692221345Sdim return; 1693221345Sdim 1694221345Sdim // Get the string length of the first string or give up. 1695221345Sdim SVal s1Length = getCStringLength(C, state, s1, s1Val); 1696221345Sdim if (s1Length.isUndef()) 1697221345Sdim return; 1698221345Sdim 1699221345Sdim // Get the string length of the second string or give up. 1700221345Sdim SVal s2Length = getCStringLength(C, state, s2, s2Val); 1701221345Sdim if (s2Length.isUndef()) 1702221345Sdim return; 1703221345Sdim 1704224145Sdim // If we know the two buffers are the same, we know the result is 0. 1705224145Sdim // First, get the two buffers' addresses. Another checker will have already 1706224145Sdim // made sure they're not undefined. 1707249423Sdim DefinedOrUnknownSVal LV = s1Val.castAs<DefinedOrUnknownSVal>(); 1708249423Sdim DefinedOrUnknownSVal RV = s2Val.castAs<DefinedOrUnknownSVal>(); 1709221345Sdim 1710224145Sdim // See if they are the same. 1711224145Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 1712224145Sdim DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); 1713234353Sdim ProgramStateRef StSameBuf, StNotSameBuf; 1714224145Sdim llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); 1715221345Sdim 1716224145Sdim // If the two arguments might be the same buffer, we know the result is 0, 1717224145Sdim // and we only need to check one size. 1718224145Sdim if (StSameBuf) { 1719234353Sdim StSameBuf = StSameBuf->BindExpr(CE, LCtx, 1720234353Sdim svalBuilder.makeZeroVal(CE->getType())); 1721224145Sdim C.addTransition(StSameBuf); 1722221345Sdim 1723224145Sdim // If the two arguments are GUARANTEED to be the same, we're done! 1724224145Sdim if (!StNotSameBuf) 1725221345Sdim return; 1726224145Sdim } 1727221345Sdim 1728224145Sdim assert(StNotSameBuf); 1729224145Sdim state = StNotSameBuf; 1730224145Sdim 1731224145Sdim // At this point we can go about comparing the two buffers. 1732224145Sdim // For now, we only do this if they're both known string literals. 1733224145Sdim 1734224145Sdim // Attempt to extract string literals from both expressions. 1735224145Sdim const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val); 1736224145Sdim const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val); 1737224145Sdim bool canComputeResult = false; 1738224145Sdim 1739224145Sdim if (s1StrLiteral && s2StrLiteral) { 1740226633Sdim StringRef s1StrRef = s1StrLiteral->getString(); 1741226633Sdim StringRef s2StrRef = s2StrLiteral->getString(); 1742224145Sdim 1743224145Sdim if (isBounded) { 1744224145Sdim // Get the max number of characters to compare. 1745224145Sdim const Expr *lenExpr = CE->getArg(2); 1746234353Sdim SVal lenVal = state->getSVal(lenExpr, LCtx); 1747224145Sdim 1748224145Sdim // If the length is known, we can get the right substrings. 1749224145Sdim if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) { 1750224145Sdim // Create substrings of each to compare the prefix. 1751224145Sdim s1StrRef = s1StrRef.substr(0, (size_t)len->getZExtValue()); 1752224145Sdim s2StrRef = s2StrRef.substr(0, (size_t)len->getZExtValue()); 1753224145Sdim canComputeResult = true; 1754224145Sdim } 1755224145Sdim } else { 1756224145Sdim // This is a normal, unbounded strcmp. 1757224145Sdim canComputeResult = true; 1758224145Sdim } 1759224145Sdim 1760224145Sdim if (canComputeResult) { 1761224145Sdim // Real strcmp stops at null characters. 1762224145Sdim size_t s1Term = s1StrRef.find('\0'); 1763226633Sdim if (s1Term != StringRef::npos) 1764224145Sdim s1StrRef = s1StrRef.substr(0, s1Term); 1765224145Sdim 1766224145Sdim size_t s2Term = s2StrRef.find('\0'); 1767226633Sdim if (s2Term != StringRef::npos) 1768224145Sdim s2StrRef = s2StrRef.substr(0, s2Term); 1769224145Sdim 1770224145Sdim // Use StringRef's comparison methods to compute the actual result. 1771224145Sdim int result; 1772224145Sdim 1773224145Sdim if (ignoreCase) { 1774224145Sdim // Compare string 1 to string 2 the same way strcasecmp() does. 1775224145Sdim result = s1StrRef.compare_lower(s2StrRef); 1776224145Sdim } else { 1777224145Sdim // Compare string 1 to string 2 the same way strcmp() does. 1778224145Sdim result = s1StrRef.compare(s2StrRef); 1779224145Sdim } 1780224145Sdim 1781224145Sdim // Build the SVal of the comparison and bind the return value. 1782224145Sdim SVal resultVal = svalBuilder.makeIntVal(result, CE->getType()); 1783234353Sdim state = state->BindExpr(CE, LCtx, resultVal); 1784224145Sdim } 1785223017Sdim } 1786221345Sdim 1787224145Sdim if (!canComputeResult) { 1788224145Sdim // Conjure a symbolic value. It's the best we can do. 1789243830Sdim SVal resultVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); 1790234353Sdim state = state->BindExpr(CE, LCtx, resultVal); 1791221345Sdim } 1792221345Sdim 1793224145Sdim // Record this as a possible path. 1794221345Sdim C.addTransition(state); 1795221345Sdim} 1796221345Sdim 1797251662Sdimvoid CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { 1798251662Sdim //char *strsep(char **stringp, const char *delim); 1799251662Sdim if (CE->getNumArgs() < 2) 1800251662Sdim return; 1801251662Sdim 1802251662Sdim // Sanity: does the search string parameter match the return type? 1803251662Sdim const Expr *SearchStrPtr = CE->getArg(0); 1804251662Sdim QualType CharPtrTy = SearchStrPtr->getType()->getPointeeType(); 1805251662Sdim if (CharPtrTy.isNull() || 1806251662Sdim CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType()) 1807251662Sdim return; 1808251662Sdim 1809251662Sdim CurrentFunctionDescription = "strsep()"; 1810251662Sdim ProgramStateRef State = C.getState(); 1811251662Sdim const LocationContext *LCtx = C.getLocationContext(); 1812251662Sdim 1813251662Sdim // Check that the search string pointer is non-null (though it may point to 1814251662Sdim // a null string). 1815251662Sdim SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx); 1816251662Sdim State = checkNonNull(C, State, SearchStrPtr, SearchStrVal); 1817251662Sdim if (!State) 1818251662Sdim return; 1819251662Sdim 1820251662Sdim // Check that the delimiter string is non-null. 1821251662Sdim const Expr *DelimStr = CE->getArg(1); 1822251662Sdim SVal DelimStrVal = State->getSVal(DelimStr, LCtx); 1823251662Sdim State = checkNonNull(C, State, DelimStr, DelimStrVal); 1824251662Sdim if (!State) 1825251662Sdim return; 1826251662Sdim 1827251662Sdim SValBuilder &SVB = C.getSValBuilder(); 1828251662Sdim SVal Result; 1829251662Sdim if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) { 1830251662Sdim // Get the current value of the search string pointer, as a char*. 1831251662Sdim Result = State->getSVal(*SearchStrLoc, CharPtrTy); 1832251662Sdim 1833251662Sdim // Invalidate the search string, representing the change of one delimiter 1834251662Sdim // character to NUL. 1835263508Sdim State = InvalidateBuffer(C, State, SearchStrPtr, Result, 1836263508Sdim /*IsSourceBuffer*/false); 1837251662Sdim 1838251662Sdim // Overwrite the search string pointer. The new value is either an address 1839251662Sdim // further along in the same string, or NULL if there are no more tokens. 1840251662Sdim State = State->bindLoc(*SearchStrLoc, 1841251662Sdim SVB.conjureSymbolVal(getTag(), CE, LCtx, CharPtrTy, 1842251662Sdim C.blockCount())); 1843251662Sdim } else { 1844251662Sdim assert(SearchStrVal.isUnknown()); 1845251662Sdim // Conjure a symbolic value. It's the best we can do. 1846251662Sdim Result = SVB.conjureSymbolVal(0, CE, LCtx, C.blockCount()); 1847251662Sdim } 1848251662Sdim 1849251662Sdim // Set the return value, and finish. 1850251662Sdim State = State->BindExpr(CE, LCtx, Result); 1851251662Sdim C.addTransition(State); 1852251662Sdim} 1853251662Sdim 1854251662Sdim 1855218887Sdim//===----------------------------------------------------------------------===// 1856218887Sdim// The driver method, and other Checker callbacks. 1857218887Sdim//===----------------------------------------------------------------------===// 1858218887Sdim 1859219077Sdimbool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { 1860234353Sdim const FunctionDecl *FDecl = C.getCalleeDecl(CE); 1861218887Sdim 1862234353Sdim if (!FDecl) 1863218887Sdim return false; 1864218887Sdim 1865251662Sdim // FIXME: Poorly-factored string switches are slow. 1866234353Sdim FnCheck evalFunction = 0; 1867234353Sdim if (C.isCLibraryFunction(FDecl, "memcpy")) 1868234353Sdim evalFunction = &CStringChecker::evalMemcpy; 1869234353Sdim else if (C.isCLibraryFunction(FDecl, "mempcpy")) 1870234353Sdim evalFunction = &CStringChecker::evalMempcpy; 1871234353Sdim else if (C.isCLibraryFunction(FDecl, "memcmp")) 1872234353Sdim evalFunction = &CStringChecker::evalMemcmp; 1873234353Sdim else if (C.isCLibraryFunction(FDecl, "memmove")) 1874234353Sdim evalFunction = &CStringChecker::evalMemmove; 1875234353Sdim else if (C.isCLibraryFunction(FDecl, "strcpy")) 1876234353Sdim evalFunction = &CStringChecker::evalStrcpy; 1877234353Sdim else if (C.isCLibraryFunction(FDecl, "strncpy")) 1878234353Sdim evalFunction = &CStringChecker::evalStrncpy; 1879234353Sdim else if (C.isCLibraryFunction(FDecl, "stpcpy")) 1880234353Sdim evalFunction = &CStringChecker::evalStpcpy; 1881234353Sdim else if (C.isCLibraryFunction(FDecl, "strcat")) 1882234353Sdim evalFunction = &CStringChecker::evalStrcat; 1883234353Sdim else if (C.isCLibraryFunction(FDecl, "strncat")) 1884234353Sdim evalFunction = &CStringChecker::evalStrncat; 1885234353Sdim else if (C.isCLibraryFunction(FDecl, "strlen")) 1886234353Sdim evalFunction = &CStringChecker::evalstrLength; 1887234353Sdim else if (C.isCLibraryFunction(FDecl, "strnlen")) 1888234353Sdim evalFunction = &CStringChecker::evalstrnLength; 1889234353Sdim else if (C.isCLibraryFunction(FDecl, "strcmp")) 1890234353Sdim evalFunction = &CStringChecker::evalStrcmp; 1891234353Sdim else if (C.isCLibraryFunction(FDecl, "strncmp")) 1892234353Sdim evalFunction = &CStringChecker::evalStrncmp; 1893234353Sdim else if (C.isCLibraryFunction(FDecl, "strcasecmp")) 1894234353Sdim evalFunction = &CStringChecker::evalStrcasecmp; 1895234353Sdim else if (C.isCLibraryFunction(FDecl, "strncasecmp")) 1896234353Sdim evalFunction = &CStringChecker::evalStrncasecmp; 1897251662Sdim else if (C.isCLibraryFunction(FDecl, "strsep")) 1898251662Sdim evalFunction = &CStringChecker::evalStrsep; 1899234353Sdim else if (C.isCLibraryFunction(FDecl, "bcopy")) 1900234353Sdim evalFunction = &CStringChecker::evalBcopy; 1901234353Sdim else if (C.isCLibraryFunction(FDecl, "bcmp")) 1902234353Sdim evalFunction = &CStringChecker::evalMemcmp; 1903234353Sdim 1904218887Sdim // If the callee isn't a string function, let another checker handle it. 1905218887Sdim if (!evalFunction) 1906218887Sdim return false; 1907218887Sdim 1908224145Sdim // Make sure each function sets its own description. 1909224145Sdim // (But don't bother in a release build.) 1910224145Sdim assert(!(CurrentFunctionDescription = NULL)); 1911224145Sdim 1912218887Sdim // Check and evaluate the call. 1913218887Sdim (this->*evalFunction)(C, CE); 1914234353Sdim 1915234353Sdim // If the evaluate call resulted in no change, chain to the next eval call 1916234353Sdim // handler. 1917234353Sdim // Note, the custom CString evaluation calls assume that basic safety 1918234353Sdim // properties are held. However, if the user chooses to turn off some of these 1919234353Sdim // checks, we ignore the issues and leave the call evaluation to a generic 1920234353Sdim // handler. 1921234353Sdim if (!C.isDifferent()) 1922234353Sdim return false; 1923234353Sdim 1924218887Sdim return true; 1925218887Sdim} 1926218887Sdim 1927219077Sdimvoid CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 1928218887Sdim // Record string length for char a[] = "abc"; 1929234353Sdim ProgramStateRef state = C.getState(); 1930218887Sdim 1931218887Sdim for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end(); 1932218887Sdim I != E; ++I) { 1933218887Sdim const VarDecl *D = dyn_cast<VarDecl>(*I); 1934218887Sdim if (!D) 1935218887Sdim continue; 1936218887Sdim 1937218887Sdim // FIXME: Handle array fields of structs. 1938218887Sdim if (!D->getType()->isArrayType()) 1939218887Sdim continue; 1940218887Sdim 1941218887Sdim const Expr *Init = D->getInit(); 1942218887Sdim if (!Init) 1943218887Sdim continue; 1944218887Sdim if (!isa<StringLiteral>(Init)) 1945218887Sdim continue; 1946218887Sdim 1947234353Sdim Loc VarLoc = state->getLValue(D, C.getLocationContext()); 1948218887Sdim const MemRegion *MR = VarLoc.getAsRegion(); 1949218887Sdim if (!MR) 1950218887Sdim continue; 1951218887Sdim 1952234353Sdim SVal StrVal = state->getSVal(Init, C.getLocationContext()); 1953218887Sdim assert(StrVal.isValid() && "Initializer string is unknown or undefined"); 1954249423Sdim DefinedOrUnknownSVal strLength = 1955249423Sdim getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>(); 1956218887Sdim 1957218887Sdim state = state->set<CStringLength>(MR, strLength); 1958218887Sdim } 1959218887Sdim 1960218887Sdim C.addTransition(state); 1961218887Sdim} 1962218887Sdim 1963234353Sdimbool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const { 1964243830Sdim CStringLengthTy Entries = state->get<CStringLength>(); 1965218887Sdim return !Entries.isEmpty(); 1966218887Sdim} 1967218887Sdim 1968234353SdimProgramStateRef 1969234353SdimCStringChecker::checkRegionChanges(ProgramStateRef state, 1970249423Sdim const InvalidatedSymbols *, 1971226633Sdim ArrayRef<const MemRegion *> ExplicitRegions, 1972234353Sdim ArrayRef<const MemRegion *> Regions, 1973239462Sdim const CallEvent *Call) const { 1974243830Sdim CStringLengthTy Entries = state->get<CStringLength>(); 1975218887Sdim if (Entries.isEmpty()) 1976218887Sdim return state; 1977218887Sdim 1978218887Sdim llvm::SmallPtrSet<const MemRegion *, 8> Invalidated; 1979218887Sdim llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions; 1980218887Sdim 1981218887Sdim // First build sets for the changed regions and their super-regions. 1982226633Sdim for (ArrayRef<const MemRegion *>::iterator 1983226633Sdim I = Regions.begin(), E = Regions.end(); I != E; ++I) { 1984226633Sdim const MemRegion *MR = *I; 1985218887Sdim Invalidated.insert(MR); 1986218887Sdim 1987218887Sdim SuperRegions.insert(MR); 1988218887Sdim while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) { 1989218887Sdim MR = SR->getSuperRegion(); 1990218887Sdim SuperRegions.insert(MR); 1991218887Sdim } 1992218887Sdim } 1993218887Sdim 1994243830Sdim CStringLengthTy::Factory &F = state->get_context<CStringLength>(); 1995218887Sdim 1996218887Sdim // Then loop over the entries in the current state. 1997243830Sdim for (CStringLengthTy::iterator I = Entries.begin(), 1998218887Sdim E = Entries.end(); I != E; ++I) { 1999218887Sdim const MemRegion *MR = I.getKey(); 2000218887Sdim 2001218887Sdim // Is this entry for a super-region of a changed region? 2002218887Sdim if (SuperRegions.count(MR)) { 2003218887Sdim Entries = F.remove(Entries, MR); 2004218887Sdim continue; 2005218887Sdim } 2006218887Sdim 2007218887Sdim // Is this entry for a sub-region of a changed region? 2008218887Sdim const MemRegion *Super = MR; 2009218887Sdim while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) { 2010218887Sdim Super = SR->getSuperRegion(); 2011218887Sdim if (Invalidated.count(Super)) { 2012218887Sdim Entries = F.remove(Entries, MR); 2013218887Sdim break; 2014218887Sdim } 2015218887Sdim } 2016218887Sdim } 2017218887Sdim 2018218887Sdim return state->set<CStringLength>(Entries); 2019218887Sdim} 2020218887Sdim 2021234353Sdimvoid CStringChecker::checkLiveSymbols(ProgramStateRef state, 2022219077Sdim SymbolReaper &SR) const { 2023218887Sdim // Mark all symbols in our string length map as valid. 2024243830Sdim CStringLengthTy Entries = state->get<CStringLength>(); 2025218887Sdim 2026243830Sdim for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); 2027218887Sdim I != E; ++I) { 2028218887Sdim SVal Len = I.getData(); 2029224145Sdim 2030234353Sdim for (SymExpr::symbol_iterator si = Len.symbol_begin(), 2031234353Sdim se = Len.symbol_end(); si != se; ++si) 2032224145Sdim SR.markInUse(*si); 2033218887Sdim } 2034218887Sdim} 2035218887Sdim 2036219077Sdimvoid CStringChecker::checkDeadSymbols(SymbolReaper &SR, 2037219077Sdim CheckerContext &C) const { 2038218887Sdim if (!SR.hasDeadSymbols()) 2039218887Sdim return; 2040218887Sdim 2041234353Sdim ProgramStateRef state = C.getState(); 2042243830Sdim CStringLengthTy Entries = state->get<CStringLength>(); 2043218887Sdim if (Entries.isEmpty()) 2044218887Sdim return; 2045218887Sdim 2046243830Sdim CStringLengthTy::Factory &F = state->get_context<CStringLength>(); 2047243830Sdim for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); 2048218887Sdim I != E; ++I) { 2049218887Sdim SVal Len = I.getData(); 2050218887Sdim if (SymbolRef Sym = Len.getAsSymbol()) { 2051218887Sdim if (SR.isDead(Sym)) 2052218887Sdim Entries = F.remove(Entries, I.getKey()); 2053218887Sdim } 2054218887Sdim } 2055218887Sdim 2056218887Sdim state = state->set<CStringLength>(Entries); 2057234353Sdim C.addTransition(state); 2058218887Sdim} 2059219077Sdim 2060234353Sdim#define REGISTER_CHECKER(name) \ 2061234353Sdimvoid ento::register##name(CheckerManager &mgr) {\ 2062263508Sdim mgr.registerChecker<CStringChecker>()->Filter.Check##name = true; \ 2063219077Sdim} 2064234353Sdim 2065234353SdimREGISTER_CHECKER(CStringNullArg) 2066234353SdimREGISTER_CHECKER(CStringOutOfBounds) 2067234353SdimREGISTER_CHECKER(CStringBufferOverlap) 2068234353SdimREGISTER_CHECKER(CStringNotNullTerm) 2069234353Sdim 2070234353Sdimvoid ento::registerCStringCheckerBasic(CheckerManager &Mgr) { 2071234353Sdim registerCStringNullArg(Mgr); 2072234353Sdim} 2073