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