29#include "llvm/ADT/APSInt.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/Support/raw_ostream.h"
38using namespace std::placeholders;
43 unsigned ArgumentIndex;
45struct SourceArgExpr : AnyArgExpr {};
46struct DestinationArgExpr : AnyArgExpr {};
47struct SizeArgExpr : AnyArgExpr {};
50enum class AccessKind { write, read };
52static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
55 llvm::raw_svector_ostream Os(Message);
59 << &FunctionDescription.data()[1];
61 if (Access == AccessKind::write) {
62 Os <<
" overflows the destination buffer";
64 Os <<
" accesses out-of-bound array element";
70enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
72enum class CharKind { Regular = 0,
Wide };
73constexpr CharKind CK_Regular = CharKind::Regular;
74constexpr CharKind CK_Wide = CharKind::Wide;
83 check::LiveSymbols, check::DeadSymbols,
84 check::RegionChanges> {
85 mutable const char *CurrentFunctionDescription =
nullptr;
95 "Improper arguments"};
98 "Accessing unitialized/garbage values"};
100 StringRef
getDebugTag()
const override {
return "MallocChecker"; }
102 static void *getTag() {
static int tag;
return &tag; }
121 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
122 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
123 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
124 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
125 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
126 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
127 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
128 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
129 {{CDM::CLibrary, {
"memcmp"}, 3},
130 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
131 {{CDM::CLibrary, {
"wmemcmp"}, 3},
132 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
133 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
134 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
135 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
136 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
137 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
138 &CStringChecker::evalMemset},
139 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
141 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
142 &CStringChecker::evalStrcpy},
143 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
144 &CStringChecker::evalStrncpy},
145 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
146 &CStringChecker::evalStpcpy},
147 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
148 &CStringChecker::evalStrlcpy},
149 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
150 &CStringChecker::evalStrcat},
151 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
152 &CStringChecker::evalStrncat},
153 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
154 &CStringChecker::evalStrlcat},
155 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
156 &CStringChecker::evalstrLength},
157 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
158 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
159 &CStringChecker::evalstrnLength},
160 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
161 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
162 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
163 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
164 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
165 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
166 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
167 {{CDM::CLibrary, {
"bcmp"}, 3},
168 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
169 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
170 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
171 &CStringChecker::evalBzero},
179 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
180 &CStringChecker::evalSprintf},
181 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
182 &CStringChecker::evalSnprintf},
187 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
196 DestinationArgExpr Dest, SourceArgExpr Source,
197 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
204 bool IsStrnlen =
false)
const;
211 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
212 bool returnPtr =
true)
const;
223 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
236 bool IsBounded)
const;
239 std::pair<ProgramStateRef , ProgramStateRef >
255 bool hypothetical =
false)
const;
274 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
290 InvalidationTraitOperations);
292 static bool SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
301 AnyArgExpr Arg,
SVal l)
const;
305 AnyArgExpr Buffer,
SVal Element,
SVal Size)
const;
307 AnyArgExpr Buffer,
SVal Element,
309 CharKind CK = CharKind::Regular)
const;
311 AnyArgExpr Buffer, SizeArgExpr Size,
313 CharKind CK = CharKind::Regular)
const;
315 SizeArgExpr Size, AnyArgExpr
First,
317 CharKind CK = CharKind::Regular)
const;
321 const Stmt *Second)
const;
324 StringRef WarningMsg)
const;
326 const Stmt *S, StringRef WarningMsg)
const;
328 const Stmt *S, StringRef WarningMsg)
const;
331 StringRef Msg)
const;
353std::pair<ProgramStateRef, ProgramStateRef>
356 std::optional<DefinedSVal> val =
V.getAs<
DefinedSVal>();
358 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
362 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
367 AnyArgExpr Arg,
SVal l)
const {
373 std::tie(stateNull, stateNonNull) =
374 assumeZero(
C, State, l, Arg.Expression->getType());
376 if (stateNull && !stateNonNull) {
377 if (NullArg.isEnabled()) {
379 llvm::raw_svector_ostream OS(buf);
380 assert(CurrentFunctionDescription);
381 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
382 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
383 << CurrentFunctionDescription;
385 emitNullArgBug(
C, stateNull, Arg.Expression, OS.str());
391 assert(stateNonNull);
397 SValBuilder &SVB = State->getStateManager().getSValBuilder();
400 if (CK == CharKind::Regular) {
416 if (Offset.isUnknown())
418 return Offset.castAs<
NonLoc>();
423 Os << Idx << llvm::getOrdinalSuffix(Idx);
428 AnyArgExpr Buffer,
SVal Element,
435 const MemRegion *R = Element.getAsRegion();
436 const auto *ER = dyn_cast_or_null<ElementRegion>(R);
446 if (!SuperR->getValueType()->isArrayType())
455 std::optional<Loc> FirstElementVal =
457 if (!FirstElementVal)
461 if (UninitializedRead.isEnabled() &&
462 State->getSVal(*FirstElementVal).isUndef()) {
464 llvm::raw_svector_ostream OS(Buf);
465 OS <<
"The first element of the ";
467 OS <<
" argument is undefined";
468 emitUninitializedReadBug(
C, State, Buffer.Expression,
469 FirstElementVal->getAsRegion(), OS.str());
500 std::optional<NonLoc> Offset =
512 SVal LastElementVal =
514 if (!isa<Loc>(LastElementVal))
517 if (UninitializedRead.isEnabled() &&
518 State->getSVal(LastElementVal.
castAs<
Loc>()).isUndef()) {
519 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
527 llvm::raw_svector_ostream OS(Buf);
528 OS <<
"The last accessed element (at index ";
529 OS << IdxInt->getExtValue();
532 OS <<
" argument is undefined";
533 emitUninitializedReadBug(
C, State, Buffer.Expression,
545 AnyArgExpr Buffer,
SVal Element,
554 const MemRegion *R = Element.getAsRegion();
558 const auto *ER = dyn_cast<ElementRegion>(R);
563 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
568 const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
572 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
573 if (StOutBound && !StInBound) {
574 if (!OutOfBounds.isEnabled())
577 ErrorMessage Message =
578 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
579 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
590 AnyArgExpr Buffer, SizeArgExpr Size,
591 AccessKind Access, CharKind CK)
const {
600 QualType PtrTy = getCharPtrType(Ctx, CK);
603 SVal BufVal =
C.getSVal(Buffer.Expression);
604 State = checkNonNull(
C, State, Buffer, BufVal);
609 if (!OutOfBounds.isEnabled())
613 svalBuilder.
evalCast(BufVal, PtrTy, Buffer.Expression->getType());
616 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
624 SVal LengthVal =
C.getSVal(
Size.Expression);
625 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
631 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
632 if (Offset.isUnknown())
637 if (std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>()) {
640 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
641 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
642 if (Access == AccessKind::read)
643 State = checkInit(
C, State, Buffer, BufEnd, *Length);
656 SizeArgExpr Size, AnyArgExpr
First,
659 if (!BufferOverlap.isEnabled())
673 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
674 Second.Expression->getType()->getPointeeType().getAddressSpace())
679 SVal firstVal = state->getSVal(
First.Expression, LCtx);
680 SVal secondVal = state->getSVal(Second.Expression, LCtx);
682 std::optional<Loc> firstLoc = firstVal.
getAs<
Loc>();
686 std::optional<Loc> secondLoc = secondVal.
getAs<
Loc>();
692 std::tie(stateTrue, stateFalse) =
693 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
695 if (stateTrue && !stateFalse) {
697 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
708 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
709 std::optional<DefinedOrUnknownSVal> reverseTest =
714 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
721 std::swap(firstLoc, secondLoc);
724 std::swap(
First, Second);
729 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
730 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
737 QualType CharPtrTy = getCharPtrType(Ctx, CK);
739 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
740 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<
Loc>();
747 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<
Loc>();
753 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
754 std::optional<DefinedOrUnknownSVal> OverlapTest =
759 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
761 if (stateTrue && !stateFalse) {
763 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
779 auto report = std::make_unique<PathSensitiveBugReport>(
780 BufferOverlap,
"Arguments must not be overlapping buffers", N);
781 report->addRange(
First->getSourceRange());
784 C.emitReport(std::move(report));
788 const Stmt *S, StringRef WarningMsg)
const {
791 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
792 Report->addRange(S->getSourceRange());
793 if (
const auto *Ex = dyn_cast<Expr>(S))
795 C.emitReport(std::move(
Report));
802 StringRef Msg)
const {
805 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
806 Report->addNote(
"Other elements might also be undefined",
811 C.emitReport(std::move(
Report));
817 StringRef WarningMsg)
const {
823 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
824 Report->addRange(S->getSourceRange());
825 C.emitReport(std::move(
Report));
831 StringRef WarningMsg)
const {
834 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
836 Report->addRange(S->getSourceRange());
837 C.emitReport(std::move(
Report));
846 if (!OutOfBounds.isEnabled())
857 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
861 if (isa<nonloc::ConcreteInt>(right)) {
862 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
867 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
872 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<
NonLoc>()) {
876 *maxMinusRightNL, cmpTy);
878 auto [StateOverflow, StateOkay] =
881 if (StateOverflow && !StateOkay) {
887 C.addSink(StateOverflow);
902 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
907 case MemRegion::StringRegionKind:
912 case MemRegion::SymbolicRegionKind:
913 case MemRegion::AllocaRegionKind:
914 case MemRegion::NonParamVarRegionKind:
915 case MemRegion::ParamVarRegionKind:
916 case MemRegion::FieldRegionKind:
917 case MemRegion::ObjCIvarRegionKind:
921 case MemRegion::ElementRegionKind:
935 return state->remove<CStringLength>(MR);
937 return state->set<CStringLength>(MR, strLength);
947 const SVal *Recorded = state->get<CStringLength>(MR);
957 C.getLocationContext(),
961 if (std::optional<NonLoc> strLn = strLength.
getAs<
NonLoc>()) {
964 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
966 std::optional<APSIntPtr> maxLengthInt =
969 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
973 state = state->set<CStringLength>(MR, strLength);
981 bool hypothetical)
const {
988 if (NotNullTerm.isEnabled()) {
990 llvm::raw_svector_ostream os(buf);
991 assert(CurrentFunctionDescription);
992 os <<
"Argument to " << CurrentFunctionDescription
993 <<
" is the address of the label '" <<
Label->getLabel()->getName()
994 <<
"', which is not a null-terminated string";
996 emitNotCStringBug(
C, state, Ex, os.str());
1010 case MemRegion::StringRegionKind: {
1015 const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
1018 case MemRegion::NonParamVarRegionKind: {
1021 const VarDecl *
Decl = cast<NonParamVarRegion>(MR)->getDecl();
1022 if (
Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage()) {
1024 if (
auto *StrLit = dyn_cast<StringLiteral>(
Init)) {
1027 return SvalBuilder.
makeIntVal(StrLit->getLength(), SizeTy);
1033 case MemRegion::SymbolicRegionKind:
1034 case MemRegion::AllocaRegionKind:
1035 case MemRegion::ParamVarRegionKind:
1036 case MemRegion::FieldRegionKind:
1037 case MemRegion::ObjCIvarRegionKind:
1038 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1039 case MemRegion::CompoundLiteralRegionKind:
1042 case MemRegion::ElementRegionKind:
1050 if (NotNullTerm.isEnabled()) {
1052 llvm::raw_svector_ostream os(buf);
1054 assert(CurrentFunctionDescription);
1055 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1057 if (SummarizeRegion(os,
C.getASTContext(), MR))
1058 os <<
", which is not a null-terminated string";
1060 os <<
"not a null-terminated string";
1062 emitNotCStringBug(
C, state, Ex, os.str());
1080 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1104 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
1111 if (Offset.isUnknown())
1117 std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>();
1121 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1134 C.getASTContext().CharTy &&
1135 "isFirstBufInBound should only be called with char* ElementRegions");
1146 return static_cast<bool>(StInBound);
1152 auto InvalidationTraitOperations =
1153 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1157 if (MemRegion::FieldRegionKind == R->
getKind() &&
1158 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1166 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1170CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1174 return isa<FieldRegion>(R);
1177 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1180ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1182 auto InvalidationTraitOperations =
1184 if (MemRegion::FieldRegionKind == R->
getKind())
1191 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1198 auto InvalidationTraitOperations =
1208 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1215 InvalidationTraitOperations) {
1216 std::optional<Loc> L =
V.getAs<
Loc>();
1236 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1238 return State->invalidateRegions(R, Elem,
C.blockCount(), LCtx,
1239 CausesPointerEscape,
nullptr,
nullptr,
1246 return State->killBinding(*L);
1249bool CStringChecker::SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
1252 case MemRegion::FunctionCodeRegionKind: {
1253 if (
const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
1254 os <<
"the address of the function '" << *FD <<
'\'';
1256 os <<
"the address of a function";
1259 case MemRegion::BlockCodeRegionKind:
1262 case MemRegion::BlockDataRegionKind:
1265 case MemRegion::CXXThisRegionKind:
1266 case MemRegion::CXXTempObjectRegionKind:
1267 os <<
"a C++ temp object of type "
1268 << cast<TypedValueRegion>(MR)->getValueType();
1270 case MemRegion::NonParamVarRegionKind:
1271 os <<
"a variable of type" << cast<TypedValueRegion>(MR)->getValueType();
1273 case MemRegion::ParamVarRegionKind:
1274 os <<
"a parameter of type" << cast<TypedValueRegion>(MR)->getValueType();
1276 case MemRegion::FieldRegionKind:
1277 os <<
"a field of type " << cast<TypedValueRegion>(MR)->getValueType();
1279 case MemRegion::ObjCIvarRegionKind:
1280 os <<
"an instance variable of type "
1281 << cast<TypedValueRegion>(MR)->getValueType();
1291 SVal MemVal =
C.getSVal(DstBuffer);
1292 SVal SizeVal =
C.getSVal(Size);
1302 const MemRegion *BR = Offset.getRegion();
1304 std::optional<NonLoc> SizeNL = SizeVal.
getAs<
NonLoc>();
1313 if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
1314 Offset.getOffset() == 0) {
1319 std::tie(StateWholeReg, StateNotWholeReg) =
1320 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1327 std::tie(StateNullChar, StateNonNullChar) =
1330 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1331 !StateNonNullChar) {
1338 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1339 C.getLocationContext());
1343 State = invalidateDestinationBufferBySize(
1344 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1347 if (StateNullChar && !StateNonNullChar) {
1350 State = setCStringLength(State, MR,
1352 }
else if (!StateNullChar && StateNonNullChar) {
1354 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1355 C.getLocationContext(),
C.blockCount());
1362 State = setCStringLength(
1369 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1370 SizeVal,
Size->getType());
1381 DestinationArgExpr Dest,
1382 SourceArgExpr Source,
bool Restricted,
1383 bool IsMempcpy, CharKind CK)
const {
1384 CurrentFunctionDescription =
"memory copy function";
1388 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1392 std::tie(stateZeroSize, stateNonZeroSize) =
1393 assumeZero(
C, state, sizeVal, sizeTy);
1396 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1400 if (stateZeroSize && !stateNonZeroSize) {
1402 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1403 C.addTransition(stateZeroSize);
1408 if (stateNonZeroSize) {
1412 state = stateNonZeroSize;
1416 state = checkNonNull(
C, state, Dest, destVal);
1421 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1425 state = checkNonNull(
C, state, Source, srcVal);
1430 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1431 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1434 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1445 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1446 SVal DestRegCharVal =
1447 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1448 SVal lastElement =
C.getSValBuilder().evalBinOp(
1449 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1453 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1456 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1460 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1469 state = invalidateDestinationBufferBySize(
1470 C, state, Dest.Expression,
Call.getCFGElementRef(),
1471 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1475 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1476 C.getSVal(Source.Expression));
1478 C.addTransition(state);
1483 CharKind CK)
const {
1486 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1487 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1488 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1492 constexpr bool IsRestricted =
true;
1493 constexpr bool IsMempcpy =
false;
1494 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1498 CharKind CK)
const {
1501 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1502 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1503 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1505 constexpr bool IsRestricted =
true;
1506 constexpr bool IsMempcpy =
true;
1507 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1512 CharKind CK)
const {
1515 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1516 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1517 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1519 constexpr bool IsRestricted =
false;
1520 constexpr bool IsMempcpy =
false;
1521 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1527 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1528 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1529 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1531 constexpr bool IsRestricted =
false;
1532 constexpr bool IsMempcpy =
false;
1533 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1534 IsMempcpy, CharKind::Regular);
1538 CharKind CK)
const {
1540 CurrentFunctionDescription =
"memory comparison function";
1542 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1543 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1544 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1551 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1555 std::tie(stateZeroSize, stateNonZeroSize) =
1556 assumeZero(
C, State, sizeVal, sizeTy);
1560 if (stateZeroSize) {
1561 State = stateZeroSize;
1562 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1563 Builder.makeZeroVal(
Call.getResultType()));
1564 C.addTransition(State);
1568 if (stateNonZeroSize) {
1569 State = stateNonZeroSize;
1580 std::tie(SameBuffer, NotSameBuffer) =
1581 State->assume(Builder.evalEQ(State, LV, RV));
1585 if (SameBuffer && !NotSameBuffer) {
1587 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1589 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1590 Builder.makeZeroVal(
Call.getResultType()));
1591 C.addTransition(State);
1598 assert(NotSameBuffer);
1599 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1600 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1603 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1604 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1605 C.addTransition(State);
1613 evalstrLengthCommon(
C,
Call,
false);
1619 evalstrLengthCommon(
C,
Call,
true);
1624 bool IsStrnlen)
const {
1625 CurrentFunctionDescription =
"string length function";
1630 const Expr *maxlenExpr =
Call.getArgExpr(1);
1631 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1634 std::tie(stateZeroSize, stateNonZeroSize) =
1635 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1639 if (stateZeroSize) {
1640 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1641 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1642 C.addTransition(stateZeroSize);
1646 if (!stateNonZeroSize)
1650 state = stateNonZeroSize;
1654 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1655 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1656 state = checkNonNull(
C, state, Arg, ArgVal);
1661 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1673 QualType cmpTy =
C.getSValBuilder().getConditionType();
1677 const Expr *maxlenExpr =
Call.getArgExpr(1);
1678 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1680 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1681 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<
NonLoc>();
1683 if (strLengthNL && maxlenValNL) {
1687 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1689 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1692 if (stateStringTooLong && !stateStringNotTooLong) {
1694 result = *maxlenValNL;
1695 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1697 result = *strLengthNL;
1706 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1710 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1711 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1716 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1717 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1729 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1734 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1735 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1736 C.addTransition(state);
1742 evalStrcpyCommon(
C,
Call,
1745 ConcatFnKind::none);
1751 evalStrcpyCommon(
C,
Call,
1754 ConcatFnKind::none);
1760 evalStrcpyCommon(
C,
Call,
1763 ConcatFnKind::none);
1769 evalStrcpyCommon(
C,
Call,
1779 evalStrcpyCommon(
C,
Call,
1782 ConcatFnKind::strcat);
1788 evalStrcpyCommon(
C,
Call,
1791 ConcatFnKind::strcat);
1799 evalStrcpyCommon(
C,
Call,
1802 ConcatFnKind::strlcat,
1807 bool ReturnEnd,
bool IsBounded,
1808 ConcatFnKind appendK,
1809 bool returnPtr)
const {
1810 if (appendK == ConcatFnKind::none)
1811 CurrentFunctionDescription =
"string copy function";
1813 CurrentFunctionDescription =
"string concatenation function";
1819 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1820 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1821 state = checkNonNull(
C, state, Dst, DstVal);
1826 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1827 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1828 state = checkNonNull(
C, state, srcExpr, srcVal);
1833 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1834 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1837 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1838 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<
NonLoc>();
1853 const char *boundWarning =
nullptr;
1857 SizeArgExpr SrcExprAsSizeDummy = {
1858 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1859 state = CheckOverlap(
1861 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1870 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1871 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1875 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1877 std::optional<NonLoc> lenValNL = lenVal.
getAs<
NonLoc>();
1881 if (strLengthNL && lenValNL) {
1883 case ConcatFnKind::none:
1884 case ConcatFnKind::strcat: {
1889 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1891 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1892 .castAs<DefinedOrUnknownSVal>());
1894 if (stateSourceTooLong && !stateSourceNotTooLong) {
1897 state = stateSourceTooLong;
1898 amountCopied = lenVal;
1900 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1902 state = stateSourceNotTooLong;
1903 amountCopied = strLength;
1907 case ConcatFnKind::strlcat:
1908 if (!dstStrLengthNL)
1913 *dstStrLengthNL, sizeTy);
1914 if (!isa<NonLoc>(freeSpace))
1917 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1919 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<
NonLoc>();
1926 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1929 std::tie(TrueState, FalseState) =
1933 if (TrueState && !FalseState) {
1934 amountCopied = strLength;
1938 if (!TrueState && FalseState) {
1939 amountCopied = freeSpace;
1942 if (TrueState && FalseState)
1950 case ConcatFnKind::strcat:
1956 if (dstStrLength.isUndef())
1959 if (dstStrLengthNL) {
1961 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1963 boundWarning =
"Size argument is greater than the free space in the "
1964 "destination buffer";
1967 case ConcatFnKind::none:
1968 case ConcatFnKind::strlcat:
1978 std::tie(StateZeroSize, StateNonZeroSize) =
1979 assumeZero(
C, state, *lenValNL, sizeTy);
1982 if (StateZeroSize && !StateNonZeroSize) {
1985 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
1987 if (appendK == ConcatFnKind::none) {
1989 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
1994 state, BO_Add, strLength, dstStrLength, sizeTy);
1996 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
1999 C.addTransition(StateZeroSize);
2007 maxLastElementIndex =
2008 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2009 boundWarning =
"Size argument is greater than the length of the "
2010 "destination buffer";
2017 amountCopied = strLength;
2028 if (appendK == ConcatFnKind::none && !returnPtr) {
2030 strlRetVal = strLength;
2036 if (appendK != ConcatFnKind::none) {
2039 if (dstStrLength.isUndef())
2042 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2043 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2044 *dstStrLengthNL, sizeTy);
2047 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<
NonLoc>();
2050 if (amountCopiedNL && dstStrLengthNL) {
2052 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2056 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2057 *dstStrLengthNL, sizeTy);
2066 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2067 assert(!finalStrLength.
isUndef());
2069 if (std::optional<NonLoc> finalStrLengthNL =
2071 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2075 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2082 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2100 finalStrLength = amountCopied;
2108 Result = (ReturnEnd ?
UnknownVal() : DstVal);
2110 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2112 Result = strlRetVal;
2114 Result = finalStrLength;
2121 if (std::optional<loc::MemRegionVal> dstRegVal =
2123 QualType ptrTy = Dst.Expression->getType();
2127 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<
NonLoc>()) {
2128 SVal maxLastElement =
2129 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2132 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2136 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2142 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<
NonLoc>()) {
2144 *knownStrLength, ptrTy);
2147 if (!boundWarning) {
2149 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2153 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2159 if (returnPtr && ReturnEnd)
2160 Result = lastElement;
2172 bool CouldAccessOutOfBound =
true;
2173 if (IsBounded && amountCopied.
isUnknown()) {
2174 auto CouldAccessOutOfBoundForSVal =
2175 [&](std::optional<NonLoc> Val) ->
bool {
2178 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2179 Dst.Expression->getType(), *Val,
2180 C.getASTContext().getSizeType());
2183 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2185 if (CouldAccessOutOfBound) {
2187 const Expr *LenExpr =
Call.getArgExpr(2);
2188 SVal LenVal = state->getSVal(LenExpr, LCtx);
2196 CouldAccessOutOfBound =
2197 CouldAccessOutOfBoundForSVal(LenVal.
getAs<
NonLoc>());
2208 if (CouldAccessOutOfBound)
2209 state = invalidateDestinationBufferBySize(
2210 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2211 amountCopied,
C.getASTContext().getSizeType());
2213 state = invalidateDestinationBufferNeverOverflows(
2214 C, state,
Call.getCFGElementRef(), *dstRegVal);
2218 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2221 if (IsBounded && (appendK == ConcatFnKind::none)) {
2226 if (amountCopied != strLength)
2229 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2237 if (ReturnEnd && Result.isUnknown()) {
2242 state = state->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2243 C.addTransition(state);
2249 evalStrcmpCommon(
C,
Call,
false,
false);
2255 evalStrcmpCommon(
C,
Call,
true,
false);
2261 evalStrcmpCommon(
C,
Call,
false,
true);
2267 evalStrcmpCommon(
C,
Call,
true,
true);
2271 bool IsBounded,
bool IgnoreCase)
const {
2272 CurrentFunctionDescription =
"string comparison function";
2277 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2278 SVal LeftVal = state->getSVal(
Left.Expression, LCtx);
2279 state = checkNonNull(
C, state, Left, LeftVal);
2284 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2285 SVal RightVal = state->getSVal(
Right.Expression, LCtx);
2286 state = checkNonNull(
C, state, Right, RightVal);
2291 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2296 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2310 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2316 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2317 svalBuilder.makeZeroVal(
Call.getResultType()));
2318 C.addTransition(StSameBuf);
2325 assert(StNotSameBuf);
2326 state = StNotSameBuf;
2333 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2335 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2336 bool canComputeResult =
false;
2337 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2339 if (LeftStrLiteral && RightStrLiteral) {
2340 StringRef LeftStrRef = LeftStrLiteral->
getString();
2341 StringRef RightStrRef = RightStrLiteral->
getString();
2345 const Expr *lenExpr =
Call.getArgExpr(2);
2346 SVal lenVal = state->getSVal(lenExpr, LCtx);
2349 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2351 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2352 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2353 canComputeResult =
true;
2357 canComputeResult =
true;
2360 if (canComputeResult) {
2362 size_t s1Term = LeftStrRef.find(
'\0');
2363 if (s1Term != StringRef::npos)
2364 LeftStrRef = LeftStrRef.substr(0, s1Term);
2366 size_t s2Term = RightStrRef.find(
'\0');
2367 if (s2Term != StringRef::npos)
2368 RightStrRef = RightStrRef.substr(0, s2Term);
2371 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2372 : LeftStrRef.compare(RightStrRef);
2376 if (compareRes == 0) {
2377 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2380 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2384 SVal compareWithZero =
2385 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2386 svalBuilder.getConditionType());
2388 state = state->assume(compareWithZeroVal,
true);
2393 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2396 C.addTransition(state);
2403 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2406 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2410 CurrentFunctionDescription =
"strsep()";
2416 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2417 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2422 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2423 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2424 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2430 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<
Loc>()) {
2432 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2437 State = invalidateDestinationBufferNeverOverflows(
2438 C, State,
Call.getCFGElementRef(), Result);
2442 State = State->bindLoc(*SearchStrLoc,
2452 State = State->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2453 C.addTransition(State);
2459 evalStdCopyCommon(
C,
Call);
2464 evalStdCopyCommon(
C,
Call);
2469 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2482 const Expr *Dst =
Call.getArgExpr(2);
2483 SVal DstVal = State->getSVal(Dst, LCtx);
2486 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2487 C, State,
Call.getCFGElementRef(), DstVal);
2492 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2494 C.addTransition(State);
2500 CurrentFunctionDescription =
"memory set function";
2502 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2503 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2504 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2510 SVal SizeVal =
C.getSVal(
Size.Expression);
2514 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2517 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2521 if (ZeroSize && !NonZeroSize) {
2522 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2523 C.addTransition(ZeroSize);
2529 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2533 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2540 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2541 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2544 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2545 C.addTransition(State);
2549 CurrentFunctionDescription =
"memory clearance function";
2551 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2552 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2553 SVal Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2558 SVal SizeVal =
C.getSVal(
Size.Expression);
2562 std::tie(StateZeroSize, StateNonZeroSize) =
2563 assumeZero(
C, State, SizeVal, SizeTy);
2567 if (StateZeroSize && !StateNonZeroSize) {
2568 C.addTransition(StateZeroSize);
2573 SVal MemVal =
C.getSVal(Buffer.Expression);
2577 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2581 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2585 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
2586 Size.Expression,
C, State))
2589 C.addTransition(State);
2594 CurrentFunctionDescription =
"'sprintf'";
2595 evalSprintfCommon(
C,
Call,
false);
2600 CurrentFunctionDescription =
"'snprintf'";
2601 evalSprintfCommon(
C,
Call,
true);
2605 bool IsBounded)
const {
2607 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
2608 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2610 const auto NumParams =
Call.parameters().size();
2611 if (CE->getNumArgs() < NumParams) {
2616 const auto AllArguments =
2617 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2618 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2620 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2623 !
type->isAnyPointerType() ||
2624 !
type->getPointeeType()->isAnyCharacterType())
2626 SourceArgExpr Source = {{ArgExpr,
unsigned(ArgIdx)}};
2629 SizeArgExpr SrcExprAsSizeDummy = {
2630 {Source.Expression, Source.ArgumentIndex}};
2631 State = CheckOverlap(
2633 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2639 C.addTransition(State);
2646CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2648 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2656 if (StdCopy.matches(
Call))
2657 return &CStringChecker::evalStdCopy;
2658 if (StdCopyBackward.matches(
Call))
2659 return &CStringChecker::evalStdCopyBackward;
2665 for (
auto I : CE->arguments()) {
2671 const FnCheck *Callback = Callbacks.lookup(
Call);
2679 FnCheck Callback = identifyCall(
Call,
C);
2686 assert(isa<CallExpr>(
Call.getOriginExpr()));
2687 Callback(
this,
C,
Call);
2695 return C.isDifferent();
2702 for (
const auto *I : DS->
decls()) {
2703 const VarDecl *
D = dyn_cast<VarDecl>(I);
2708 if (!
D->getType()->isArrayType())
2714 if (!isa<StringLiteral>(
Init))
2717 Loc VarLoc = state->getLValue(
D,
C.getLocationContext());
2723 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2727 state = state->set<CStringLength>(MR, strLength);
2730 C.addTransition(state);
2740 CStringLengthTy Entries = state->get<CStringLength>();
2741 if (Entries.isEmpty())
2749 Invalidated.insert(MR);
2751 SuperRegions.insert(MR);
2752 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2753 MR = SR->getSuperRegion();
2754 SuperRegions.insert(MR);
2758 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2761 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2763 if (SuperRegions.count(MR)) {
2764 Entries = F.remove(Entries, MR);
2770 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2771 Super = SR->getSuperRegion();
2772 if (Invalidated.count(Super)) {
2773 Entries = F.remove(Entries, MR);
2779 return state->set<CStringLength>(Entries);
2785 CStringLengthTy Entries = state->get<CStringLength>();
2787 for (
SVal Len : llvm::make_second_range(Entries)) {
2796 CStringLengthTy Entries = state->get<CStringLength>();
2797 if (Entries.isEmpty())
2800 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2801 for (
auto [Reg, Len] : Entries) {
2802 if (
SymbolRef Sym = Len.getAsSymbol()) {
2804 Entries = F.remove(Entries, Reg);
2808 state = state->set<CStringLength>(Entries);
2809 C.addTransition(state);
2819bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
2823#define REGISTER_CHECKER(NAME) \
2824 void ento::registerCString##NAME(CheckerManager &Mgr) { \
2825 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
2828 bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \
static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)
#define REGISTER_CHECKER(NAME)
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedCharTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Represents a function declaration or definition.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
virtual StringRef getDebugTag() const =0
The description of this program point which will be dumped for debugging purposes.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
StringLiteral - This represents a string literal expression, e.g.
unsigned getLength() const
StringRef getString() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
Represents a variable declaration or definition.
A record of the "type" of an APSInt, used for conversions.
llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY
APSIntPtr getMaxValue(const llvm::APSInt &v)
std::optional< APSIntPtr > evalAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt &V1, const llvm::APSInt &V2)
An immutable map from CallDescriptions to arbitrary data.
A CallDescription is a pattern that can be used to match calls based on the qualified name and the ar...
Represents an abstract call to a function or method along a particular path.
Checker families (where a single backend class implements multiple related frontends) should derive f...
Trivial convenience class for the common case when a certain checker frontend always uses the same bu...
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
ElementRegion is used to represent both array elements and casts.
QualType getValueType() const override
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const RegionTy * castAs() const
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
Put a diagnostic on return statement of all inlined functions for which the region of interest Region...
Information about invalidation for a particular region/symbol.
@ TK_PreserveContents
Tells that a region's contents is not changed.
@ TK_DoNotInvalidateSuperRegion
@ TK_SuppressEscape
Suppress pointer-escaping of a region.
void setTrait(SymbolRef Sym, InvalidationKinds IK)
Represent a region's offset within the top level base region.
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with a memory location and non-location opera...
DefinedSVal getMetadataSymbolVal(const void *symbolTag, const MemRegion *region, const Expr *expr, QualType type, const LocationContext *LCtx, unsigned count)
virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, Loc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two memory location operands.
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
QualType getArrayIndexType() const
loc::MemRegionVal makeLoc(SymbolRef sym)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy)
Cast a given SVal to another SVal using given QualType's.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, ConstCFGElementRef elem, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
NonLoc makeZeroArrayIndex()
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
StringRegion - Region associated with a StringLiteral.
LLVM_ATTRIBUTE_RETURNS_NONNULL const StringLiteral * getStringLiteral() const
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
llvm::iterator_range< symbol_iterator > symbols() const
A class responsible for cleaning up unused symbols.
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
void markInUse(SymbolRef sym)
Marks a symbol as important to a checker.
TypedValueRegion - An abstract class representing regions having a typed value.
__inline void unsigned int _2
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
const char *const UnixAPI
DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB)
llvm::DenseSet< SymbolRef > InvalidatedSymbols
The JSON file list parser is used to communicate input to InstallAPI.
CFGBlock::ConstCFGElementRef ConstCFGElementRef
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
const FunctionProtoType * T
int const char * function