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