1226633Sdim//= CStringChecker.cpp - Checks calls to C string functions --------*- C++ -*-// 2218887Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6218887Sdim// 7218887Sdim//===----------------------------------------------------------------------===// 8218887Sdim// 9218887Sdim// This defines CStringChecker, which is an assortment of checks on calls 10218887Sdim// to functions in <string.h>. 11218887Sdim// 12218887Sdim//===----------------------------------------------------------------------===// 13218887Sdim 14344779Sdim#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 15234353Sdim#include "InterCheckerAPI.h" 16249423Sdim#include "clang/Basic/CharInfo.h" 17249423Sdim#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 18221345Sdim#include "clang/StaticAnalyzer/Core/Checker.h" 19218887Sdim#include "clang/StaticAnalyzer/Core/CheckerManager.h" 20353358Sdim#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.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" 25249423Sdim#include "llvm/Support/raw_ostream.h" 26218887Sdim 27218887Sdimusing namespace clang; 28218887Sdimusing namespace ento; 29218887Sdim 30218887Sdimnamespace { 31360784Sdimenum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 }; 32221345Sdimclass CStringChecker : public Checker< eval::Call, 33219077Sdim check::PreStmt<DeclStmt>, 34219077Sdim check::LiveSymbols, 35219077Sdim check::DeadSymbols, 36219077Sdim check::RegionChanges 37219077Sdim > { 38276479Sdim mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap, 39276479Sdim BT_NotCString, BT_AdditionOverflow; 40234353Sdim 41224145Sdim mutable const char *CurrentFunctionDescription; 42224145Sdim 43218887Sdimpublic: 44234353Sdim /// The filter is used to filter out the diagnostics which are not enabled by 45234353Sdim /// the user. 46234353Sdim struct CStringChecksFilter { 47234353Sdim DefaultBool CheckCStringNullArg; 48234353Sdim DefaultBool CheckCStringOutOfBounds; 49234353Sdim DefaultBool CheckCStringBufferOverlap; 50234353Sdim DefaultBool CheckCStringNotNullTerm; 51276479Sdim 52360784Sdim CheckerNameRef CheckNameCStringNullArg; 53360784Sdim CheckerNameRef CheckNameCStringOutOfBounds; 54360784Sdim CheckerNameRef CheckNameCStringBufferOverlap; 55360784Sdim CheckerNameRef CheckNameCStringNotNullTerm; 56234353Sdim }; 57234353Sdim 58234353Sdim CStringChecksFilter Filter; 59234353Sdim 60218887Sdim static void *getTag() { static int tag; return &tag; } 61218887Sdim 62353358Sdim bool evalCall(const CallEvent &Call, CheckerContext &C) const; 63219077Sdim void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const; 64234353Sdim void checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const; 65219077Sdim void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; 66218887Sdim 67296417Sdim ProgramStateRef 68234353Sdim checkRegionChanges(ProgramStateRef state, 69249423Sdim const InvalidatedSymbols *, 70226633Sdim ArrayRef<const MemRegion *> ExplicitRegions, 71234353Sdim ArrayRef<const MemRegion *> Regions, 72321369Sdim const LocationContext *LCtx, 73239462Sdim const CallEvent *Call) const; 74218887Sdim 75219077Sdim typedef void (CStringChecker::*FnCheck)(CheckerContext &, 76219077Sdim const CallExpr *) const; 77353358Sdim CallDescriptionMap<FnCheck> Callbacks = { 78353358Sdim {{CDF_MaybeBuiltin, "memcpy", 3}, &CStringChecker::evalMemcpy}, 79353358Sdim {{CDF_MaybeBuiltin, "mempcpy", 3}, &CStringChecker::evalMempcpy}, 80353358Sdim {{CDF_MaybeBuiltin, "memcmp", 3}, &CStringChecker::evalMemcmp}, 81353358Sdim {{CDF_MaybeBuiltin, "memmove", 3}, &CStringChecker::evalMemmove}, 82353358Sdim {{CDF_MaybeBuiltin, "memset", 3}, &CStringChecker::evalMemset}, 83353358Sdim {{CDF_MaybeBuiltin, "explicit_memset", 3}, &CStringChecker::evalMemset}, 84353358Sdim {{CDF_MaybeBuiltin, "strcpy", 2}, &CStringChecker::evalStrcpy}, 85353358Sdim {{CDF_MaybeBuiltin, "strncpy", 3}, &CStringChecker::evalStrncpy}, 86353358Sdim {{CDF_MaybeBuiltin, "stpcpy", 2}, &CStringChecker::evalStpcpy}, 87353358Sdim {{CDF_MaybeBuiltin, "strlcpy", 3}, &CStringChecker::evalStrlcpy}, 88353358Sdim {{CDF_MaybeBuiltin, "strcat", 2}, &CStringChecker::evalStrcat}, 89353358Sdim {{CDF_MaybeBuiltin, "strncat", 3}, &CStringChecker::evalStrncat}, 90353358Sdim {{CDF_MaybeBuiltin, "strlcat", 3}, &CStringChecker::evalStrlcat}, 91353358Sdim {{CDF_MaybeBuiltin, "strlen", 1}, &CStringChecker::evalstrLength}, 92353358Sdim {{CDF_MaybeBuiltin, "strnlen", 2}, &CStringChecker::evalstrnLength}, 93353358Sdim {{CDF_MaybeBuiltin, "strcmp", 2}, &CStringChecker::evalStrcmp}, 94353358Sdim {{CDF_MaybeBuiltin, "strncmp", 3}, &CStringChecker::evalStrncmp}, 95353358Sdim {{CDF_MaybeBuiltin, "strcasecmp", 2}, &CStringChecker::evalStrcasecmp}, 96353358Sdim {{CDF_MaybeBuiltin, "strncasecmp", 3}, &CStringChecker::evalStrncasecmp}, 97353358Sdim {{CDF_MaybeBuiltin, "strsep", 2}, &CStringChecker::evalStrsep}, 98353358Sdim {{CDF_MaybeBuiltin, "bcopy", 3}, &CStringChecker::evalBcopy}, 99353358Sdim {{CDF_MaybeBuiltin, "bcmp", 3}, &CStringChecker::evalMemcmp}, 100353358Sdim {{CDF_MaybeBuiltin, "bzero", 2}, &CStringChecker::evalBzero}, 101353358Sdim {{CDF_MaybeBuiltin, "explicit_bzero", 2}, &CStringChecker::evalBzero}, 102353358Sdim }; 103218887Sdim 104353358Sdim // These require a bit of special handling. 105353358Sdim CallDescription StdCopy{{"std", "copy"}, 3}, 106353358Sdim StdCopyBackward{{"std", "copy_backward"}, 3}; 107353358Sdim 108353358Sdim FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const; 109219077Sdim void evalMemcpy(CheckerContext &C, const CallExpr *CE) const; 110221345Sdim void evalMempcpy(CheckerContext &C, const CallExpr *CE) const; 111219077Sdim void evalMemmove(CheckerContext &C, const CallExpr *CE) const; 112219077Sdim void evalBcopy(CheckerContext &C, const CallExpr *CE) const; 113221345Sdim void evalCopyCommon(CheckerContext &C, const CallExpr *CE, 114234353Sdim ProgramStateRef state, 115226633Sdim const Expr *Size, 116226633Sdim const Expr *Source, 117226633Sdim const Expr *Dest, 118221345Sdim bool Restricted = false, 119221345Sdim bool IsMempcpy = false) const; 120218887Sdim 121219077Sdim void evalMemcmp(CheckerContext &C, const CallExpr *CE) const; 122218887Sdim 123219077Sdim void evalstrLength(CheckerContext &C, const CallExpr *CE) const; 124219077Sdim void evalstrnLength(CheckerContext &C, const CallExpr *CE) const; 125226633Sdim void evalstrLengthCommon(CheckerContext &C, 126296417Sdim const CallExpr *CE, 127219077Sdim bool IsStrnlen = false) const; 128218887Sdim 129219077Sdim void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; 130219077Sdim void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; 131219077Sdim void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; 132341825Sdim void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const; 133360784Sdim void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd, 134360784Sdim bool IsBounded, ConcatFnKind appendK, 135341825Sdim bool returnPtr = true) const; 136218887Sdim 137221345Sdim void evalStrcat(CheckerContext &C, const CallExpr *CE) const; 138221345Sdim void evalStrncat(CheckerContext &C, const CallExpr *CE) const; 139341825Sdim void evalStrlcat(CheckerContext &C, const CallExpr *CE) const; 140221345Sdim 141221345Sdim void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; 142221345Sdim void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; 143221345Sdim void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const; 144223017Sdim void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; 145226633Sdim void evalStrcmpCommon(CheckerContext &C, 146226633Sdim const CallExpr *CE, 147360784Sdim bool IsBounded = false, 148360784Sdim bool IgnoreCase = false) const; 149221345Sdim 150251662Sdim void evalStrsep(CheckerContext &C, const CallExpr *CE) const; 151251662Sdim 152309124Sdim void evalStdCopy(CheckerContext &C, const CallExpr *CE) const; 153309124Sdim void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const; 154309124Sdim void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const; 155321369Sdim void evalMemset(CheckerContext &C, const CallExpr *CE) const; 156344779Sdim void evalBzero(CheckerContext &C, const CallExpr *CE) const; 157309124Sdim 158218887Sdim // Utility methods 159234353Sdim std::pair<ProgramStateRef , ProgramStateRef > 160219077Sdim static assumeZero(CheckerContext &C, 161234353Sdim ProgramStateRef state, SVal V, QualType Ty); 162218887Sdim 163234353Sdim static ProgramStateRef setCStringLength(ProgramStateRef state, 164226633Sdim const MemRegion *MR, 165226633Sdim SVal strLength); 166219077Sdim static SVal getCStringLengthForRegion(CheckerContext &C, 167234353Sdim ProgramStateRef &state, 168226633Sdim const Expr *Ex, 169226633Sdim const MemRegion *MR, 170224145Sdim bool hypothetical); 171226633Sdim SVal getCStringLength(CheckerContext &C, 172234353Sdim ProgramStateRef &state, 173226633Sdim const Expr *Ex, 174226633Sdim SVal Buf, 175224145Sdim bool hypothetical = false) const; 176218887Sdim 177296417Sdim const StringLiteral *getCStringLiteral(CheckerContext &C, 178234353Sdim ProgramStateRef &state, 179296417Sdim const Expr *expr, 180221345Sdim SVal val) const; 181221345Sdim 182234353Sdim static ProgramStateRef InvalidateBuffer(CheckerContext &C, 183261991Sdim ProgramStateRef state, 184261991Sdim const Expr *Ex, SVal V, 185296417Sdim bool IsSourceBuffer, 186296417Sdim const Expr *Size); 187218887Sdim 188226633Sdim static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, 189219077Sdim const MemRegion *MR); 190218887Sdim 191344779Sdim static bool memsetAux(const Expr *DstBuffer, SVal CharE, 192341825Sdim const Expr *Size, CheckerContext &C, 193341825Sdim ProgramStateRef &State); 194341825Sdim 195218887Sdim // Re-usable checks 196234353Sdim ProgramStateRef checkNonNull(CheckerContext &C, 197234353Sdim ProgramStateRef state, 198226633Sdim const Expr *S, 199360784Sdim SVal l, 200360784Sdim unsigned IdxOfArg) const; 201234353Sdim ProgramStateRef CheckLocation(CheckerContext &C, 202234353Sdim ProgramStateRef state, 203226633Sdim const Expr *S, 204226633Sdim SVal l, 205276479Sdim const char *message = nullptr) const; 206234353Sdim ProgramStateRef CheckBufferAccess(CheckerContext &C, 207234353Sdim ProgramStateRef state, 208226633Sdim const Expr *Size, 209226633Sdim const Expr *FirstBuf, 210226633Sdim const Expr *SecondBuf, 211276479Sdim const char *firstMessage = nullptr, 212276479Sdim const char *secondMessage = nullptr, 213226633Sdim bool WarnAboutSize = false) const; 214226633Sdim 215234353Sdim ProgramStateRef CheckBufferAccess(CheckerContext &C, 216234353Sdim ProgramStateRef state, 217226633Sdim const Expr *Size, 218226633Sdim const Expr *Buf, 219276479Sdim const char *message = nullptr, 220226633Sdim bool WarnAboutSize = false) const { 221344779Sdim // This is a convenience overload. 222276479Sdim return CheckBufferAccess(C, state, Size, Buf, nullptr, message, nullptr, 223224145Sdim WarnAboutSize); 224224145Sdim } 225234353Sdim ProgramStateRef CheckOverlap(CheckerContext &C, 226234353Sdim ProgramStateRef state, 227226633Sdim const Expr *Size, 228226633Sdim const Expr *First, 229226633Sdim const Expr *Second) const; 230226633Sdim void emitOverlapBug(CheckerContext &C, 231234353Sdim ProgramStateRef state, 232226633Sdim const Stmt *First, 233226633Sdim const Stmt *Second) const; 234226633Sdim 235341825Sdim void emitNullArgBug(CheckerContext &C, ProgramStateRef State, const Stmt *S, 236341825Sdim StringRef WarningMsg) const; 237341825Sdim void emitOutOfBoundsBug(CheckerContext &C, ProgramStateRef State, 238341825Sdim const Stmt *S, StringRef WarningMsg) const; 239341825Sdim void emitNotCStringBug(CheckerContext &C, ProgramStateRef State, 240341825Sdim const Stmt *S, StringRef WarningMsg) const; 241341825Sdim void emitAdditionOverflowBug(CheckerContext &C, ProgramStateRef State) const; 242341825Sdim 243234353Sdim ProgramStateRef checkAdditionOverflow(CheckerContext &C, 244234353Sdim ProgramStateRef state, 245226633Sdim NonLoc left, 246226633Sdim NonLoc right) const; 247296417Sdim 248296417Sdim // Return true if the destination buffer of the copy function may be in bound. 249296417Sdim // Expects SVal of Size to be positive and unsigned. 250296417Sdim // Expects SVal of FirstBuf to be a FieldRegion. 251296417Sdim static bool IsFirstBufInBound(CheckerContext &C, 252296417Sdim ProgramStateRef state, 253296417Sdim const Expr *FirstBuf, 254296417Sdim const Expr *Size); 255218887Sdim}; 256218887Sdim 257218887Sdim} //end anonymous namespace 258218887Sdim 259243830SdimREGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal) 260218887Sdim 261218887Sdim//===----------------------------------------------------------------------===// 262218887Sdim// Individual checks and utility methods. 263218887Sdim//===----------------------------------------------------------------------===// 264218887Sdim 265234353Sdimstd::pair<ProgramStateRef , ProgramStateRef > 266234353SdimCStringChecker::assumeZero(CheckerContext &C, ProgramStateRef state, SVal V, 267218887Sdim QualType Ty) { 268249423Sdim Optional<DefinedSVal> val = V.getAs<DefinedSVal>(); 269218887Sdim if (!val) 270234353Sdim return std::pair<ProgramStateRef , ProgramStateRef >(state, state); 271218887Sdim 272218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 273218887Sdim DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty); 274218887Sdim return state->assume(svalBuilder.evalEQ(state, *val, zero)); 275218887Sdim} 276218887Sdim 277234353SdimProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, 278234353Sdim ProgramStateRef state, 279360784Sdim const Expr *S, SVal l, 280360784Sdim unsigned IdxOfArg) const { 281218887Sdim // If a previous check has failed, propagate the failure. 282218887Sdim if (!state) 283276479Sdim return nullptr; 284218887Sdim 285234353Sdim ProgramStateRef stateNull, stateNonNull; 286276479Sdim std::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType()); 287218887Sdim 288218887Sdim if (stateNull && !stateNonNull) { 289341825Sdim if (Filter.CheckCStringNullArg) { 290341825Sdim SmallString<80> buf; 291360784Sdim llvm::raw_svector_ostream OS(buf); 292341825Sdim assert(CurrentFunctionDescription); 293360784Sdim OS << "Null pointer passed as " << IdxOfArg 294360784Sdim << llvm::getOrdinalSuffix(IdxOfArg) << " argument to " 295360784Sdim << CurrentFunctionDescription; 296234353Sdim 297360784Sdim emitNullArgBug(C, stateNull, S, OS.str()); 298341825Sdim } 299276479Sdim return nullptr; 300218887Sdim } 301218887Sdim 302218887Sdim // From here on, assume that the value is non-null. 303218887Sdim assert(stateNonNull); 304218887Sdim return stateNonNull; 305218887Sdim} 306218887Sdim 307218887Sdim// FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor? 308234353SdimProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, 309234353Sdim ProgramStateRef state, 310218887Sdim const Expr *S, SVal l, 311224145Sdim const char *warningMsg) const { 312218887Sdim // If a previous check has failed, propagate the failure. 313218887Sdim if (!state) 314276479Sdim return nullptr; 315218887Sdim 316218887Sdim // Check for out of bound array element access. 317218887Sdim const MemRegion *R = l.getAsRegion(); 318218887Sdim if (!R) 319218887Sdim return state; 320218887Sdim 321218887Sdim const ElementRegion *ER = dyn_cast<ElementRegion>(R); 322218887Sdim if (!ER) 323218887Sdim return state; 324218887Sdim 325327952Sdim if (ER->getValueType() != C.getASTContext().CharTy) 326327952Sdim return state; 327218887Sdim 328218887Sdim // Get the size of the array. 329218887Sdim const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); 330218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 331296417Sdim SVal Extent = 332224145Sdim svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); 333249423Sdim DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>(); 334218887Sdim 335218887Sdim // Get the index of the accessed element. 336249423Sdim DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 337218887Sdim 338234353Sdim ProgramStateRef StInBound = state->assumeInBound(Idx, Size, true); 339234353Sdim ProgramStateRef StOutBound = state->assumeInBound(Idx, Size, false); 340218887Sdim if (StOutBound && !StInBound) { 341341825Sdim // These checks are either enabled by the CString out-of-bounds checker 342341825Sdim // explicitly or implicitly by the Malloc checker. 343341825Sdim // In the latter case we only do modeling but do not emit warning. 344341825Sdim if (!Filter.CheckCStringOutOfBounds) 345276479Sdim return nullptr; 346341825Sdim // Emit a bug report. 347224145Sdim if (warningMsg) { 348341825Sdim emitOutOfBoundsBug(C, StOutBound, S, warningMsg); 349218887Sdim } else { 350224145Sdim assert(CurrentFunctionDescription); 351224145Sdim assert(CurrentFunctionDescription[0] != '\0'); 352224145Sdim 353234353Sdim SmallString<80> buf; 354224145Sdim llvm::raw_svector_ostream os(buf); 355249423Sdim os << toUppercase(CurrentFunctionDescription[0]) 356224145Sdim << &CurrentFunctionDescription[1] 357224145Sdim << " accesses out-of-bound array element"; 358341825Sdim emitOutOfBoundsBug(C, StOutBound, S, os.str()); 359218887Sdim } 360276479Sdim return nullptr; 361218887Sdim } 362296417Sdim 363218887Sdim // Array bound check succeeded. From this point forward the array bound 364218887Sdim // should always succeed. 365218887Sdim return StInBound; 366218887Sdim} 367218887Sdim 368234353SdimProgramStateRef CStringChecker::CheckBufferAccess(CheckerContext &C, 369234353Sdim ProgramStateRef state, 370218887Sdim const Expr *Size, 371218887Sdim const Expr *FirstBuf, 372218887Sdim const Expr *SecondBuf, 373224145Sdim const char *firstMessage, 374224145Sdim const char *secondMessage, 375224145Sdim bool WarnAboutSize) const { 376218887Sdim // If a previous check has failed, propagate the failure. 377218887Sdim if (!state) 378276479Sdim return nullptr; 379218887Sdim 380218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 381224145Sdim ASTContext &Ctx = svalBuilder.getContext(); 382234353Sdim const LocationContext *LCtx = C.getLocationContext(); 383218887Sdim 384218887Sdim QualType sizeTy = Size->getType(); 385218887Sdim QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); 386218887Sdim 387218887Sdim // Check that the first buffer is non-null. 388341825Sdim SVal BufVal = C.getSVal(FirstBuf); 389360784Sdim state = checkNonNull(C, state, FirstBuf, BufVal, 1); 390218887Sdim if (!state) 391276479Sdim return nullptr; 392218887Sdim 393234353Sdim // If out-of-bounds checking is turned off, skip the rest. 394234353Sdim if (!Filter.CheckCStringOutOfBounds) 395234353Sdim return state; 396234353Sdim 397218887Sdim // Get the access length and make sure it is known. 398224145Sdim // FIXME: This assumes the caller has already checked that the access length 399224145Sdim // is positive. And that it's unsigned. 400341825Sdim SVal LengthVal = C.getSVal(Size); 401249423Sdim Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 402218887Sdim if (!Length) 403218887Sdim return state; 404218887Sdim 405218887Sdim // Compute the offset of the last element to be accessed: size-1. 406249423Sdim NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 407341825Sdim SVal Offset = svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy); 408341825Sdim if (Offset.isUnknown()) 409341825Sdim return nullptr; 410341825Sdim NonLoc LastOffset = Offset.castAs<NonLoc>(); 411218887Sdim 412221345Sdim // Check that the first buffer is sufficiently long. 413218887Sdim SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); 414249423Sdim if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { 415224145Sdim const Expr *warningExpr = (WarnAboutSize ? Size : FirstBuf); 416224145Sdim 417218887Sdim SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, 418218887Sdim LastOffset, PtrTy); 419224145Sdim state = CheckLocation(C, state, warningExpr, BufEnd, firstMessage); 420218887Sdim 421218887Sdim // If the buffer isn't large enough, abort. 422218887Sdim if (!state) 423276479Sdim return nullptr; 424218887Sdim } 425218887Sdim 426218887Sdim // If there's a second buffer, check it as well. 427218887Sdim if (SecondBuf) { 428234353Sdim BufVal = state->getSVal(SecondBuf, LCtx); 429360784Sdim state = checkNonNull(C, state, SecondBuf, BufVal, 2); 430218887Sdim if (!state) 431276479Sdim return nullptr; 432218887Sdim 433218887Sdim BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType()); 434249423Sdim if (Optional<Loc> BufLoc = BufStart.getAs<Loc>()) { 435224145Sdim const Expr *warningExpr = (WarnAboutSize ? Size : SecondBuf); 436224145Sdim 437218887Sdim SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, 438218887Sdim LastOffset, PtrTy); 439224145Sdim state = CheckLocation(C, state, warningExpr, BufEnd, secondMessage); 440218887Sdim } 441218887Sdim } 442218887Sdim 443218887Sdim // Large enough or not, return this state! 444218887Sdim return state; 445218887Sdim} 446218887Sdim 447234353SdimProgramStateRef CStringChecker::CheckOverlap(CheckerContext &C, 448234353Sdim ProgramStateRef state, 449218887Sdim const Expr *Size, 450218887Sdim const Expr *First, 451219077Sdim const Expr *Second) const { 452234353Sdim if (!Filter.CheckCStringBufferOverlap) 453234353Sdim return state; 454234353Sdim 455218887Sdim // Do a simple check for overlap: if the two arguments are from the same 456218887Sdim // buffer, see if the end of the first is greater than the start of the second 457218887Sdim // or vice versa. 458218887Sdim 459218887Sdim // If a previous check has failed, propagate the failure. 460218887Sdim if (!state) 461276479Sdim return nullptr; 462218887Sdim 463234353Sdim ProgramStateRef stateTrue, stateFalse; 464218887Sdim 465218887Sdim // Get the buffer values and make sure they're known locations. 466234353Sdim const LocationContext *LCtx = C.getLocationContext(); 467234353Sdim SVal firstVal = state->getSVal(First, LCtx); 468234353Sdim SVal secondVal = state->getSVal(Second, LCtx); 469218887Sdim 470249423Sdim Optional<Loc> firstLoc = firstVal.getAs<Loc>(); 471218887Sdim if (!firstLoc) 472218887Sdim return state; 473218887Sdim 474249423Sdim Optional<Loc> secondLoc = secondVal.getAs<Loc>(); 475218887Sdim if (!secondLoc) 476218887Sdim return state; 477218887Sdim 478218887Sdim // Are the two values the same? 479296417Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 480276479Sdim std::tie(stateTrue, stateFalse) = 481218887Sdim state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc)); 482218887Sdim 483218887Sdim if (stateTrue && !stateFalse) { 484218887Sdim // If the values are known to be equal, that's automatically an overlap. 485218887Sdim emitOverlapBug(C, stateTrue, First, Second); 486276479Sdim return nullptr; 487218887Sdim } 488218887Sdim 489218887Sdim // assume the two expressions are not equal. 490218887Sdim assert(stateFalse); 491218887Sdim state = stateFalse; 492218887Sdim 493218887Sdim // Which value comes first? 494224145Sdim QualType cmpTy = svalBuilder.getConditionType(); 495218887Sdim SVal reverse = svalBuilder.evalBinOpLL(state, BO_GT, 496218887Sdim *firstLoc, *secondLoc, cmpTy); 497249423Sdim Optional<DefinedOrUnknownSVal> reverseTest = 498249423Sdim reverse.getAs<DefinedOrUnknownSVal>(); 499218887Sdim if (!reverseTest) 500218887Sdim return state; 501218887Sdim 502276479Sdim std::tie(stateTrue, stateFalse) = state->assume(*reverseTest); 503218887Sdim if (stateTrue) { 504218887Sdim if (stateFalse) { 505218887Sdim // If we don't know which one comes first, we can't perform this test. 506218887Sdim return state; 507218887Sdim } else { 508218887Sdim // Switch the values so that firstVal is before secondVal. 509249423Sdim std::swap(firstLoc, secondLoc); 510218887Sdim 511218887Sdim // Switch the Exprs as well, so that they still correspond. 512249423Sdim std::swap(First, Second); 513218887Sdim } 514218887Sdim } 515218887Sdim 516218887Sdim // Get the length, and make sure it too is known. 517234353Sdim SVal LengthVal = state->getSVal(Size, LCtx); 518249423Sdim Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 519218887Sdim if (!Length) 520218887Sdim return state; 521218887Sdim 522218887Sdim // Convert the first buffer's start address to char*. 523218887Sdim // Bail out if the cast fails. 524224145Sdim ASTContext &Ctx = svalBuilder.getContext(); 525218887Sdim QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); 526296417Sdim SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy, 527224145Sdim First->getType()); 528249423Sdim Optional<Loc> FirstStartLoc = FirstStart.getAs<Loc>(); 529218887Sdim if (!FirstStartLoc) 530218887Sdim return state; 531218887Sdim 532218887Sdim // Compute the end of the first buffer. Bail out if THAT fails. 533218887Sdim SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add, 534218887Sdim *FirstStartLoc, *Length, CharPtrTy); 535249423Sdim Optional<Loc> FirstEndLoc = FirstEnd.getAs<Loc>(); 536218887Sdim if (!FirstEndLoc) 537218887Sdim return state; 538218887Sdim 539218887Sdim // Is the end of the first buffer past the start of the second buffer? 540218887Sdim SVal Overlap = svalBuilder.evalBinOpLL(state, BO_GT, 541218887Sdim *FirstEndLoc, *secondLoc, cmpTy); 542249423Sdim Optional<DefinedOrUnknownSVal> OverlapTest = 543249423Sdim Overlap.getAs<DefinedOrUnknownSVal>(); 544218887Sdim if (!OverlapTest) 545218887Sdim return state; 546218887Sdim 547276479Sdim std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest); 548218887Sdim 549218887Sdim if (stateTrue && !stateFalse) { 550218887Sdim // Overlap! 551218887Sdim emitOverlapBug(C, stateTrue, First, Second); 552276479Sdim return nullptr; 553218887Sdim } 554218887Sdim 555218887Sdim // assume the two expressions don't overlap. 556218887Sdim assert(stateFalse); 557218887Sdim return stateFalse; 558218887Sdim} 559218887Sdim 560234353Sdimvoid CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, 561219077Sdim const Stmt *First, const Stmt *Second) const { 562296417Sdim ExplodedNode *N = C.generateErrorNode(state); 563218887Sdim if (!N) 564218887Sdim return; 565218887Sdim 566218887Sdim if (!BT_Overlap) 567276479Sdim BT_Overlap.reset(new BugType(Filter.CheckNameCStringBufferOverlap, 568276479Sdim categories::UnixAPI, "Improper arguments")); 569218887Sdim 570218887Sdim // Generate a report for this bug. 571360784Sdim auto report = std::make_unique<PathSensitiveBugReport>( 572288943Sdim *BT_Overlap, "Arguments must not be overlapping buffers", N); 573218887Sdim report->addRange(First->getSourceRange()); 574218887Sdim report->addRange(Second->getSourceRange()); 575218887Sdim 576288943Sdim C.emitReport(std::move(report)); 577218887Sdim} 578218887Sdim 579341825Sdimvoid CStringChecker::emitNullArgBug(CheckerContext &C, ProgramStateRef State, 580341825Sdim const Stmt *S, StringRef WarningMsg) const { 581341825Sdim if (ExplodedNode *N = C.generateErrorNode(State)) { 582341825Sdim if (!BT_Null) 583341825Sdim BT_Null.reset(new BuiltinBug( 584341825Sdim Filter.CheckNameCStringNullArg, categories::UnixAPI, 585341825Sdim "Null pointer argument in call to byte string function")); 586341825Sdim 587341825Sdim BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Null.get()); 588360784Sdim auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); 589341825Sdim Report->addRange(S->getSourceRange()); 590344779Sdim if (const auto *Ex = dyn_cast<Expr>(S)) 591344779Sdim bugreporter::trackExpressionValue(N, Ex, *Report); 592341825Sdim C.emitReport(std::move(Report)); 593341825Sdim } 594341825Sdim} 595341825Sdim 596341825Sdimvoid CStringChecker::emitOutOfBoundsBug(CheckerContext &C, 597341825Sdim ProgramStateRef State, const Stmt *S, 598341825Sdim StringRef WarningMsg) const { 599341825Sdim if (ExplodedNode *N = C.generateErrorNode(State)) { 600341825Sdim if (!BT_Bounds) 601341825Sdim BT_Bounds.reset(new BuiltinBug( 602341825Sdim Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds 603341825Sdim : Filter.CheckNameCStringNullArg, 604341825Sdim "Out-of-bound array access", 605341825Sdim "Byte string function accesses out-of-bound array element")); 606341825Sdim 607341825Sdim BuiltinBug *BT = static_cast<BuiltinBug *>(BT_Bounds.get()); 608341825Sdim 609341825Sdim // FIXME: It would be nice to eventually make this diagnostic more clear, 610341825Sdim // e.g., by referencing the original declaration or by saying *why* this 611341825Sdim // reference is outside the range. 612360784Sdim auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N); 613341825Sdim Report->addRange(S->getSourceRange()); 614341825Sdim C.emitReport(std::move(Report)); 615341825Sdim } 616341825Sdim} 617341825Sdim 618341825Sdimvoid CStringChecker::emitNotCStringBug(CheckerContext &C, ProgramStateRef State, 619341825Sdim const Stmt *S, 620341825Sdim StringRef WarningMsg) const { 621341825Sdim if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { 622341825Sdim if (!BT_NotCString) 623341825Sdim BT_NotCString.reset(new BuiltinBug( 624341825Sdim Filter.CheckNameCStringNotNullTerm, categories::UnixAPI, 625341825Sdim "Argument is not a null-terminated string.")); 626341825Sdim 627360784Sdim auto Report = 628360784Sdim std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); 629341825Sdim 630341825Sdim Report->addRange(S->getSourceRange()); 631341825Sdim C.emitReport(std::move(Report)); 632341825Sdim } 633341825Sdim} 634341825Sdim 635341825Sdimvoid CStringChecker::emitAdditionOverflowBug(CheckerContext &C, 636341825Sdim ProgramStateRef State) const { 637341825Sdim if (ExplodedNode *N = C.generateErrorNode(State)) { 638341825Sdim if (!BT_NotCString) 639341825Sdim BT_NotCString.reset( 640341825Sdim new BuiltinBug(Filter.CheckNameCStringOutOfBounds, "API", 641341825Sdim "Sum of expressions causes overflow.")); 642341825Sdim 643341825Sdim // This isn't a great error message, but this should never occur in real 644341825Sdim // code anyway -- you'd have to create a buffer longer than a size_t can 645341825Sdim // represent, which is sort of a contradiction. 646341825Sdim const char *WarningMsg = 647341825Sdim "This expression will create a string whose length is too big to " 648341825Sdim "be represented as a size_t"; 649341825Sdim 650360784Sdim auto Report = 651360784Sdim std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N); 652341825Sdim C.emitReport(std::move(Report)); 653341825Sdim } 654341825Sdim} 655341825Sdim 656234353SdimProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, 657234353Sdim ProgramStateRef state, 658224145Sdim NonLoc left, 659224145Sdim NonLoc right) const { 660234353Sdim // If out-of-bounds checking is turned off, skip the rest. 661234353Sdim if (!Filter.CheckCStringOutOfBounds) 662234353Sdim return state; 663234353Sdim 664224145Sdim // If a previous check has failed, propagate the failure. 665224145Sdim if (!state) 666276479Sdim return nullptr; 667224145Sdim 668224145Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 669224145Sdim BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); 670224145Sdim 671224145Sdim QualType sizeTy = svalBuilder.getContext().getSizeType(); 672224145Sdim const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); 673224145Sdim NonLoc maxVal = svalBuilder.makeIntVal(maxValInt); 674224145Sdim 675234353Sdim SVal maxMinusRight; 676249423Sdim if (right.getAs<nonloc::ConcreteInt>()) { 677234353Sdim maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, right, 678234353Sdim sizeTy); 679234353Sdim } else { 680224145Sdim // Try switching the operands. (The order of these two assignments is 681224145Sdim // important!) 682296417Sdim maxMinusRight = svalBuilder.evalBinOpNN(state, BO_Sub, maxVal, left, 683224145Sdim sizeTy); 684224145Sdim left = right; 685224145Sdim } 686224145Sdim 687249423Sdim if (Optional<NonLoc> maxMinusRightNL = maxMinusRight.getAs<NonLoc>()) { 688224145Sdim QualType cmpTy = svalBuilder.getConditionType(); 689224145Sdim // If left > max - right, we have an overflow. 690224145Sdim SVal willOverflow = svalBuilder.evalBinOpNN(state, BO_GT, left, 691224145Sdim *maxMinusRightNL, cmpTy); 692224145Sdim 693234353Sdim ProgramStateRef stateOverflow, stateOkay; 694276479Sdim std::tie(stateOverflow, stateOkay) = 695249423Sdim state->assume(willOverflow.castAs<DefinedOrUnknownSVal>()); 696224145Sdim 697224145Sdim if (stateOverflow && !stateOkay) { 698224145Sdim // We have an overflow. Emit a bug report. 699341825Sdim emitAdditionOverflowBug(C, stateOverflow); 700276479Sdim return nullptr; 701224145Sdim } 702224145Sdim 703224145Sdim // From now on, assume an overflow didn't occur. 704224145Sdim assert(stateOkay); 705224145Sdim state = stateOkay; 706224145Sdim } 707224145Sdim 708224145Sdim return state; 709224145Sdim} 710224145Sdim 711234353SdimProgramStateRef CStringChecker::setCStringLength(ProgramStateRef state, 712218887Sdim const MemRegion *MR, 713218887Sdim SVal strLength) { 714218887Sdim assert(!strLength.isUndef() && "Attempt to set an undefined string length"); 715218887Sdim 716218887Sdim MR = MR->StripCasts(); 717218887Sdim 718218887Sdim switch (MR->getKind()) { 719218887Sdim case MemRegion::StringRegionKind: 720218887Sdim // FIXME: This can happen if we strcpy() into a string region. This is 721218887Sdim // undefined [C99 6.4.5p6], but we should still warn about it. 722218887Sdim return state; 723218887Sdim 724218887Sdim case MemRegion::SymbolicRegionKind: 725218887Sdim case MemRegion::AllocaRegionKind: 726218887Sdim case MemRegion::VarRegionKind: 727218887Sdim case MemRegion::FieldRegionKind: 728218887Sdim case MemRegion::ObjCIvarRegionKind: 729224145Sdim // These are the types we can currently track string lengths for. 730224145Sdim break; 731218887Sdim 732218887Sdim case MemRegion::ElementRegionKind: 733218887Sdim // FIXME: Handle element regions by upper-bounding the parent region's 734218887Sdim // string length. 735218887Sdim return state; 736218887Sdim 737218887Sdim default: 738218887Sdim // Other regions (mostly non-data) can't have a reliable C string length. 739218887Sdim // For now, just ignore the change. 740218887Sdim // FIXME: These are rare but not impossible. We should output some kind of 741218887Sdim // warning for things like strcpy((char[]){'a', 0}, "b"); 742218887Sdim return state; 743218887Sdim } 744224145Sdim 745224145Sdim if (strLength.isUnknown()) 746224145Sdim return state->remove<CStringLength>(MR); 747224145Sdim 748224145Sdim return state->set<CStringLength>(MR, strLength); 749218887Sdim} 750218887Sdim 751218887SdimSVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, 752234353Sdim ProgramStateRef &state, 753218887Sdim const Expr *Ex, 754224145Sdim const MemRegion *MR, 755224145Sdim bool hypothetical) { 756224145Sdim if (!hypothetical) { 757224145Sdim // If there's a recorded length, go ahead and return it. 758224145Sdim const SVal *Recorded = state->get<CStringLength>(MR); 759224145Sdim if (Recorded) 760224145Sdim return *Recorded; 761224145Sdim } 762261991Sdim 763218887Sdim // Otherwise, get a new symbol and update the state. 764218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 765218887Sdim QualType sizeTy = svalBuilder.getContext().getSizeType(); 766219077Sdim SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), 767243830Sdim MR, Ex, sizeTy, 768314564Sdim C.getLocationContext(), 769243830Sdim C.blockCount()); 770224145Sdim 771261991Sdim if (!hypothetical) { 772261991Sdim if (Optional<NonLoc> strLn = strLength.getAs<NonLoc>()) { 773261991Sdim // In case of unbounded calls strlen etc bound the range to SIZE_MAX/4 774261991Sdim BasicValueFactory &BVF = svalBuilder.getBasicValueFactory(); 775261991Sdim const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy); 776261991Sdim llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4); 777261991Sdim const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt, 778261991Sdim fourInt); 779261991Sdim NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt); 780261991Sdim SVal evalLength = svalBuilder.evalBinOpNN(state, BO_LE, *strLn, 781261991Sdim maxLength, sizeTy); 782261991Sdim state = state->assume(evalLength.castAs<DefinedOrUnknownSVal>(), true); 783261991Sdim } 784224145Sdim state = state->set<CStringLength>(MR, strLength); 785261991Sdim } 786224145Sdim 787218887Sdim return strLength; 788218887Sdim} 789218887Sdim 790234353SdimSVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, 791224145Sdim const Expr *Ex, SVal Buf, 792224145Sdim bool hypothetical) const { 793218887Sdim const MemRegion *MR = Buf.getAsRegion(); 794218887Sdim if (!MR) { 795218887Sdim // If we can't get a region, see if it's something we /know/ isn't a 796218887Sdim // C string. In the context of locations, the only time we can issue such 797218887Sdim // a warning is for labels. 798249423Sdim if (Optional<loc::GotoLabel> Label = Buf.getAs<loc::GotoLabel>()) { 799341825Sdim if (Filter.CheckCStringNotNullTerm) { 800234353Sdim SmallString<120> buf; 801218887Sdim llvm::raw_svector_ostream os(buf); 802224145Sdim assert(CurrentFunctionDescription); 803224145Sdim os << "Argument to " << CurrentFunctionDescription 804224145Sdim << " is the address of the label '" << Label->getLabel()->getName() 805218887Sdim << "', which is not a null-terminated string"; 806218887Sdim 807341825Sdim emitNotCStringBug(C, state, Ex, os.str()); 808218887Sdim } 809234353Sdim return UndefinedVal(); 810218887Sdim } 811218887Sdim 812218887Sdim // If it's not a region and not a label, give up. 813218887Sdim return UnknownVal(); 814218887Sdim } 815218887Sdim 816218887Sdim // If we have a region, strip casts from it and see if we can figure out 817218887Sdim // its length. For anything we can't figure out, just return UnknownVal. 818218887Sdim MR = MR->StripCasts(); 819218887Sdim 820218887Sdim switch (MR->getKind()) { 821218887Sdim case MemRegion::StringRegionKind: { 822218887Sdim // Modifying the contents of string regions is undefined [C99 6.4.5p6], 823218887Sdim // so we can assume that the byte length is the correct C string length. 824218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 825218887Sdim QualType sizeTy = svalBuilder.getContext().getSizeType(); 826218887Sdim const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral(); 827218887Sdim return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy); 828218887Sdim } 829218887Sdim case MemRegion::SymbolicRegionKind: 830218887Sdim case MemRegion::AllocaRegionKind: 831218887Sdim case MemRegion::VarRegionKind: 832218887Sdim case MemRegion::FieldRegionKind: 833218887Sdim case MemRegion::ObjCIvarRegionKind: 834224145Sdim return getCStringLengthForRegion(C, state, Ex, MR, hypothetical); 835218887Sdim case MemRegion::CompoundLiteralRegionKind: 836218887Sdim // FIXME: Can we track this? Is it necessary? 837218887Sdim return UnknownVal(); 838218887Sdim case MemRegion::ElementRegionKind: 839218887Sdim // FIXME: How can we handle this? It's not good enough to subtract the 840218887Sdim // offset from the base string length; consider "123\x00567" and &a[5]. 841218887Sdim return UnknownVal(); 842218887Sdim default: 843218887Sdim // Other regions (mostly non-data) can't have a reliable C string length. 844218887Sdim // In this case, an error is emitted and UndefinedVal is returned. 845218887Sdim // The caller should always be prepared to handle this case. 846341825Sdim if (Filter.CheckCStringNotNullTerm) { 847234353Sdim SmallString<120> buf; 848218887Sdim llvm::raw_svector_ostream os(buf); 849218887Sdim 850224145Sdim assert(CurrentFunctionDescription); 851224145Sdim os << "Argument to " << CurrentFunctionDescription << " is "; 852218887Sdim 853218887Sdim if (SummarizeRegion(os, C.getASTContext(), MR)) 854218887Sdim os << ", which is not a null-terminated string"; 855218887Sdim else 856218887Sdim os << "not a null-terminated string"; 857218887Sdim 858341825Sdim emitNotCStringBug(C, state, Ex, os.str()); 859218887Sdim } 860218887Sdim return UndefinedVal(); 861218887Sdim } 862218887Sdim} 863218887Sdim 864221345Sdimconst StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C, 865234353Sdim ProgramStateRef &state, const Expr *expr, SVal val) const { 866221345Sdim 867221345Sdim // Get the memory region pointed to by the val. 868221345Sdim const MemRegion *bufRegion = val.getAsRegion(); 869221345Sdim if (!bufRegion) 870276479Sdim return nullptr; 871221345Sdim 872221345Sdim // Strip casts off the memory region. 873221345Sdim bufRegion = bufRegion->StripCasts(); 874221345Sdim 875221345Sdim // Cast the memory region to a string region. 876221345Sdim const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion); 877221345Sdim if (!strRegion) 878276479Sdim return nullptr; 879221345Sdim 880221345Sdim // Return the actual string in the string region. 881221345Sdim return strRegion->getStringLiteral(); 882221345Sdim} 883221345Sdim 884296417Sdimbool CStringChecker::IsFirstBufInBound(CheckerContext &C, 885296417Sdim ProgramStateRef state, 886296417Sdim const Expr *FirstBuf, 887296417Sdim const Expr *Size) { 888296417Sdim // If we do not know that the buffer is long enough we return 'true'. 889296417Sdim // Otherwise the parent region of this field region would also get 890296417Sdim // invalidated, which would lead to warnings based on an unknown state. 891296417Sdim 892296417Sdim // Originally copied from CheckBufferAccess and CheckLocation. 893296417Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 894296417Sdim ASTContext &Ctx = svalBuilder.getContext(); 895296417Sdim const LocationContext *LCtx = C.getLocationContext(); 896296417Sdim 897296417Sdim QualType sizeTy = Size->getType(); 898296417Sdim QualType PtrTy = Ctx.getPointerType(Ctx.CharTy); 899296417Sdim SVal BufVal = state->getSVal(FirstBuf, LCtx); 900296417Sdim 901296417Sdim SVal LengthVal = state->getSVal(Size, LCtx); 902296417Sdim Optional<NonLoc> Length = LengthVal.getAs<NonLoc>(); 903296417Sdim if (!Length) 904296417Sdim return true; // cf top comment. 905296417Sdim 906296417Sdim // Compute the offset of the last element to be accessed: size-1. 907296417Sdim NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 908341825Sdim SVal Offset = svalBuilder.evalBinOpNN(state, BO_Sub, *Length, One, sizeTy); 909341825Sdim if (Offset.isUnknown()) 910341825Sdim return true; // cf top comment 911341825Sdim NonLoc LastOffset = Offset.castAs<NonLoc>(); 912296417Sdim 913296417Sdim // Check that the first buffer is sufficiently long. 914296417Sdim SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType()); 915296417Sdim Optional<Loc> BufLoc = BufStart.getAs<Loc>(); 916296417Sdim if (!BufLoc) 917296417Sdim return true; // cf top comment. 918296417Sdim 919296417Sdim SVal BufEnd = 920296417Sdim svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc, LastOffset, PtrTy); 921296417Sdim 922296417Sdim // Check for out of bound array element access. 923296417Sdim const MemRegion *R = BufEnd.getAsRegion(); 924296417Sdim if (!R) 925296417Sdim return true; // cf top comment. 926296417Sdim 927296417Sdim const ElementRegion *ER = dyn_cast<ElementRegion>(R); 928296417Sdim if (!ER) 929296417Sdim return true; // cf top comment. 930296417Sdim 931327952Sdim // FIXME: Does this crash when a non-standard definition 932327952Sdim // of a library function is encountered? 933296417Sdim assert(ER->getValueType() == C.getASTContext().CharTy && 934296417Sdim "IsFirstBufInBound should only be called with char* ElementRegions"); 935296417Sdim 936296417Sdim // Get the size of the array. 937296417Sdim const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion()); 938296417Sdim SVal Extent = 939296417Sdim svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder)); 940296417Sdim DefinedOrUnknownSVal ExtentSize = Extent.castAs<DefinedOrUnknownSVal>(); 941296417Sdim 942296417Sdim // Get the index of the accessed element. 943296417Sdim DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>(); 944296417Sdim 945296417Sdim ProgramStateRef StInBound = state->assumeInBound(Idx, ExtentSize, true); 946296417Sdim 947296417Sdim return static_cast<bool>(StInBound); 948296417Sdim} 949296417Sdim 950234353SdimProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, 951261991Sdim ProgramStateRef state, 952261991Sdim const Expr *E, SVal V, 953296417Sdim bool IsSourceBuffer, 954296417Sdim const Expr *Size) { 955249423Sdim Optional<Loc> L = V.getAs<Loc>(); 956218887Sdim if (!L) 957218887Sdim return state; 958218887Sdim 959218887Sdim // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes 960218887Sdim // some assumptions about the value that CFRefCount can't. Even so, it should 961218887Sdim // probably be refactored. 962249423Sdim if (Optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) { 963218887Sdim const MemRegion *R = MR->getRegion()->StripCasts(); 964218887Sdim 965218887Sdim // Are we dealing with an ElementRegion? If so, we should be invalidating 966218887Sdim // the super-region. 967218887Sdim if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) { 968218887Sdim R = ER->getSuperRegion(); 969218887Sdim // FIXME: What about layers of ElementRegions? 970218887Sdim } 971218887Sdim 972218887Sdim // Invalidate this region. 973234353Sdim const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); 974261991Sdim 975261991Sdim bool CausesPointerEscape = false; 976261991Sdim RegionAndSymbolInvalidationTraits ITraits; 977261991Sdim // Invalidate and escape only indirect regions accessible through the source 978261991Sdim // buffer. 979261991Sdim if (IsSourceBuffer) { 980309124Sdim ITraits.setTrait(R->getBaseRegion(), 981261991Sdim RegionAndSymbolInvalidationTraits::TK_PreserveContents); 982261991Sdim ITraits.setTrait(R, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); 983261991Sdim CausesPointerEscape = true; 984296417Sdim } else { 985296417Sdim const MemRegion::Kind& K = R->getKind(); 986296417Sdim if (K == MemRegion::FieldRegionKind) 987296417Sdim if (Size && IsFirstBufInBound(C, state, E, Size)) { 988296417Sdim // If destination buffer is a field region and access is in bound, 989296417Sdim // do not invalidate its super region. 990296417Sdim ITraits.setTrait( 991296417Sdim R, 992296417Sdim RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); 993296417Sdim } 994261991Sdim } 995261991Sdim 996296417Sdim return state->invalidateRegions(R, E, C.blockCount(), LCtx, 997276479Sdim CausesPointerEscape, nullptr, nullptr, 998276479Sdim &ITraits); 999218887Sdim } 1000218887Sdim 1001218887Sdim // If we have a non-region value by chance, just remove the binding. 1002218887Sdim // FIXME: is this necessary or correct? This handles the non-Region 1003218887Sdim // cases. Is it ever valid to store to these? 1004243830Sdim return state->killBinding(*L); 1005218887Sdim} 1006218887Sdim 1007226633Sdimbool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, 1008218887Sdim const MemRegion *MR) { 1009226633Sdim switch (MR->getKind()) { 1010296417Sdim case MemRegion::FunctionCodeRegionKind: { 1011360784Sdim if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl()) 1012226633Sdim os << "the address of the function '" << *FD << '\''; 1013218887Sdim else 1014218887Sdim os << "the address of a function"; 1015218887Sdim return true; 1016218887Sdim } 1017296417Sdim case MemRegion::BlockCodeRegionKind: 1018218887Sdim os << "block text"; 1019218887Sdim return true; 1020218887Sdim case MemRegion::BlockDataRegionKind: 1021218887Sdim os << "a block"; 1022218887Sdim return true; 1023218887Sdim case MemRegion::CXXThisRegionKind: 1024218887Sdim case MemRegion::CXXTempObjectRegionKind: 1025360784Sdim os << "a C++ temp object of type " 1026360784Sdim << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 1027218887Sdim return true; 1028218887Sdim case MemRegion::VarRegionKind: 1029360784Sdim os << "a variable of type" 1030360784Sdim << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 1031218887Sdim return true; 1032218887Sdim case MemRegion::FieldRegionKind: 1033360784Sdim os << "a field of type " 1034360784Sdim << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 1035218887Sdim return true; 1036218887Sdim case MemRegion::ObjCIvarRegionKind: 1037360784Sdim os << "an instance variable of type " 1038360784Sdim << cast<TypedValueRegion>(MR)->getValueType().getAsString(); 1039218887Sdim return true; 1040218887Sdim default: 1041218887Sdim return false; 1042218887Sdim } 1043218887Sdim} 1044218887Sdim 1045344779Sdimbool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, 1046341825Sdim const Expr *Size, CheckerContext &C, 1047341825Sdim ProgramStateRef &State) { 1048341825Sdim SVal MemVal = C.getSVal(DstBuffer); 1049341825Sdim SVal SizeVal = C.getSVal(Size); 1050341825Sdim const MemRegion *MR = MemVal.getAsRegion(); 1051341825Sdim if (!MR) 1052341825Sdim return false; 1053341825Sdim 1054341825Sdim // We're about to model memset by producing a "default binding" in the Store. 1055341825Sdim // Our current implementation - RegionStore - doesn't support default bindings 1056341825Sdim // that don't cover the whole base region. So we should first get the offset 1057341825Sdim // and the base region to figure out whether the offset of buffer is 0. 1058341825Sdim RegionOffset Offset = MR->getAsOffset(); 1059341825Sdim const MemRegion *BR = Offset.getRegion(); 1060341825Sdim 1061341825Sdim Optional<NonLoc> SizeNL = SizeVal.getAs<NonLoc>(); 1062341825Sdim if (!SizeNL) 1063341825Sdim return false; 1064341825Sdim 1065341825Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 1066341825Sdim ASTContext &Ctx = C.getASTContext(); 1067341825Sdim 1068341825Sdim // void *memset(void *dest, int ch, size_t count); 1069341825Sdim // For now we can only handle the case of offset is 0 and concrete char value. 1070341825Sdim if (Offset.isValid() && !Offset.hasSymbolicOffset() && 1071341825Sdim Offset.getOffset() == 0) { 1072341825Sdim // Get the base region's extent. 1073341825Sdim auto *SubReg = cast<SubRegion>(BR); 1074341825Sdim DefinedOrUnknownSVal Extent = SubReg->getExtent(svalBuilder); 1075341825Sdim 1076341825Sdim ProgramStateRef StateWholeReg, StateNotWholeReg; 1077341825Sdim std::tie(StateWholeReg, StateNotWholeReg) = 1078341825Sdim State->assume(svalBuilder.evalEQ(State, Extent, *SizeNL)); 1079341825Sdim 1080341825Sdim // With the semantic of 'memset()', we should convert the CharVal to 1081341825Sdim // unsigned char. 1082341825Sdim CharVal = svalBuilder.evalCast(CharVal, Ctx.UnsignedCharTy, Ctx.IntTy); 1083341825Sdim 1084341825Sdim ProgramStateRef StateNullChar, StateNonNullChar; 1085341825Sdim std::tie(StateNullChar, StateNonNullChar) = 1086341825Sdim assumeZero(C, State, CharVal, Ctx.UnsignedCharTy); 1087341825Sdim 1088341825Sdim if (StateWholeReg && !StateNotWholeReg && StateNullChar && 1089341825Sdim !StateNonNullChar) { 1090341825Sdim // If the 'memset()' acts on the whole region of destination buffer and 1091341825Sdim // the value of the second argument of 'memset()' is zero, bind the second 1092341825Sdim // argument's value to the destination buffer with 'default binding'. 1093341825Sdim // FIXME: Since there is no perfect way to bind the non-zero character, we 1094341825Sdim // can only deal with zero value here. In the future, we need to deal with 1095341825Sdim // the binding of non-zero value in the case of whole region. 1096341825Sdim State = State->bindDefaultZero(svalBuilder.makeLoc(BR), 1097341825Sdim C.getLocationContext()); 1098341825Sdim } else { 1099341825Sdim // If the destination buffer's extent is not equal to the value of 1100341825Sdim // third argument, just invalidate buffer. 1101341825Sdim State = InvalidateBuffer(C, State, DstBuffer, MemVal, 1102341825Sdim /*IsSourceBuffer*/ false, Size); 1103341825Sdim } 1104341825Sdim 1105341825Sdim if (StateNullChar && !StateNonNullChar) { 1106341825Sdim // If the value of the second argument of 'memset()' is zero, set the 1107341825Sdim // string length of destination buffer to 0 directly. 1108341825Sdim State = setCStringLength(State, MR, 1109341825Sdim svalBuilder.makeZeroVal(Ctx.getSizeType())); 1110341825Sdim } else if (!StateNullChar && StateNonNullChar) { 1111341825Sdim SVal NewStrLen = svalBuilder.getMetadataSymbolVal( 1112341825Sdim CStringChecker::getTag(), MR, DstBuffer, Ctx.getSizeType(), 1113341825Sdim C.getLocationContext(), C.blockCount()); 1114341825Sdim 1115341825Sdim // If the value of second argument is not zero, then the string length 1116341825Sdim // is at least the size argument. 1117341825Sdim SVal NewStrLenGESize = svalBuilder.evalBinOp( 1118341825Sdim State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType()); 1119341825Sdim 1120341825Sdim State = setCStringLength( 1121341825Sdim State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(), true), 1122341825Sdim MR, NewStrLen); 1123341825Sdim } 1124341825Sdim } else { 1125341825Sdim // If the offset is not zero and char value is not concrete, we can do 1126341825Sdim // nothing but invalidate the buffer. 1127341825Sdim State = InvalidateBuffer(C, State, DstBuffer, MemVal, 1128341825Sdim /*IsSourceBuffer*/ false, Size); 1129341825Sdim } 1130341825Sdim return true; 1131341825Sdim} 1132341825Sdim 1133218887Sdim//===----------------------------------------------------------------------===// 1134218887Sdim// evaluation of individual function calls. 1135218887Sdim//===----------------------------------------------------------------------===// 1136218887Sdim 1137296417Sdimvoid CStringChecker::evalCopyCommon(CheckerContext &C, 1138221345Sdim const CallExpr *CE, 1139234353Sdim ProgramStateRef state, 1140218887Sdim const Expr *Size, const Expr *Dest, 1141221345Sdim const Expr *Source, bool Restricted, 1142221345Sdim bool IsMempcpy) const { 1143224145Sdim CurrentFunctionDescription = "memory copy function"; 1144224145Sdim 1145218887Sdim // See if the size argument is zero. 1146234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1147234353Sdim SVal sizeVal = state->getSVal(Size, LCtx); 1148218887Sdim QualType sizeTy = Size->getType(); 1149218887Sdim 1150234353Sdim ProgramStateRef stateZeroSize, stateNonZeroSize; 1151276479Sdim std::tie(stateZeroSize, stateNonZeroSize) = 1152224145Sdim assumeZero(C, state, sizeVal, sizeTy); 1153218887Sdim 1154221345Sdim // Get the value of the Dest. 1155234353Sdim SVal destVal = state->getSVal(Dest, LCtx); 1156221345Sdim 1157221345Sdim // If the size is zero, there won't be any actual memory access, so 1158221345Sdim // just bind the return value to the destination buffer and return. 1159239462Sdim if (stateZeroSize && !stateNonZeroSize) { 1160234353Sdim stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal); 1161218887Sdim C.addTransition(stateZeroSize); 1162239462Sdim return; 1163221345Sdim } 1164218887Sdim 1165218887Sdim // If the size can be nonzero, we have to check the other arguments. 1166218887Sdim if (stateNonZeroSize) { 1167223017Sdim state = stateNonZeroSize; 1168221345Sdim 1169221345Sdim // Ensure the destination is not null. If it is NULL there will be a 1170221345Sdim // NULL pointer dereference. 1171360784Sdim state = checkNonNull(C, state, Dest, destVal, 1); 1172221345Sdim if (!state) 1173221345Sdim return; 1174221345Sdim 1175221345Sdim // Get the value of the Src. 1176234353Sdim SVal srcVal = state->getSVal(Source, LCtx); 1177296417Sdim 1178221345Sdim // Ensure the source is not null. If it is NULL there will be a 1179221345Sdim // NULL pointer dereference. 1180360784Sdim state = checkNonNull(C, state, Source, srcVal, 2); 1181221345Sdim if (!state) 1182221345Sdim return; 1183221345Sdim 1184223017Sdim // Ensure the accesses are valid and that the buffers do not overlap. 1185224145Sdim const char * const writeWarning = 1186224145Sdim "Memory copy function overflows destination buffer"; 1187218887Sdim state = CheckBufferAccess(C, state, Size, Dest, Source, 1188276479Sdim writeWarning, /* sourceWarning = */ nullptr); 1189218887Sdim if (Restricted) 1190218887Sdim state = CheckOverlap(C, state, Size, Dest, Source); 1191218887Sdim 1192223017Sdim if (!state) 1193223017Sdim return; 1194221345Sdim 1195296417Sdim // If this is mempcpy, get the byte after the last byte copied and 1196223017Sdim // bind the expr. 1197223017Sdim if (IsMempcpy) { 1198327952Sdim // Get the byte after the last byte copied. 1199327952Sdim SValBuilder &SvalBuilder = C.getSValBuilder(); 1200327952Sdim ASTContext &Ctx = SvalBuilder.getContext(); 1201327952Sdim QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy); 1202327952Sdim SVal DestRegCharVal = 1203327952Sdim SvalBuilder.evalCast(destVal, CharPtrTy, Dest->getType()); 1204327952Sdim SVal lastElement = C.getSValBuilder().evalBinOp( 1205327952Sdim state, BO_Add, DestRegCharVal, sizeVal, Dest->getType()); 1206327952Sdim // If we don't know how much we copied, we can at least 1207327952Sdim // conjure a return value for later. 1208327952Sdim if (lastElement.isUnknown()) 1209327952Sdim lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 1210243830Sdim C.blockCount()); 1211221345Sdim 1212327952Sdim // The byte after the last byte copied is the return value. 1213327952Sdim state = state->BindExpr(CE, LCtx, lastElement); 1214223017Sdim } else { 1215223017Sdim // All other copies return the destination buffer. 1216223017Sdim // (Well, bcopy() has a void return type, but this won't hurt.) 1217234353Sdim state = state->BindExpr(CE, LCtx, destVal); 1218218887Sdim } 1219223017Sdim 1220261991Sdim // Invalidate the destination (regular invalidation without pointer-escaping 1221261991Sdim // the address of the top-level region). 1222223017Sdim // FIXME: Even if we can't perfectly model the copy, we should see if we 1223223017Sdim // can use LazyCompoundVals to copy the source values into the destination. 1224223017Sdim // This would probably remove any existing bindings past the end of the 1225223017Sdim // copied region, but that's still an improvement over blank invalidation. 1226296417Sdim state = InvalidateBuffer(C, state, Dest, C.getSVal(Dest), 1227296417Sdim /*IsSourceBuffer*/false, Size); 1228261991Sdim 1229261991Sdim // Invalidate the source (const-invalidation without const-pointer-escaping 1230261991Sdim // the address of the top-level region). 1231296417Sdim state = InvalidateBuffer(C, state, Source, C.getSVal(Source), 1232296417Sdim /*IsSourceBuffer*/true, nullptr); 1233261991Sdim 1234223017Sdim C.addTransition(state); 1235218887Sdim } 1236218887Sdim} 1237218887Sdim 1238218887Sdim 1239219077Sdimvoid CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) const { 1240218887Sdim // void *memcpy(void *restrict dst, const void *restrict src, size_t n); 1241218887Sdim // The return value is the address of the destination buffer. 1242218887Sdim const Expr *Dest = CE->getArg(0); 1243234353Sdim ProgramStateRef state = C.getState(); 1244223017Sdim 1245221345Sdim evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true); 1246218887Sdim} 1247218887Sdim 1248221345Sdimvoid CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE) const { 1249221345Sdim // void *mempcpy(void *restrict dst, const void *restrict src, size_t n); 1250221345Sdim // The return value is a pointer to the byte following the last written byte. 1251221345Sdim const Expr *Dest = CE->getArg(0); 1252234353Sdim ProgramStateRef state = C.getState(); 1253296417Sdim 1254221345Sdim evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1), true, true); 1255221345Sdim} 1256221345Sdim 1257219077Sdimvoid CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) const { 1258218887Sdim // void *memmove(void *dst, const void *src, size_t n); 1259218887Sdim // The return value is the address of the destination buffer. 1260218887Sdim const Expr *Dest = CE->getArg(0); 1261234353Sdim ProgramStateRef state = C.getState(); 1262223017Sdim 1263221345Sdim evalCopyCommon(C, CE, state, CE->getArg(2), Dest, CE->getArg(1)); 1264218887Sdim} 1265218887Sdim 1266219077Sdimvoid CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const { 1267218887Sdim // void bcopy(const void *src, void *dst, size_t n); 1268296417Sdim evalCopyCommon(C, CE, C.getState(), 1269221345Sdim CE->getArg(2), CE->getArg(1), CE->getArg(0)); 1270218887Sdim} 1271218887Sdim 1272219077Sdimvoid CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { 1273218887Sdim // int memcmp(const void *s1, const void *s2, size_t n); 1274224145Sdim CurrentFunctionDescription = "memory comparison function"; 1275224145Sdim 1276218887Sdim const Expr *Left = CE->getArg(0); 1277218887Sdim const Expr *Right = CE->getArg(1); 1278218887Sdim const Expr *Size = CE->getArg(2); 1279218887Sdim 1280234353Sdim ProgramStateRef state = C.getState(); 1281218887Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 1282218887Sdim 1283218887Sdim // See if the size argument is zero. 1284234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1285234353Sdim SVal sizeVal = state->getSVal(Size, LCtx); 1286218887Sdim QualType sizeTy = Size->getType(); 1287218887Sdim 1288234353Sdim ProgramStateRef stateZeroSize, stateNonZeroSize; 1289276479Sdim std::tie(stateZeroSize, stateNonZeroSize) = 1290218887Sdim assumeZero(C, state, sizeVal, sizeTy); 1291218887Sdim 1292218887Sdim // If the size can be zero, the result will be 0 in that case, and we don't 1293218887Sdim // have to check either of the buffers. 1294218887Sdim if (stateZeroSize) { 1295218887Sdim state = stateZeroSize; 1296234353Sdim state = state->BindExpr(CE, LCtx, 1297234353Sdim svalBuilder.makeZeroVal(CE->getType())); 1298218887Sdim C.addTransition(state); 1299218887Sdim } 1300218887Sdim 1301218887Sdim // If the size can be nonzero, we have to check the other arguments. 1302218887Sdim if (stateNonZeroSize) { 1303218887Sdim state = stateNonZeroSize; 1304218887Sdim // If we know the two buffers are the same, we know the result is 0. 1305218887Sdim // First, get the two buffers' addresses. Another checker will have already 1306218887Sdim // made sure they're not undefined. 1307234353Sdim DefinedOrUnknownSVal LV = 1308249423Sdim state->getSVal(Left, LCtx).castAs<DefinedOrUnknownSVal>(); 1309234353Sdim DefinedOrUnknownSVal RV = 1310249423Sdim state->getSVal(Right, LCtx).castAs<DefinedOrUnknownSVal>(); 1311218887Sdim 1312218887Sdim // See if they are the same. 1313218887Sdim DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); 1314234353Sdim ProgramStateRef StSameBuf, StNotSameBuf; 1315276479Sdim std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); 1316218887Sdim 1317360784Sdim // If the two arguments are the same buffer, we know the result is 0, 1318218887Sdim // and we only need to check one size. 1319360784Sdim if (StSameBuf && !StNotSameBuf) { 1320218887Sdim state = StSameBuf; 1321218887Sdim state = CheckBufferAccess(C, state, Size, Left); 1322218887Sdim if (state) { 1323234353Sdim state = StSameBuf->BindExpr(CE, LCtx, 1324234353Sdim svalBuilder.makeZeroVal(CE->getType())); 1325234353Sdim C.addTransition(state); 1326218887Sdim } 1327360784Sdim return; 1328218887Sdim } 1329218887Sdim 1330360784Sdim // If the two arguments might be different buffers, we have to check 1331360784Sdim // the size of both of them. 1332360784Sdim assert(StNotSameBuf); 1333360784Sdim state = CheckBufferAccess(C, state, Size, Left, Right); 1334360784Sdim if (state) { 1335360784Sdim // The return value is the comparison result, which we don't know. 1336360784Sdim SVal CmpV = 1337360784Sdim svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 1338360784Sdim state = state->BindExpr(CE, LCtx, CmpV); 1339360784Sdim C.addTransition(state); 1340218887Sdim } 1341218887Sdim } 1342218887Sdim} 1343218887Sdim 1344219077Sdimvoid CStringChecker::evalstrLength(CheckerContext &C, 1345219077Sdim const CallExpr *CE) const { 1346218887Sdim // size_t strlen(const char *s); 1347219077Sdim evalstrLengthCommon(C, CE, /* IsStrnlen = */ false); 1348219077Sdim} 1349219077Sdim 1350219077Sdimvoid CStringChecker::evalstrnLength(CheckerContext &C, 1351219077Sdim const CallExpr *CE) const { 1352219077Sdim // size_t strnlen(const char *s, size_t maxlen); 1353219077Sdim evalstrLengthCommon(C, CE, /* IsStrnlen = */ true); 1354219077Sdim} 1355219077Sdim 1356219077Sdimvoid CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, 1357219077Sdim bool IsStrnlen) const { 1358224145Sdim CurrentFunctionDescription = "string length function"; 1359234353Sdim ProgramStateRef state = C.getState(); 1360234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1361224145Sdim 1362224145Sdim if (IsStrnlen) { 1363224145Sdim const Expr *maxlenExpr = CE->getArg(1); 1364234353Sdim SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); 1365224145Sdim 1366234353Sdim ProgramStateRef stateZeroSize, stateNonZeroSize; 1367276479Sdim std::tie(stateZeroSize, stateNonZeroSize) = 1368224145Sdim assumeZero(C, state, maxlenVal, maxlenExpr->getType()); 1369224145Sdim 1370224145Sdim // If the size can be zero, the result will be 0 in that case, and we don't 1371224145Sdim // have to check the string itself. 1372224145Sdim if (stateZeroSize) { 1373224145Sdim SVal zero = C.getSValBuilder().makeZeroVal(CE->getType()); 1374234353Sdim stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero); 1375224145Sdim C.addTransition(stateZeroSize); 1376224145Sdim } 1377224145Sdim 1378224145Sdim // If the size is GUARANTEED to be zero, we're done! 1379224145Sdim if (!stateNonZeroSize) 1380224145Sdim return; 1381224145Sdim 1382224145Sdim // Otherwise, record the assumption that the size is nonzero. 1383224145Sdim state = stateNonZeroSize; 1384224145Sdim } 1385224145Sdim 1386224145Sdim // Check that the string argument is non-null. 1387218887Sdim const Expr *Arg = CE->getArg(0); 1388234353Sdim SVal ArgVal = state->getSVal(Arg, LCtx); 1389218887Sdim 1390360784Sdim state = checkNonNull(C, state, Arg, ArgVal, 1); 1391218887Sdim 1392224145Sdim if (!state) 1393224145Sdim return; 1394218887Sdim 1395224145Sdim SVal strLength = getCStringLength(C, state, Arg, ArgVal); 1396218887Sdim 1397224145Sdim // If the argument isn't a valid C string, there's no valid state to 1398224145Sdim // transition to. 1399224145Sdim if (strLength.isUndef()) 1400224145Sdim return; 1401219077Sdim 1402224145Sdim DefinedOrUnknownSVal result = UnknownVal(); 1403224145Sdim 1404224145Sdim // If the check is for strnlen() then bind the return value to no more than 1405224145Sdim // the maxlen value. 1406224145Sdim if (IsStrnlen) { 1407224145Sdim QualType cmpTy = C.getSValBuilder().getConditionType(); 1408224145Sdim 1409224145Sdim // It's a little unfortunate to be getting this again, 1410224145Sdim // but it's not that expensive... 1411224145Sdim const Expr *maxlenExpr = CE->getArg(1); 1412234353Sdim SVal maxlenVal = state->getSVal(maxlenExpr, LCtx); 1413224145Sdim 1414249423Sdim Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); 1415249423Sdim Optional<NonLoc> maxlenValNL = maxlenVal.getAs<NonLoc>(); 1416224145Sdim 1417224145Sdim if (strLengthNL && maxlenValNL) { 1418234353Sdim ProgramStateRef stateStringTooLong, stateStringNotTooLong; 1419224145Sdim 1420224145Sdim // Check if the strLength is greater than the maxlen. 1421276479Sdim std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume( 1422276479Sdim C.getSValBuilder() 1423276479Sdim .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy) 1424276479Sdim .castAs<DefinedOrUnknownSVal>()); 1425219077Sdim 1426224145Sdim if (stateStringTooLong && !stateStringNotTooLong) { 1427224145Sdim // If the string is longer than maxlen, return maxlen. 1428224145Sdim result = *maxlenValNL; 1429224145Sdim } else if (stateStringNotTooLong && !stateStringTooLong) { 1430224145Sdim // If the string is shorter than maxlen, return its length. 1431224145Sdim result = *strLengthNL; 1432219077Sdim } 1433219077Sdim } 1434219077Sdim 1435224145Sdim if (result.isUnknown()) { 1436224145Sdim // If we don't have enough information for a comparison, there's 1437224145Sdim // no guarantee the full string length will actually be returned. 1438224145Sdim // All we know is the return value is the min of the string length 1439224145Sdim // and the limit. This is better than nothing. 1440276479Sdim result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 1441276479Sdim C.blockCount()); 1442249423Sdim NonLoc resultNL = result.castAs<NonLoc>(); 1443224145Sdim 1444224145Sdim if (strLengthNL) { 1445249423Sdim state = state->assume(C.getSValBuilder().evalBinOpNN( 1446249423Sdim state, BO_LE, resultNL, *strLengthNL, cmpTy) 1447249423Sdim .castAs<DefinedOrUnknownSVal>(), true); 1448224145Sdim } 1449296417Sdim 1450224145Sdim if (maxlenValNL) { 1451249423Sdim state = state->assume(C.getSValBuilder().evalBinOpNN( 1452249423Sdim state, BO_LE, resultNL, *maxlenValNL, cmpTy) 1453249423Sdim .castAs<DefinedOrUnknownSVal>(), true); 1454224145Sdim } 1455224145Sdim } 1456224145Sdim 1457224145Sdim } else { 1458224145Sdim // This is a plain strlen(), not strnlen(). 1459249423Sdim result = strLength.castAs<DefinedOrUnknownSVal>(); 1460224145Sdim 1461224145Sdim // If we don't know the length of the string, conjure a return 1462218887Sdim // value, so it can be used in constraints, at least. 1463224145Sdim if (result.isUnknown()) { 1464276479Sdim result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx, 1465276479Sdim C.blockCount()); 1466218887Sdim } 1467224145Sdim } 1468218887Sdim 1469224145Sdim // Bind the return value. 1470224145Sdim assert(!result.isUnknown() && "Should have conjured a value by now"); 1471234353Sdim state = state->BindExpr(CE, LCtx, result); 1472224145Sdim C.addTransition(state); 1473218887Sdim} 1474218887Sdim 1475219077Sdimvoid CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { 1476218887Sdim // char *strcpy(char *restrict dst, const char *restrict src); 1477296417Sdim evalStrcpyCommon(C, CE, 1478360784Sdim /* ReturnEnd = */ false, 1479360784Sdim /* IsBounded = */ false, 1480360784Sdim /* appendK = */ ConcatFnKind::none); 1481218887Sdim} 1482218887Sdim 1483219077Sdimvoid CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { 1484223017Sdim // char *strncpy(char *restrict dst, const char *restrict src, size_t n); 1485296417Sdim evalStrcpyCommon(C, CE, 1486360784Sdim /* ReturnEnd = */ false, 1487360784Sdim /* IsBounded = */ true, 1488360784Sdim /* appendK = */ ConcatFnKind::none); 1489219077Sdim} 1490219077Sdim 1491219077Sdimvoid CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const { 1492218887Sdim // char *stpcpy(char *restrict dst, const char *restrict src); 1493296417Sdim evalStrcpyCommon(C, CE, 1494360784Sdim /* ReturnEnd = */ true, 1495360784Sdim /* IsBounded = */ false, 1496360784Sdim /* appendK = */ ConcatFnKind::none); 1497218887Sdim} 1498218887Sdim 1499341825Sdimvoid CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const { 1500360784Sdim // size_t strlcpy(char *dest, const char *src, size_t size); 1501341825Sdim evalStrcpyCommon(C, CE, 1502360784Sdim /* ReturnEnd = */ true, 1503360784Sdim /* IsBounded = */ true, 1504360784Sdim /* appendK = */ ConcatFnKind::none, 1505341825Sdim /* returnPtr = */ false); 1506341825Sdim} 1507341825Sdim 1508221345Sdimvoid CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { 1509360784Sdim // char *strcat(char *restrict s1, const char *restrict s2); 1510296417Sdim evalStrcpyCommon(C, CE, 1511360784Sdim /* ReturnEnd = */ false, 1512360784Sdim /* IsBounded = */ false, 1513360784Sdim /* appendK = */ ConcatFnKind::strcat); 1514221345Sdim} 1515221345Sdim 1516221345Sdimvoid CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const { 1517221345Sdim //char *strncat(char *restrict s1, const char *restrict s2, size_t n); 1518296417Sdim evalStrcpyCommon(C, CE, 1519360784Sdim /* ReturnEnd = */ false, 1520360784Sdim /* IsBounded = */ true, 1521360784Sdim /* appendK = */ ConcatFnKind::strcat); 1522221345Sdim} 1523221345Sdim 1524341825Sdimvoid CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const { 1525360784Sdim // size_t strlcat(char *dst, const char *src, size_t size); 1526360784Sdim // It will append at most size - strlen(dst) - 1 bytes, 1527360784Sdim // NULL-terminating the result. 1528341825Sdim evalStrcpyCommon(C, CE, 1529360784Sdim /* ReturnEnd = */ false, 1530360784Sdim /* IsBounded = */ true, 1531360784Sdim /* appendK = */ ConcatFnKind::strlcat, 1532341825Sdim /* returnPtr = */ false); 1533341825Sdim} 1534341825Sdim 1535218887Sdimvoid CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, 1536360784Sdim bool ReturnEnd, bool IsBounded, 1537360784Sdim ConcatFnKind appendK, 1538360784Sdim bool returnPtr) const { 1539360784Sdim if (appendK == ConcatFnKind::none) 1540360784Sdim CurrentFunctionDescription = "string copy function"; 1541360784Sdim else 1542360784Sdim CurrentFunctionDescription = "string concatenation function"; 1543234353Sdim ProgramStateRef state = C.getState(); 1544234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1545218887Sdim 1546221345Sdim // Check that the destination is non-null. 1547218887Sdim const Expr *Dst = CE->getArg(0); 1548234353Sdim SVal DstVal = state->getSVal(Dst, LCtx); 1549218887Sdim 1550360784Sdim state = checkNonNull(C, state, Dst, DstVal, 1); 1551218887Sdim if (!state) 1552218887Sdim return; 1553218887Sdim 1554218887Sdim // Check that the source is non-null. 1555218887Sdim const Expr *srcExpr = CE->getArg(1); 1556234353Sdim SVal srcVal = state->getSVal(srcExpr, LCtx); 1557360784Sdim state = checkNonNull(C, state, srcExpr, srcVal, 2); 1558218887Sdim if (!state) 1559218887Sdim return; 1560218887Sdim 1561218887Sdim // Get the string length of the source. 1562218887Sdim SVal strLength = getCStringLength(C, state, srcExpr, srcVal); 1563360784Sdim Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); 1564218887Sdim 1565360784Sdim // Get the string length of the destination buffer. 1566360784Sdim SVal dstStrLength = getCStringLength(C, state, Dst, DstVal); 1567360784Sdim Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); 1568360784Sdim 1569218887Sdim // If the source isn't a valid C string, give up. 1570218887Sdim if (strLength.isUndef()) 1571218887Sdim return; 1572218887Sdim 1573224145Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 1574224145Sdim QualType cmpTy = svalBuilder.getConditionType(); 1575224145Sdim QualType sizeTy = svalBuilder.getContext().getSizeType(); 1576224145Sdim 1577224145Sdim // These two values allow checking two kinds of errors: 1578224145Sdim // - actual overflows caused by a source that doesn't fit in the destination 1579224145Sdim // - potential overflows caused by a bound that could exceed the destination 1580224145Sdim SVal amountCopied = UnknownVal(); 1581224145Sdim SVal maxLastElementIndex = UnknownVal(); 1582276479Sdim const char *boundWarning = nullptr; 1583224145Sdim 1584360784Sdim state = CheckOverlap(C, state, IsBounded ? CE->getArg(2) : CE->getArg(1), Dst, 1585360784Sdim srcExpr); 1586341825Sdim 1587341825Sdim if (!state) 1588341825Sdim return; 1589341825Sdim 1590221345Sdim // If the function is strncpy, strncat, etc... it is bounded. 1591360784Sdim if (IsBounded) { 1592221345Sdim // Get the max number of characters to copy. 1593219077Sdim const Expr *lenExpr = CE->getArg(2); 1594234353Sdim SVal lenVal = state->getSVal(lenExpr, LCtx); 1595219077Sdim 1596224145Sdim // Protect against misdeclared strncpy(). 1597224145Sdim lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType()); 1598224145Sdim 1599249423Sdim Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>(); 1600219077Sdim 1601224145Sdim // If we know both values, we might be able to figure out how much 1602224145Sdim // we're copying. 1603224145Sdim if (strLengthNL && lenValNL) { 1604360784Sdim switch (appendK) { 1605360784Sdim case ConcatFnKind::none: 1606360784Sdim case ConcatFnKind::strcat: { 1607360784Sdim ProgramStateRef stateSourceTooLong, stateSourceNotTooLong; 1608360784Sdim // Check if the max number to copy is less than the length of the src. 1609360784Sdim // If the bound is equal to the source length, strncpy won't null- 1610360784Sdim // terminate the result! 1611360784Sdim std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( 1612360784Sdim svalBuilder 1613360784Sdim .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) 1614360784Sdim .castAs<DefinedOrUnknownSVal>()); 1615219077Sdim 1616360784Sdim if (stateSourceTooLong && !stateSourceNotTooLong) { 1617360784Sdim // Max number to copy is less than the length of the src, so the 1618360784Sdim // actual strLength copied is the max number arg. 1619360784Sdim state = stateSourceTooLong; 1620360784Sdim amountCopied = lenVal; 1621224145Sdim 1622360784Sdim } else if (!stateSourceTooLong && stateSourceNotTooLong) { 1623360784Sdim // The source buffer entirely fits in the bound. 1624360784Sdim state = stateSourceNotTooLong; 1625360784Sdim amountCopied = strLength; 1626360784Sdim } 1627360784Sdim break; 1628360784Sdim } 1629360784Sdim case ConcatFnKind::strlcat: 1630360784Sdim if (!dstStrLengthNL) 1631360784Sdim return; 1632224145Sdim 1633360784Sdim // amountCopied = min (size - dstLen - 1 , srcLen) 1634360784Sdim SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, 1635360784Sdim *dstStrLengthNL, sizeTy); 1636360784Sdim if (!freeSpace.getAs<NonLoc>()) 1637360784Sdim return; 1638360784Sdim freeSpace = 1639360784Sdim svalBuilder.evalBinOp(state, BO_Sub, freeSpace, 1640360784Sdim svalBuilder.makeIntVal(1, sizeTy), sizeTy); 1641360784Sdim Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>(); 1642360784Sdim 1643360784Sdim // While unlikely, it is possible that the subtraction is 1644360784Sdim // too complex to compute, let's check whether it succeeded. 1645360784Sdim if (!freeSpaceNL) 1646360784Sdim return; 1647360784Sdim SVal hasEnoughSpace = svalBuilder.evalBinOpNN( 1648360784Sdim state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy); 1649360784Sdim 1650360784Sdim ProgramStateRef TrueState, FalseState; 1651360784Sdim std::tie(TrueState, FalseState) = 1652360784Sdim state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>()); 1653360784Sdim 1654360784Sdim // srcStrLength <= size - dstStrLength -1 1655360784Sdim if (TrueState && !FalseState) { 1656360784Sdim amountCopied = strLength; 1657360784Sdim } 1658360784Sdim 1659360784Sdim // srcStrLength > size - dstStrLength -1 1660360784Sdim if (!TrueState && FalseState) { 1661360784Sdim amountCopied = freeSpace; 1662360784Sdim } 1663360784Sdim 1664360784Sdim if (TrueState && FalseState) 1665360784Sdim amountCopied = UnknownVal(); 1666360784Sdim break; 1667224145Sdim } 1668224145Sdim } 1669224145Sdim // We still want to know if the bound is known to be too large. 1670224145Sdim if (lenValNL) { 1671360784Sdim switch (appendK) { 1672360784Sdim case ConcatFnKind::strcat: 1673224145Sdim // For strncat, the check is strlen(dst) + lenVal < sizeof(dst) 1674224145Sdim 1675224145Sdim // Get the string length of the destination. If the destination is 1676224145Sdim // memory that can't have a string length, we shouldn't be copying 1677224145Sdim // into it anyway. 1678224145Sdim if (dstStrLength.isUndef()) 1679224145Sdim return; 1680224145Sdim 1681360784Sdim if (dstStrLengthNL) { 1682360784Sdim maxLastElementIndex = svalBuilder.evalBinOpNN( 1683360784Sdim state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy); 1684360784Sdim 1685224145Sdim boundWarning = "Size argument is greater than the free space in the " 1686224145Sdim "destination buffer"; 1687224145Sdim } 1688360784Sdim break; 1689360784Sdim case ConcatFnKind::none: 1690360784Sdim case ConcatFnKind::strlcat: 1691360784Sdim // For strncpy and strlcat, this is just checking 1692360784Sdim // that lenVal <= sizeof(dst). 1693224145Sdim // (Yes, strncpy and strncat differ in how they treat termination. 1694224145Sdim // strncat ALWAYS terminates, but strncpy doesn't.) 1695239462Sdim 1696239462Sdim // We need a special case for when the copy size is zero, in which 1697239462Sdim // case strncpy will do no work at all. Our bounds check uses n-1 1698239462Sdim // as the last element accessed, so n == 0 is problematic. 1699239462Sdim ProgramStateRef StateZeroSize, StateNonZeroSize; 1700276479Sdim std::tie(StateZeroSize, StateNonZeroSize) = 1701360784Sdim assumeZero(C, state, *lenValNL, sizeTy); 1702239462Sdim 1703239462Sdim // If the size is known to be zero, we're done. 1704239462Sdim if (StateZeroSize && !StateNonZeroSize) { 1705341825Sdim if (returnPtr) { 1706341825Sdim StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal); 1707341825Sdim } else { 1708360784Sdim if (appendK == ConcatFnKind::none) { 1709360784Sdim // strlcpy returns strlen(src) 1710360784Sdim StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength); 1711360784Sdim } else { 1712360784Sdim // strlcat returns strlen(src) + strlen(dst) 1713360784Sdim SVal retSize = svalBuilder.evalBinOp( 1714360784Sdim state, BO_Add, strLength, dstStrLength, sizeTy); 1715360784Sdim StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize); 1716360784Sdim } 1717341825Sdim } 1718239462Sdim C.addTransition(StateZeroSize); 1719239462Sdim return; 1720239462Sdim } 1721239462Sdim 1722239462Sdim // Otherwise, go ahead and figure out the last element we'll touch. 1723239462Sdim // We don't record the non-zero assumption here because we can't 1724239462Sdim // be sure. We won't warn on a possible zero. 1725249423Sdim NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); 1726360784Sdim maxLastElementIndex = 1727360784Sdim svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy); 1728224145Sdim boundWarning = "Size argument is greater than the length of the " 1729224145Sdim "destination buffer"; 1730360784Sdim break; 1731224145Sdim } 1732224145Sdim } 1733224145Sdim } else { 1734224145Sdim // The function isn't bounded. The amount copied should match the length 1735224145Sdim // of the source buffer. 1736224145Sdim amountCopied = strLength; 1737219077Sdim } 1738219077Sdim 1739224145Sdim assert(state); 1740224145Sdim 1741224145Sdim // This represents the number of characters copied into the destination 1742224145Sdim // buffer. (It may not actually be the strlen if the destination buffer 1743224145Sdim // is not terminated.) 1744224145Sdim SVal finalStrLength = UnknownVal(); 1745360784Sdim SVal strlRetVal = UnknownVal(); 1746224145Sdim 1747360784Sdim if (appendK == ConcatFnKind::none && !returnPtr) { 1748360784Sdim // strlcpy returns the sizeof(src) 1749360784Sdim strlRetVal = strLength; 1750360784Sdim } 1751360784Sdim 1752221345Sdim // If this is an appending function (strcat, strncat...) then set the 1753221345Sdim // string length to strlen(src) + strlen(dst) since the buffer will 1754221345Sdim // ultimately contain both. 1755360784Sdim if (appendK != ConcatFnKind::none) { 1756224145Sdim // Get the string length of the destination. If the destination is memory 1757224145Sdim // that can't have a string length, we shouldn't be copying into it anyway. 1758221345Sdim if (dstStrLength.isUndef()) 1759221345Sdim return; 1760221345Sdim 1761360784Sdim if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) { 1762360784Sdim strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL, 1763360784Sdim *dstStrLengthNL, sizeTy); 1764360784Sdim } 1765296417Sdim 1766360784Sdim Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>(); 1767360784Sdim 1768224145Sdim // If we know both string lengths, we might know the final string length. 1769360784Sdim if (amountCopiedNL && dstStrLengthNL) { 1770224145Sdim // Make sure the two lengths together don't overflow a size_t. 1771360784Sdim state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL); 1772224145Sdim if (!state) 1773224145Sdim return; 1774221345Sdim 1775360784Sdim finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL, 1776224145Sdim *dstStrLengthNL, sizeTy); 1777224145Sdim } 1778221345Sdim 1779224145Sdim // If we couldn't get a single value for the final string length, 1780224145Sdim // we can at least bound it by the individual lengths. 1781224145Sdim if (finalStrLength.isUnknown()) { 1782224145Sdim // Try to get a "hypothetical" string length symbol, which we can later 1783224145Sdim // set as a real value if that turns out to be the case. 1784224145Sdim finalStrLength = getCStringLength(C, state, CE, DstVal, true); 1785224145Sdim assert(!finalStrLength.isUndef()); 1786224145Sdim 1787249423Sdim if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) { 1788360784Sdim if (amountCopiedNL && appendK == ConcatFnKind::none) { 1789360784Sdim // we overwrite dst string with the src 1790224145Sdim // finalStrLength >= srcStrLength 1791360784Sdim SVal sourceInResult = svalBuilder.evalBinOpNN( 1792360784Sdim state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy); 1793249423Sdim state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(), 1794224145Sdim true); 1795224145Sdim if (!state) 1796224145Sdim return; 1797224145Sdim } 1798224145Sdim 1799360784Sdim if (dstStrLengthNL && appendK != ConcatFnKind::none) { 1800360784Sdim // we extend the dst string with the src 1801224145Sdim // finalStrLength >= dstStrLength 1802224145Sdim SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE, 1803224145Sdim *finalStrLengthNL, 1804224145Sdim *dstStrLengthNL, 1805224145Sdim cmpTy); 1806249423Sdim state = 1807249423Sdim state->assume(destInResult.castAs<DefinedOrUnknownSVal>(), true); 1808224145Sdim if (!state) 1809224145Sdim return; 1810224145Sdim } 1811224145Sdim } 1812224145Sdim } 1813224145Sdim 1814224145Sdim } else { 1815224145Sdim // Otherwise, this is a copy-over function (strcpy, strncpy, ...), and 1816224145Sdim // the final string length will match the input string length. 1817224145Sdim finalStrLength = amountCopied; 1818221345Sdim } 1819221345Sdim 1820341825Sdim SVal Result; 1821218887Sdim 1822341825Sdim if (returnPtr) { 1823341825Sdim // The final result of the function will either be a pointer past the last 1824341825Sdim // copied element, or a pointer to the start of the destination buffer. 1825360784Sdim Result = (ReturnEnd ? UnknownVal() : DstVal); 1826341825Sdim } else { 1827360784Sdim if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none) 1828360784Sdim //strlcpy, strlcat 1829360784Sdim Result = strlRetVal; 1830360784Sdim else 1831360784Sdim Result = finalStrLength; 1832341825Sdim } 1833341825Sdim 1834224145Sdim assert(state); 1835224145Sdim 1836218887Sdim // If the destination is a MemRegion, try to check for a buffer overflow and 1837218887Sdim // record the new string length. 1838249423Sdim if (Optional<loc::MemRegionVal> dstRegVal = 1839341825Sdim DstVal.getAs<loc::MemRegionVal>()) { 1840224145Sdim QualType ptrTy = Dst->getType(); 1841218887Sdim 1842224145Sdim // If we have an exact value on a bounded copy, use that to check for 1843224145Sdim // overflows, rather than our estimate about how much is actually copied. 1844224145Sdim if (boundWarning) { 1845249423Sdim if (Optional<NonLoc> maxLastNL = maxLastElementIndex.getAs<NonLoc>()) { 1846224145Sdim SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, 1847341825Sdim *maxLastNL, ptrTy); 1848296417Sdim state = CheckLocation(C, state, CE->getArg(2), maxLastElement, 1849341825Sdim boundWarning); 1850224145Sdim if (!state) 1851224145Sdim return; 1852224145Sdim } 1853224145Sdim } 1854218887Sdim 1855224145Sdim // Then, if the final length is known... 1856249423Sdim if (Optional<NonLoc> knownStrLength = finalStrLength.getAs<NonLoc>()) { 1857224145Sdim SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, 1858341825Sdim *knownStrLength, ptrTy); 1859224145Sdim 1860224145Sdim // ...and we haven't checked the bound, we'll check the actual copy. 1861224145Sdim if (!boundWarning) { 1862224145Sdim const char * const warningMsg = 1863224145Sdim "String copy function overflows destination buffer"; 1864224145Sdim state = CheckLocation(C, state, Dst, lastElement, warningMsg); 1865224145Sdim if (!state) 1866224145Sdim return; 1867224145Sdim } 1868224145Sdim 1869218887Sdim // If this is a stpcpy-style copy, the last element is the return value. 1870360784Sdim if (returnPtr && ReturnEnd) 1871218887Sdim Result = lastElement; 1872218887Sdim } 1873218887Sdim 1874261991Sdim // Invalidate the destination (regular invalidation without pointer-escaping 1875261991Sdim // the address of the top-level region). This must happen before we set the 1876261991Sdim // C string length because invalidation will clear the length. 1877218887Sdim // FIXME: Even if we can't perfectly model the copy, we should see if we 1878218887Sdim // can use LazyCompoundVals to copy the source values into the destination. 1879218887Sdim // This would probably remove any existing bindings past the end of the 1880218887Sdim // string, but that's still an improvement over blank invalidation. 1881261991Sdim state = InvalidateBuffer(C, state, Dst, *dstRegVal, 1882341825Sdim /*IsSourceBuffer*/false, nullptr); 1883218887Sdim 1884261991Sdim // Invalidate the source (const-invalidation without const-pointer-escaping 1885261991Sdim // the address of the top-level region). 1886296417Sdim state = InvalidateBuffer(C, state, srcExpr, srcVal, /*IsSourceBuffer*/true, 1887341825Sdim nullptr); 1888261991Sdim 1889224145Sdim // Set the C string length of the destination, if we know it. 1890360784Sdim if (IsBounded && (appendK == ConcatFnKind::none)) { 1891224145Sdim // strncpy is annoying in that it doesn't guarantee to null-terminate 1892224145Sdim // the result string. If the original string didn't fit entirely inside 1893224145Sdim // the bound (including the null-terminator), we don't know how long the 1894224145Sdim // result is. 1895224145Sdim if (amountCopied != strLength) 1896224145Sdim finalStrLength = UnknownVal(); 1897224145Sdim } 1898224145Sdim state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength); 1899218887Sdim } 1900218887Sdim 1901224145Sdim assert(state); 1902224145Sdim 1903341825Sdim if (returnPtr) { 1904341825Sdim // If this is a stpcpy-style copy, but we were unable to check for a buffer 1905341825Sdim // overflow, we still need a result. Conjure a return value. 1906360784Sdim if (ReturnEnd && Result.isUnknown()) { 1907341825Sdim Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 1908341825Sdim } 1909218887Sdim } 1910218887Sdim // Set the return value. 1911234353Sdim state = state->BindExpr(CE, LCtx, Result); 1912218887Sdim C.addTransition(state); 1913218887Sdim} 1914218887Sdim 1915221345Sdimvoid CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { 1916224145Sdim //int strcmp(const char *s1, const char *s2); 1917360784Sdim evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ false); 1918221345Sdim} 1919221345Sdim 1920221345Sdimvoid CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { 1921224145Sdim //int strncmp(const char *s1, const char *s2, size_t n); 1922360784Sdim evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ false); 1923221345Sdim} 1924221345Sdim 1925296417Sdimvoid CStringChecker::evalStrcasecmp(CheckerContext &C, 1926341825Sdim const CallExpr *CE) const { 1927224145Sdim //int strcasecmp(const char *s1, const char *s2); 1928360784Sdim evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ true); 1929221345Sdim} 1930221345Sdim 1931296417Sdimvoid CStringChecker::evalStrncasecmp(CheckerContext &C, 1932341825Sdim const CallExpr *CE) const { 1933224145Sdim //int strncasecmp(const char *s1, const char *s2, size_t n); 1934360784Sdim evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ true); 1935223017Sdim} 1936223017Sdim 1937221345Sdimvoid CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, 1938360784Sdim bool IsBounded, bool IgnoreCase) const { 1939224145Sdim CurrentFunctionDescription = "string comparison function"; 1940234353Sdim ProgramStateRef state = C.getState(); 1941234353Sdim const LocationContext *LCtx = C.getLocationContext(); 1942221345Sdim 1943221345Sdim // Check that the first string is non-null 1944221345Sdim const Expr *s1 = CE->getArg(0); 1945234353Sdim SVal s1Val = state->getSVal(s1, LCtx); 1946360784Sdim state = checkNonNull(C, state, s1, s1Val, 1); 1947221345Sdim if (!state) 1948221345Sdim return; 1949221345Sdim 1950221345Sdim // Check that the second string is non-null. 1951221345Sdim const Expr *s2 = CE->getArg(1); 1952234353Sdim SVal s2Val = state->getSVal(s2, LCtx); 1953360784Sdim state = checkNonNull(C, state, s2, s2Val, 2); 1954221345Sdim if (!state) 1955221345Sdim return; 1956221345Sdim 1957221345Sdim // Get the string length of the first string or give up. 1958221345Sdim SVal s1Length = getCStringLength(C, state, s1, s1Val); 1959221345Sdim if (s1Length.isUndef()) 1960221345Sdim return; 1961221345Sdim 1962221345Sdim // Get the string length of the second string or give up. 1963221345Sdim SVal s2Length = getCStringLength(C, state, s2, s2Val); 1964221345Sdim if (s2Length.isUndef()) 1965221345Sdim return; 1966221345Sdim 1967224145Sdim // If we know the two buffers are the same, we know the result is 0. 1968224145Sdim // First, get the two buffers' addresses. Another checker will have already 1969224145Sdim // made sure they're not undefined. 1970249423Sdim DefinedOrUnknownSVal LV = s1Val.castAs<DefinedOrUnknownSVal>(); 1971249423Sdim DefinedOrUnknownSVal RV = s2Val.castAs<DefinedOrUnknownSVal>(); 1972221345Sdim 1973224145Sdim // See if they are the same. 1974224145Sdim SValBuilder &svalBuilder = C.getSValBuilder(); 1975224145Sdim DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV); 1976234353Sdim ProgramStateRef StSameBuf, StNotSameBuf; 1977276479Sdim std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); 1978221345Sdim 1979224145Sdim // If the two arguments might be the same buffer, we know the result is 0, 1980224145Sdim // and we only need to check one size. 1981224145Sdim if (StSameBuf) { 1982234353Sdim StSameBuf = StSameBuf->BindExpr(CE, LCtx, 1983341825Sdim svalBuilder.makeZeroVal(CE->getType())); 1984224145Sdim C.addTransition(StSameBuf); 1985221345Sdim 1986224145Sdim // If the two arguments are GUARANTEED to be the same, we're done! 1987224145Sdim if (!StNotSameBuf) 1988221345Sdim return; 1989224145Sdim } 1990221345Sdim 1991224145Sdim assert(StNotSameBuf); 1992224145Sdim state = StNotSameBuf; 1993224145Sdim 1994224145Sdim // At this point we can go about comparing the two buffers. 1995224145Sdim // For now, we only do this if they're both known string literals. 1996224145Sdim 1997224145Sdim // Attempt to extract string literals from both expressions. 1998224145Sdim const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val); 1999224145Sdim const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val); 2000224145Sdim bool canComputeResult = false; 2001309124Sdim SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, 2002341825Sdim C.blockCount()); 2003224145Sdim 2004224145Sdim if (s1StrLiteral && s2StrLiteral) { 2005226633Sdim StringRef s1StrRef = s1StrLiteral->getString(); 2006226633Sdim StringRef s2StrRef = s2StrLiteral->getString(); 2007224145Sdim 2008360784Sdim if (IsBounded) { 2009224145Sdim // Get the max number of characters to compare. 2010224145Sdim const Expr *lenExpr = CE->getArg(2); 2011234353Sdim SVal lenVal = state->getSVal(lenExpr, LCtx); 2012224145Sdim 2013224145Sdim // If the length is known, we can get the right substrings. 2014224145Sdim if (const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) { 2015224145Sdim // Create substrings of each to compare the prefix. 2016224145Sdim s1StrRef = s1StrRef.substr(0, (size_t)len->getZExtValue()); 2017224145Sdim s2StrRef = s2StrRef.substr(0, (size_t)len->getZExtValue()); 2018224145Sdim canComputeResult = true; 2019224145Sdim } 2020224145Sdim } else { 2021224145Sdim // This is a normal, unbounded strcmp. 2022224145Sdim canComputeResult = true; 2023224145Sdim } 2024224145Sdim 2025224145Sdim if (canComputeResult) { 2026224145Sdim // Real strcmp stops at null characters. 2027224145Sdim size_t s1Term = s1StrRef.find('\0'); 2028226633Sdim if (s1Term != StringRef::npos) 2029224145Sdim s1StrRef = s1StrRef.substr(0, s1Term); 2030224145Sdim 2031224145Sdim size_t s2Term = s2StrRef.find('\0'); 2032226633Sdim if (s2Term != StringRef::npos) 2033224145Sdim s2StrRef = s2StrRef.substr(0, s2Term); 2034224145Sdim 2035224145Sdim // Use StringRef's comparison methods to compute the actual result. 2036360784Sdim int compareRes = IgnoreCase ? s1StrRef.compare_lower(s2StrRef) 2037341825Sdim : s1StrRef.compare(s2StrRef); 2038224145Sdim 2039309124Sdim // The strcmp function returns an integer greater than, equal to, or less 2040309124Sdim // than zero, [c11, p7.24.4.2]. 2041309124Sdim if (compareRes == 0) { 2042309124Sdim resultVal = svalBuilder.makeIntVal(compareRes, CE->getType()); 2043224145Sdim } 2044309124Sdim else { 2045309124Sdim DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType()); 2046309124Sdim // Constrain strcmp's result range based on the result of StringRef's 2047309124Sdim // comparison methods. 2048309124Sdim BinaryOperatorKind op = (compareRes == 1) ? BO_GT : BO_LT; 2049309124Sdim SVal compareWithZero = 2050309124Sdim svalBuilder.evalBinOp(state, op, resultVal, zeroVal, 2051341825Sdim svalBuilder.getConditionType()); 2052309124Sdim DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>(); 2053309124Sdim state = state->assume(compareWithZeroVal, true); 2054309124Sdim } 2055224145Sdim } 2056223017Sdim } 2057221345Sdim 2058309124Sdim state = state->BindExpr(CE, LCtx, resultVal); 2059221345Sdim 2060224145Sdim // Record this as a possible path. 2061221345Sdim C.addTransition(state); 2062221345Sdim} 2063221345Sdim 2064251662Sdimvoid CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const { 2065251662Sdim //char *strsep(char **stringp, const char *delim); 2066251662Sdim // Sanity: does the search string parameter match the return type? 2067251662Sdim const Expr *SearchStrPtr = CE->getArg(0); 2068251662Sdim QualType CharPtrTy = SearchStrPtr->getType()->getPointeeType(); 2069251662Sdim if (CharPtrTy.isNull() || 2070251662Sdim CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType()) 2071251662Sdim return; 2072251662Sdim 2073251662Sdim CurrentFunctionDescription = "strsep()"; 2074251662Sdim ProgramStateRef State = C.getState(); 2075251662Sdim const LocationContext *LCtx = C.getLocationContext(); 2076251662Sdim 2077251662Sdim // Check that the search string pointer is non-null (though it may point to 2078251662Sdim // a null string). 2079251662Sdim SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx); 2080360784Sdim State = checkNonNull(C, State, SearchStrPtr, SearchStrVal, 1); 2081251662Sdim if (!State) 2082251662Sdim return; 2083251662Sdim 2084251662Sdim // Check that the delimiter string is non-null. 2085251662Sdim const Expr *DelimStr = CE->getArg(1); 2086251662Sdim SVal DelimStrVal = State->getSVal(DelimStr, LCtx); 2087360784Sdim State = checkNonNull(C, State, DelimStr, DelimStrVal, 2); 2088251662Sdim if (!State) 2089251662Sdim return; 2090251662Sdim 2091251662Sdim SValBuilder &SVB = C.getSValBuilder(); 2092251662Sdim SVal Result; 2093251662Sdim if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) { 2094251662Sdim // Get the current value of the search string pointer, as a char*. 2095251662Sdim Result = State->getSVal(*SearchStrLoc, CharPtrTy); 2096251662Sdim 2097251662Sdim // Invalidate the search string, representing the change of one delimiter 2098251662Sdim // character to NUL. 2099261991Sdim State = InvalidateBuffer(C, State, SearchStrPtr, Result, 2100341825Sdim /*IsSourceBuffer*/false, nullptr); 2101251662Sdim 2102251662Sdim // Overwrite the search string pointer. The new value is either an address 2103251662Sdim // further along in the same string, or NULL if there are no more tokens. 2104251662Sdim State = State->bindLoc(*SearchStrLoc, 2105341825Sdim SVB.conjureSymbolVal(getTag(), 2106341825Sdim CE, 2107341825Sdim LCtx, 2108341825Sdim CharPtrTy, 2109341825Sdim C.blockCount()), 2110341825Sdim LCtx); 2111251662Sdim } else { 2112251662Sdim assert(SearchStrVal.isUnknown()); 2113251662Sdim // Conjure a symbolic value. It's the best we can do. 2114276479Sdim Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 2115251662Sdim } 2116251662Sdim 2117251662Sdim // Set the return value, and finish. 2118251662Sdim State = State->BindExpr(CE, LCtx, Result); 2119251662Sdim C.addTransition(State); 2120251662Sdim} 2121251662Sdim 2122309124Sdim// These should probably be moved into a C++ standard library checker. 2123309124Sdimvoid CStringChecker::evalStdCopy(CheckerContext &C, const CallExpr *CE) const { 2124309124Sdim evalStdCopyCommon(C, CE); 2125309124Sdim} 2126251662Sdim 2127309124Sdimvoid CStringChecker::evalStdCopyBackward(CheckerContext &C, 2128341825Sdim const CallExpr *CE) const { 2129309124Sdim evalStdCopyCommon(C, CE); 2130309124Sdim} 2131309124Sdim 2132309124Sdimvoid CStringChecker::evalStdCopyCommon(CheckerContext &C, 2133341825Sdim const CallExpr *CE) const { 2134353358Sdim if (!CE->getArg(2)->getType()->isPointerType()) 2135309124Sdim return; 2136309124Sdim 2137309124Sdim ProgramStateRef State = C.getState(); 2138309124Sdim 2139309124Sdim const LocationContext *LCtx = C.getLocationContext(); 2140309124Sdim 2141309124Sdim // template <class _InputIterator, class _OutputIterator> 2142309124Sdim // _OutputIterator 2143309124Sdim // copy(_InputIterator __first, _InputIterator __last, 2144309124Sdim // _OutputIterator __result) 2145309124Sdim 2146309124Sdim // Invalidate the destination buffer 2147309124Sdim const Expr *Dst = CE->getArg(2); 2148309124Sdim SVal DstVal = State->getSVal(Dst, LCtx); 2149309124Sdim State = InvalidateBuffer(C, State, Dst, DstVal, /*IsSource=*/false, 2150341825Sdim /*Size=*/nullptr); 2151309124Sdim 2152309124Sdim SValBuilder &SVB = C.getSValBuilder(); 2153309124Sdim 2154309124Sdim SVal ResultVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); 2155309124Sdim State = State->BindExpr(CE, LCtx, ResultVal); 2156309124Sdim 2157309124Sdim C.addTransition(State); 2158309124Sdim} 2159309124Sdim 2160321369Sdimvoid CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const { 2161321369Sdim CurrentFunctionDescription = "memory set function"; 2162321369Sdim 2163321369Sdim const Expr *Mem = CE->getArg(0); 2164341825Sdim const Expr *CharE = CE->getArg(1); 2165321369Sdim const Expr *Size = CE->getArg(2); 2166321369Sdim ProgramStateRef State = C.getState(); 2167321369Sdim 2168321369Sdim // See if the size argument is zero. 2169321369Sdim const LocationContext *LCtx = C.getLocationContext(); 2170321369Sdim SVal SizeVal = State->getSVal(Size, LCtx); 2171321369Sdim QualType SizeTy = Size->getType(); 2172321369Sdim 2173321369Sdim ProgramStateRef StateZeroSize, StateNonZeroSize; 2174321369Sdim std::tie(StateZeroSize, StateNonZeroSize) = 2175321369Sdim assumeZero(C, State, SizeVal, SizeTy); 2176321369Sdim 2177321369Sdim // Get the value of the memory area. 2178321369Sdim SVal MemVal = State->getSVal(Mem, LCtx); 2179321369Sdim 2180321369Sdim // If the size is zero, there won't be any actual memory access, so 2181321369Sdim // just bind the return value to the Mem buffer and return. 2182321369Sdim if (StateZeroSize && !StateNonZeroSize) { 2183321369Sdim StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal); 2184321369Sdim C.addTransition(StateZeroSize); 2185321369Sdim return; 2186321369Sdim } 2187321369Sdim 2188321369Sdim // Ensure the memory area is not null. 2189321369Sdim // If it is NULL there will be a NULL pointer dereference. 2190360784Sdim State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1); 2191321369Sdim if (!State) 2192321369Sdim return; 2193321369Sdim 2194321369Sdim State = CheckBufferAccess(C, State, Size, Mem); 2195321369Sdim if (!State) 2196321369Sdim return; 2197341825Sdim 2198341825Sdim // According to the values of the arguments, bind the value of the second 2199341825Sdim // argument to the destination buffer and set string length, or just 2200341825Sdim // invalidate the destination buffer. 2201344779Sdim if (!memsetAux(Mem, C.getSVal(CharE), Size, C, State)) 2202321369Sdim return; 2203321369Sdim 2204321369Sdim State = State->BindExpr(CE, LCtx, MemVal); 2205321369Sdim C.addTransition(State); 2206321369Sdim} 2207321369Sdim 2208344779Sdimvoid CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const { 2209344779Sdim CurrentFunctionDescription = "memory clearance function"; 2210344779Sdim 2211344779Sdim const Expr *Mem = CE->getArg(0); 2212344779Sdim const Expr *Size = CE->getArg(1); 2213344779Sdim SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy); 2214344779Sdim 2215344779Sdim ProgramStateRef State = C.getState(); 2216360784Sdim 2217344779Sdim // See if the size argument is zero. 2218344779Sdim SVal SizeVal = C.getSVal(Size); 2219344779Sdim QualType SizeTy = Size->getType(); 2220344779Sdim 2221344779Sdim ProgramStateRef StateZeroSize, StateNonZeroSize; 2222344779Sdim std::tie(StateZeroSize, StateNonZeroSize) = 2223344779Sdim assumeZero(C, State, SizeVal, SizeTy); 2224344779Sdim 2225344779Sdim // If the size is zero, there won't be any actual memory access, 2226344779Sdim // In this case we just return. 2227344779Sdim if (StateZeroSize && !StateNonZeroSize) { 2228344779Sdim C.addTransition(StateZeroSize); 2229344779Sdim return; 2230344779Sdim } 2231344779Sdim 2232344779Sdim // Get the value of the memory area. 2233344779Sdim SVal MemVal = C.getSVal(Mem); 2234344779Sdim 2235344779Sdim // Ensure the memory area is not null. 2236344779Sdim // If it is NULL there will be a NULL pointer dereference. 2237360784Sdim State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1); 2238344779Sdim if (!State) 2239344779Sdim return; 2240344779Sdim 2241344779Sdim State = CheckBufferAccess(C, State, Size, Mem); 2242344779Sdim if (!State) 2243344779Sdim return; 2244344779Sdim 2245344779Sdim if (!memsetAux(Mem, Zero, Size, C, State)) 2246344779Sdim return; 2247344779Sdim 2248344779Sdim C.addTransition(State); 2249344779Sdim} 2250344779Sdim 2251218887Sdim//===----------------------------------------------------------------------===// 2252218887Sdim// The driver method, and other Checker callbacks. 2253218887Sdim//===----------------------------------------------------------------------===// 2254218887Sdim 2255353358SdimCStringChecker::FnCheck CStringChecker::identifyCall(const CallEvent &Call, 2256353358Sdim CheckerContext &C) const { 2257353358Sdim const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); 2258353358Sdim if (!CE) 2259344779Sdim return nullptr; 2260218887Sdim 2261353358Sdim const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); 2262353358Sdim if (!FD) 2263353358Sdim return nullptr; 2264353358Sdim 2265353358Sdim if (Call.isCalled(StdCopy)) { 2266353358Sdim return &CStringChecker::evalStdCopy; 2267353358Sdim } else if (Call.isCalled(StdCopyBackward)) { 2268353358Sdim return &CStringChecker::evalStdCopyBackward; 2269353358Sdim } 2270353358Sdim 2271344779Sdim // Pro-actively check that argument types are safe to do arithmetic upon. 2272344779Sdim // We do not want to crash if someone accidentally passes a structure 2273353358Sdim // into, say, a C++ overload of any of these functions. We could not check 2274353358Sdim // that for std::copy because they may have arguments of other types. 2275353358Sdim for (auto I : CE->arguments()) { 2276353358Sdim QualType T = I->getType(); 2277353358Sdim if (!T->isIntegralOrEnumerationType() && !T->isPointerType()) 2278344779Sdim return nullptr; 2279344779Sdim } 2280344779Sdim 2281353358Sdim const FnCheck *Callback = Callbacks.lookup(Call); 2282353358Sdim if (Callback) 2283353358Sdim return *Callback; 2284296417Sdim 2285344779Sdim return nullptr; 2286344779Sdim} 2287344779Sdim 2288353358Sdimbool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { 2289353358Sdim FnCheck Callback = identifyCall(Call, C); 2290344779Sdim 2291218887Sdim // If the callee isn't a string function, let another checker handle it. 2292353358Sdim if (!Callback) 2293218887Sdim return false; 2294218887Sdim 2295218887Sdim // Check and evaluate the call. 2296353358Sdim const auto *CE = cast<CallExpr>(Call.getOriginExpr()); 2297353358Sdim (this->*Callback)(C, CE); 2298234353Sdim 2299234353Sdim // If the evaluate call resulted in no change, chain to the next eval call 2300234353Sdim // handler. 2301234353Sdim // Note, the custom CString evaluation calls assume that basic safety 2302234353Sdim // properties are held. However, if the user chooses to turn off some of these 2303234353Sdim // checks, we ignore the issues and leave the call evaluation to a generic 2304234353Sdim // handler. 2305296417Sdim return C.isDifferent(); 2306218887Sdim} 2307218887Sdim 2308219077Sdimvoid CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { 2309218887Sdim // Record string length for char a[] = "abc"; 2310234353Sdim ProgramStateRef state = C.getState(); 2311218887Sdim 2312276479Sdim for (const auto *I : DS->decls()) { 2313276479Sdim const VarDecl *D = dyn_cast<VarDecl>(I); 2314218887Sdim if (!D) 2315218887Sdim continue; 2316218887Sdim 2317218887Sdim // FIXME: Handle array fields of structs. 2318218887Sdim if (!D->getType()->isArrayType()) 2319218887Sdim continue; 2320218887Sdim 2321218887Sdim const Expr *Init = D->getInit(); 2322218887Sdim if (!Init) 2323218887Sdim continue; 2324218887Sdim if (!isa<StringLiteral>(Init)) 2325218887Sdim continue; 2326218887Sdim 2327234353Sdim Loc VarLoc = state->getLValue(D, C.getLocationContext()); 2328218887Sdim const MemRegion *MR = VarLoc.getAsRegion(); 2329218887Sdim if (!MR) 2330218887Sdim continue; 2331218887Sdim 2332341825Sdim SVal StrVal = C.getSVal(Init); 2333218887Sdim assert(StrVal.isValid() && "Initializer string is unknown or undefined"); 2334249423Sdim DefinedOrUnknownSVal strLength = 2335341825Sdim getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>(); 2336218887Sdim 2337218887Sdim state = state->set<CStringLength>(MR, strLength); 2338218887Sdim } 2339218887Sdim 2340218887Sdim C.addTransition(state); 2341218887Sdim} 2342218887Sdim 2343296417SdimProgramStateRef 2344234353SdimCStringChecker::checkRegionChanges(ProgramStateRef state, 2345341825Sdim const InvalidatedSymbols *, 2346341825Sdim ArrayRef<const MemRegion *> ExplicitRegions, 2347341825Sdim ArrayRef<const MemRegion *> Regions, 2348341825Sdim const LocationContext *LCtx, 2349341825Sdim const CallEvent *Call) const { 2350243830Sdim CStringLengthTy Entries = state->get<CStringLength>(); 2351218887Sdim if (Entries.isEmpty()) 2352218887Sdim return state; 2353218887Sdim 2354218887Sdim llvm::SmallPtrSet<const MemRegion *, 8> Invalidated; 2355218887Sdim llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions; 2356218887Sdim 2357218887Sdim // First build sets for the changed regions and their super-regions. 2358226633Sdim for (ArrayRef<const MemRegion *>::iterator 2359341825Sdim I = Regions.begin(), E = Regions.end(); I != E; ++I) { 2360226633Sdim const MemRegion *MR = *I; 2361218887Sdim Invalidated.insert(MR); 2362218887Sdim 2363218887Sdim SuperRegions.insert(MR); 2364218887Sdim while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) { 2365218887Sdim MR = SR->getSuperRegion(); 2366218887Sdim SuperRegions.insert(MR); 2367218887Sdim } 2368218887Sdim } 2369218887Sdim 2370243830Sdim CStringLengthTy::Factory &F = state->get_context<CStringLength>(); 2371218887Sdim 2372218887Sdim // Then loop over the entries in the current state. 2373243830Sdim for (CStringLengthTy::iterator I = Entries.begin(), 2374341825Sdim E = Entries.end(); I != E; ++I) { 2375218887Sdim const MemRegion *MR = I.getKey(); 2376218887Sdim 2377218887Sdim // Is this entry for a super-region of a changed region? 2378218887Sdim if (SuperRegions.count(MR)) { 2379218887Sdim Entries = F.remove(Entries, MR); 2380218887Sdim continue; 2381218887Sdim } 2382218887Sdim 2383218887Sdim // Is this entry for a sub-region of a changed region? 2384218887Sdim const MemRegion *Super = MR; 2385218887Sdim while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) { 2386218887Sdim Super = SR->getSuperRegion(); 2387218887Sdim if (Invalidated.count(Super)) { 2388218887Sdim Entries = F.remove(Entries, MR); 2389218887Sdim break; 2390218887Sdim } 2391218887Sdim } 2392218887Sdim } 2393218887Sdim 2394218887Sdim return state->set<CStringLength>(Entries); 2395218887Sdim} 2396218887Sdim 2397234353Sdimvoid CStringChecker::checkLiveSymbols(ProgramStateRef state, 2398341825Sdim SymbolReaper &SR) const { 2399218887Sdim // Mark all symbols in our string length map as valid. 2400243830Sdim CStringLengthTy Entries = state->get<CStringLength>(); 2401218887Sdim 2402243830Sdim for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); 2403341825Sdim I != E; ++I) { 2404218887Sdim SVal Len = I.getData(); 2405224145Sdim 2406234353Sdim for (SymExpr::symbol_iterator si = Len.symbol_begin(), 2407341825Sdim se = Len.symbol_end(); si != se; ++si) 2408224145Sdim SR.markInUse(*si); 2409218887Sdim } 2410218887Sdim} 2411218887Sdim 2412219077Sdimvoid CStringChecker::checkDeadSymbols(SymbolReaper &SR, 2413341825Sdim CheckerContext &C) const { 2414234353Sdim ProgramStateRef state = C.getState(); 2415243830Sdim CStringLengthTy Entries = state->get<CStringLength>(); 2416218887Sdim if (Entries.isEmpty()) 2417218887Sdim return; 2418218887Sdim 2419243830Sdim CStringLengthTy::Factory &F = state->get_context<CStringLength>(); 2420243830Sdim for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); 2421341825Sdim I != E; ++I) { 2422218887Sdim SVal Len = I.getData(); 2423218887Sdim if (SymbolRef Sym = Len.getAsSymbol()) { 2424218887Sdim if (SR.isDead(Sym)) 2425218887Sdim Entries = F.remove(Entries, I.getKey()); 2426218887Sdim } 2427218887Sdim } 2428218887Sdim 2429218887Sdim state = state->set<CStringLength>(Entries); 2430234353Sdim C.addTransition(state); 2431218887Sdim} 2432219077Sdim 2433353358Sdimvoid ento::registerCStringModeling(CheckerManager &Mgr) { 2434353358Sdim Mgr.registerChecker<CStringChecker>(); 2435353358Sdim} 2436353358Sdim 2437353358Sdimbool ento::shouldRegisterCStringModeling(const LangOptions &LO) { 2438353358Sdim return true; 2439353358Sdim} 2440353358Sdim 2441276479Sdim#define REGISTER_CHECKER(name) \ 2442276479Sdim void ento::register##name(CheckerManager &mgr) { \ 2443353358Sdim CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ 2444276479Sdim checker->Filter.Check##name = true; \ 2445360784Sdim checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ 2446353358Sdim } \ 2447353358Sdim \ 2448360784Sdim bool ento::shouldRegister##name(const LangOptions &LO) { return true; } 2449234353Sdim 2450360784SdimREGISTER_CHECKER(CStringNullArg) 2451360784SdimREGISTER_CHECKER(CStringOutOfBounds) 2452360784SdimREGISTER_CHECKER(CStringBufferOverlap) 2453234353SdimREGISTER_CHECKER(CStringNotNullTerm) 2454