29#include "llvm/ADT/APSInt.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/Support/Casting.h"
33#include "llvm/Support/raw_ostream.h"
39using namespace std::placeholders;
44 unsigned ArgumentIndex;
46struct SourceArgExpr : AnyArgExpr {};
47struct DestinationArgExpr : AnyArgExpr {};
48struct SizeArgExpr : AnyArgExpr {};
51enum class AccessKind { write, read };
53static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
56 llvm::raw_svector_ostream Os(Message);
60 << &FunctionDescription.data()[1];
62 if (Access == AccessKind::write) {
63 Os <<
" overflows the destination buffer";
65 Os <<
" accesses out-of-bound array element";
71enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
73enum class CharKind { Regular = 0,
Wide };
74constexpr CharKind CK_Regular = CharKind::Regular;
75constexpr CharKind CK_Wide = CharKind::Wide;
82class CStringChecker :
public Checker< eval::Call,
83 check::PreStmt<DeclStmt>,
88 mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
89 BT_NotCString, BT_AdditionOverflow, BT_UninitRead;
91 mutable const char *CurrentFunctionDescription =
nullptr;
96 struct CStringChecksFilter {
97 bool CheckCStringNullArg =
false;
98 bool CheckCStringOutOfBounds =
false;
99 bool CheckCStringBufferOverlap =
false;
100 bool CheckCStringNotNullTerm =
false;
101 bool CheckCStringUninitializedRead =
false;
110 CStringChecksFilter
Filter;
112 static void *getTag() {
static int tag;
return &tag; }
127 using FnCheck = std::function<void(
const CStringChecker *,
CheckerContext &,
131 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
132 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
133 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
134 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
135 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
136 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
137 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
138 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
139 {{CDM::CLibrary, {
"memcmp"}, 3},
140 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
141 {{CDM::CLibrary, {
"wmemcmp"}, 3},
142 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
143 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
144 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
145 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
146 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
147 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
148 &CStringChecker::evalMemset},
149 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
151 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
152 &CStringChecker::evalStrcpy},
153 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
154 &CStringChecker::evalStrncpy},
155 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
156 &CStringChecker::evalStpcpy},
157 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
158 &CStringChecker::evalStrlcpy},
159 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
160 &CStringChecker::evalStrcat},
161 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
162 &CStringChecker::evalStrncat},
163 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
164 &CStringChecker::evalStrlcat},
165 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
166 &CStringChecker::evalstrLength},
167 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
168 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
169 &CStringChecker::evalstrnLength},
170 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
171 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
172 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
173 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
174 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
175 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
176 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
177 {{CDM::CLibrary, {
"bcmp"}, 3},
178 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
179 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
180 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
181 &CStringChecker::evalBzero},
189 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
190 &CStringChecker::evalSprintf},
191 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
192 &CStringChecker::evalSnprintf},
197 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
206 DestinationArgExpr Dest, SourceArgExpr Source,
207 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
214 bool IsStrnlen =
false)
const;
221 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
222 bool returnPtr =
true)
const;
233 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
246 bool IsBounded)
const;
249 std::pair<ProgramStateRef , ProgramStateRef >
265 bool hypothetical =
false)
const;
284 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
299 InvalidationTraitOperations);
301 static bool SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
304 static bool memsetAux(
const Expr *DstBuffer,
SVal CharE,
310 AnyArgExpr Arg,
SVal l)
const;
314 AnyArgExpr Buffer,
SVal Element,
SVal Size)
const;
316 AnyArgExpr Buffer,
SVal Element,
318 CharKind CK = CharKind::Regular)
const;
320 AnyArgExpr Buffer, SizeArgExpr Size,
322 CharKind CK = CharKind::Regular)
const;
324 SizeArgExpr Size, AnyArgExpr
First,
326 CharKind CK = CharKind::Regular)
const;
330 const Stmt *Second)
const;
333 StringRef WarningMsg)
const;
335 const Stmt *S, StringRef WarningMsg)
const;
337 const Stmt *S, StringRef WarningMsg)
const;
340 const Expr *
E, StringRef Msg)
const;
362std::pair<ProgramStateRef, ProgramStateRef>
365 std::optional<DefinedSVal> val =
V.getAs<
DefinedSVal>();
367 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
371 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
376 AnyArgExpr Arg,
SVal l)
const {
382 std::tie(stateNull, stateNonNull) =
383 assumeZero(
C, State, l, Arg.Expression->getType());
385 if (stateNull && !stateNonNull) {
386 if (
Filter.CheckCStringNullArg) {
388 llvm::raw_svector_ostream OS(buf);
389 assert(CurrentFunctionDescription);
390 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
391 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
392 << CurrentFunctionDescription;
394 emitNullArgBug(
C, stateNull, Arg.Expression, OS.str());
400 assert(stateNonNull);
406 SValBuilder &SVB = State->getStateManager().getSValBuilder();
409 if (CK == CharKind::Regular) {
425 if (Offset.isUnknown())
427 return Offset.castAs<
NonLoc>();
432 Os << Idx << llvm::getOrdinalSuffix(Idx);
437 AnyArgExpr Buffer,
SVal Element,
444 const MemRegion *R = Element.getAsRegion();
445 const auto *ER = dyn_cast_or_null<ElementRegion>(R);
455 if (!SuperR->getValueType()->isArrayType())
464 std::optional<Loc> FirstElementVal =
466 if (!FirstElementVal)
470 if (
Filter.CheckCStringUninitializedRead &&
471 State->getSVal(*FirstElementVal).isUndef()) {
473 llvm::raw_svector_ostream OS(Buf);
474 OS <<
"The first element of the ";
476 OS <<
" argument is undefined";
477 emitUninitializedReadBug(
C, State, Buffer.Expression, OS.str());
508 std::optional<NonLoc> Offset =
520 SVal LastElementVal =
522 if (!isa<Loc>(LastElementVal))
525 if (
Filter.CheckCStringUninitializedRead &&
526 State->getSVal(LastElementVal.
castAs<
Loc>()).isUndef()) {
527 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
535 llvm::raw_svector_ostream OS(Buf);
536 OS <<
"The last accessed element (at index ";
537 OS << IdxInt->getExtValue();
540 OS <<
" argument is undefined";
541 emitUninitializedReadBug(
C, State, Buffer.Expression, OS.str());
550 AnyArgExpr Buffer,
SVal Element,
559 const MemRegion *R = Element.getAsRegion();
563 const auto *ER = dyn_cast<ElementRegion>(R);
568 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
573 const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
577 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
578 if (StOutBound && !StInBound) {
582 if (!
Filter.CheckCStringOutOfBounds)
586 ErrorMessage Message =
587 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
588 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
599 AnyArgExpr Buffer, SizeArgExpr Size,
600 AccessKind Access, CharKind CK)
const {
609 QualType PtrTy = getCharPtrType(Ctx, CK);
612 SVal BufVal =
C.getSVal(Buffer.Expression);
613 State = checkNonNull(
C, State, Buffer, BufVal);
618 if (!
Filter.CheckCStringOutOfBounds)
622 svalBuilder.
evalCast(BufVal, PtrTy, Buffer.Expression->getType());
625 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
633 SVal LengthVal =
C.getSVal(
Size.Expression);
634 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
640 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
641 if (Offset.isUnknown())
646 if (std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>()) {
649 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
650 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
651 if (Access == AccessKind::read)
652 State = checkInit(
C, State, Buffer, BufEnd, *Length);
665 SizeArgExpr Size, AnyArgExpr
First,
668 if (!
Filter.CheckCStringBufferOverlap)
682 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
683 Second.Expression->getType()->getPointeeType().getAddressSpace())
688 SVal firstVal = state->getSVal(
First.Expression, LCtx);
689 SVal secondVal = state->getSVal(Second.Expression, LCtx);
691 std::optional<Loc> firstLoc = firstVal.
getAs<
Loc>();
695 std::optional<Loc> secondLoc = secondVal.
getAs<
Loc>();
701 std::tie(stateTrue, stateFalse) =
702 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
704 if (stateTrue && !stateFalse) {
706 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
717 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
718 std::optional<DefinedOrUnknownSVal> reverseTest =
723 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
730 std::swap(firstLoc, secondLoc);
733 std::swap(
First, Second);
738 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
739 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
746 QualType CharPtrTy = getCharPtrType(Ctx, CK);
748 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
749 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<
Loc>();
756 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<
Loc>();
762 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
763 std::optional<DefinedOrUnknownSVal> OverlapTest =
768 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
770 if (stateTrue && !stateFalse) {
772 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
788 BT_Overlap.reset(
new BugType(
Filter.CheckNameCStringBufferOverlap,
792 auto report = std::make_unique<PathSensitiveBugReport>(
793 *BT_Overlap,
"Arguments must not be overlapping buffers", N);
794 report->addRange(
First->getSourceRange());
797 C.emitReport(std::move(report));
801 const Stmt *S, StringRef WarningMsg)
const {
811 std::make_unique<PathSensitiveBugReport>(*BT_Null, WarningMsg, N);
812 Report->addRange(S->getSourceRange());
813 if (
const auto *Ex = dyn_cast<Expr>(S))
815 C.emitReport(std::move(Report));
822 StringRef Msg)
const {
825 BT_UninitRead.reset(
new BugType(
Filter.CheckNameCStringUninitializedRead,
826 "Accessing unitialized/garbage values"));
829 std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N);
830 Report->addNote(
"Other elements might also be undefined",
831 Report->getLocation());
834 C.emitReport(std::move(Report));
840 StringRef WarningMsg)
const {
844 ?
Filter.CheckNameCStringOutOfBounds
845 :
Filter.CheckNameCStringNullArg,
846 "Out-of-bound array access"));
852 std::make_unique<PathSensitiveBugReport>(*BT_Bounds, WarningMsg, N);
853 Report->addRange(S->getSourceRange());
854 C.emitReport(std::move(Report));
860 StringRef WarningMsg)
const {
862 if (!BT_NotCString) {
870 std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
872 Report->addRange(S->getSourceRange());
873 C.emitReport(std::move(Report));
880 if (!BT_AdditionOverflow) {
884 BT_AdditionOverflow.reset(
891 const char *WarningMsg =
892 "This expression will create a string whose length is too big to "
893 "be represented as a size_t";
895 auto Report = std::make_unique<PathSensitiveBugReport>(*BT_AdditionOverflow,
897 C.emitReport(std::move(Report));
906 if (!
Filter.CheckCStringOutOfBounds)
917 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
921 if (isa<nonloc::ConcreteInt>(right)) {
922 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
927 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
932 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<
NonLoc>()) {
936 *maxMinusRightNL, cmpTy);
939 std::tie(stateOverflow, stateOkay) =
942 if (stateOverflow && !stateOkay) {
944 emitAdditionOverflowBug(
C, stateOverflow);
959 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
964 case MemRegion::StringRegionKind:
969 case MemRegion::SymbolicRegionKind:
970 case MemRegion::AllocaRegionKind:
971 case MemRegion::NonParamVarRegionKind:
972 case MemRegion::ParamVarRegionKind:
973 case MemRegion::FieldRegionKind:
974 case MemRegion::ObjCIvarRegionKind:
978 case MemRegion::ElementRegionKind:
992 return state->remove<CStringLength>(MR);
994 return state->set<CStringLength>(MR, strLength);
1001 bool hypothetical) {
1002 if (!hypothetical) {
1004 const SVal *Recorded = state->get<CStringLength>(MR);
1014 C.getLocationContext(),
1017 if (!hypothetical) {
1018 if (std::optional<NonLoc> strLn = strLength.
getAs<
NonLoc>()) {
1021 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1023 const llvm::APSInt *maxLengthInt = BVF.
evalAPSInt(BO_Div, maxValInt,
1026 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1030 state = state->set<CStringLength>(MR, strLength);
1038 bool hypothetical)
const {
1045 if (
Filter.CheckCStringNotNullTerm) {
1047 llvm::raw_svector_ostream os(buf);
1048 assert(CurrentFunctionDescription);
1049 os <<
"Argument to " << CurrentFunctionDescription
1050 <<
" is the address of the label '" <<
Label->getLabel()->getName()
1051 <<
"', which is not a null-terminated string";
1053 emitNotCStringBug(
C, state, Ex, os.str());
1067 case MemRegion::StringRegionKind: {
1072 const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
1075 case MemRegion::NonParamVarRegionKind: {
1078 const VarDecl *
Decl = cast<NonParamVarRegion>(MR)->getDecl();
1079 if (
Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage()) {
1081 if (
auto *StrLit = dyn_cast<StringLiteral>(
Init)) {
1084 return SvalBuilder.
makeIntVal(StrLit->getLength(), SizeTy);
1090 case MemRegion::SymbolicRegionKind:
1091 case MemRegion::AllocaRegionKind:
1092 case MemRegion::ParamVarRegionKind:
1093 case MemRegion::FieldRegionKind:
1094 case MemRegion::ObjCIvarRegionKind:
1095 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1096 case MemRegion::CompoundLiteralRegionKind:
1099 case MemRegion::ElementRegionKind:
1107 if (
Filter.CheckCStringNotNullTerm) {
1109 llvm::raw_svector_ostream os(buf);
1111 assert(CurrentFunctionDescription);
1112 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1114 if (SummarizeRegion(os,
C.getASTContext(), MR))
1115 os <<
", which is not a null-terminated string";
1117 os <<
"not a null-terminated string";
1119 emitNotCStringBug(
C, state, Ex, os.str());
1137 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1161 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
1168 if (Offset.isUnknown())
1174 std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>();
1178 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1192 "isFirstBufInBound should only be called with char* ElementRegions");
1203 return static_cast<bool>(StInBound);
1209 auto InvalidationTraitOperations =
1210 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1214 if (MemRegion::FieldRegionKind == R->
getKind() &&
1215 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1223 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1227CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1231 return isa<FieldRegion>(R);
1234 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1237ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1239 auto InvalidationTraitOperations =
1241 if (MemRegion::FieldRegionKind == R->
getKind())
1248 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1255 auto InvalidationTraitOperations =
1265 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1272 InvalidationTraitOperations) {
1273 std::optional<Loc> L =
V.getAs<
Loc>();
1293 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1295 return State->invalidateRegions(R,
E,
C.blockCount(), LCtx,
1296 CausesPointerEscape,
nullptr,
nullptr,
1303 return State->killBinding(*L);
1306bool CStringChecker::SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
1309 case MemRegion::FunctionCodeRegionKind: {
1310 if (
const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
1311 os <<
"the address of the function '" << *FD <<
'\'';
1313 os <<
"the address of a function";
1316 case MemRegion::BlockCodeRegionKind:
1319 case MemRegion::BlockDataRegionKind:
1322 case MemRegion::CXXThisRegionKind:
1323 case MemRegion::CXXTempObjectRegionKind:
1324 os <<
"a C++ temp object of type "
1325 << cast<TypedValueRegion>(MR)->getValueType();
1327 case MemRegion::NonParamVarRegionKind:
1328 os <<
"a variable of type" << cast<TypedValueRegion>(MR)->getValueType();
1330 case MemRegion::ParamVarRegionKind:
1331 os <<
"a parameter of type" << cast<TypedValueRegion>(MR)->getValueType();
1333 case MemRegion::FieldRegionKind:
1334 os <<
"a field of type " << cast<TypedValueRegion>(MR)->getValueType();
1336 case MemRegion::ObjCIvarRegionKind:
1337 os <<
"an instance variable of type "
1338 << cast<TypedValueRegion>(MR)->getValueType();
1345bool CStringChecker::memsetAux(
const Expr *DstBuffer,
SVal CharVal,
1348 SVal MemVal =
C.getSVal(DstBuffer);
1349 SVal SizeVal =
C.getSVal(Size);
1359 const MemRegion *BR = Offset.getRegion();
1361 std::optional<NonLoc> SizeNL = SizeVal.
getAs<
NonLoc>();
1370 if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
1371 Offset.getOffset() == 0) {
1376 std::tie(StateWholeReg, StateNotWholeReg) =
1377 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1384 std::tie(StateNullChar, StateNonNullChar) =
1387 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1388 !StateNonNullChar) {
1395 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1396 C.getLocationContext());
1400 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, MemVal,
1401 SizeVal,
Size->getType());
1404 if (StateNullChar && !StateNonNullChar) {
1407 State = setCStringLength(State, MR,
1409 }
else if (!StateNullChar && StateNonNullChar) {
1411 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1412 C.getLocationContext(),
C.blockCount());
1419 State = setCStringLength(
1426 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, MemVal,
1427 SizeVal,
Size->getType());
1438 DestinationArgExpr Dest,
1439 SourceArgExpr Source,
bool Restricted,
1440 bool IsMempcpy, CharKind CK)
const {
1441 CurrentFunctionDescription =
"memory copy function";
1445 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1449 std::tie(stateZeroSize, stateNonZeroSize) =
1450 assumeZero(
C, state, sizeVal, sizeTy);
1453 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1457 if (stateZeroSize && !stateNonZeroSize) {
1459 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1460 C.addTransition(stateZeroSize);
1465 if (stateNonZeroSize) {
1469 state = stateNonZeroSize;
1473 state = checkNonNull(
C, state, Dest, destVal);
1478 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1482 state = checkNonNull(
C, state, Source, srcVal);
1487 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1488 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1491 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1502 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1503 SVal DestRegCharVal =
1504 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1505 SVal lastElement =
C.getSValBuilder().evalBinOp(
1506 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1510 lastElement =
C.getSValBuilder().conjureSymbolVal(
1511 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1514 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1518 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1527 state = invalidateDestinationBufferBySize(
1528 C, state, Dest.Expression,
C.getSVal(Dest.Expression), sizeVal,
1529 Size.Expression->getType());
1533 state = invalidateSourceBuffer(
C, state, Source.Expression,
1534 C.getSVal(Source.Expression));
1536 C.addTransition(state);
1541 CharKind CK)
const {
1544 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1545 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1546 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1550 constexpr bool IsRestricted =
true;
1551 constexpr bool IsMempcpy =
false;
1552 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1556 CharKind CK)
const {
1559 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1560 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1561 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1563 constexpr bool IsRestricted =
true;
1564 constexpr bool IsMempcpy =
true;
1565 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1570 CharKind CK)
const {
1573 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1574 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1575 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1577 constexpr bool IsRestricted =
false;
1578 constexpr bool IsMempcpy =
false;
1579 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1585 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1586 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1587 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1589 constexpr bool IsRestricted =
false;
1590 constexpr bool IsMempcpy =
false;
1591 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1592 IsMempcpy, CharKind::Regular);
1596 CharKind CK)
const {
1598 CurrentFunctionDescription =
"memory comparison function";
1600 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1601 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1602 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1609 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1613 std::tie(stateZeroSize, stateNonZeroSize) =
1614 assumeZero(
C, State, sizeVal, sizeTy);
1618 if (stateZeroSize) {
1619 State = stateZeroSize;
1620 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1621 Builder.makeZeroVal(
Call.getResultType()));
1622 C.addTransition(State);
1626 if (stateNonZeroSize) {
1627 State = stateNonZeroSize;
1638 std::tie(SameBuffer, NotSameBuffer) =
1639 State->assume(Builder.evalEQ(State, LV, RV));
1643 if (SameBuffer && !NotSameBuffer) {
1645 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1647 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1648 Builder.makeZeroVal(
Call.getResultType()));
1649 C.addTransition(State);
1656 assert(NotSameBuffer);
1657 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1658 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1661 SVal CmpV = Builder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(), LCtx,
1663 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1664 C.addTransition(State);
1672 evalstrLengthCommon(
C,
Call,
false);
1678 evalstrLengthCommon(
C,
Call,
true);
1683 bool IsStrnlen)
const {
1684 CurrentFunctionDescription =
"string length function";
1689 const Expr *maxlenExpr =
Call.getArgExpr(1);
1690 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1693 std::tie(stateZeroSize, stateNonZeroSize) =
1694 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1698 if (stateZeroSize) {
1699 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1700 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1701 C.addTransition(stateZeroSize);
1705 if (!stateNonZeroSize)
1709 state = stateNonZeroSize;
1713 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1714 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1715 state = checkNonNull(
C, state, Arg, ArgVal);
1720 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1732 QualType cmpTy =
C.getSValBuilder().getConditionType();
1736 const Expr *maxlenExpr =
Call.getArgExpr(1);
1737 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1739 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1740 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<
NonLoc>();
1742 if (strLengthNL && maxlenValNL) {
1746 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1748 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1751 if (stateStringTooLong && !stateStringNotTooLong) {
1753 result = *maxlenValNL;
1754 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1756 result = *strLengthNL;
1765 result =
C.getSValBuilder().conjureSymbolVal(
1766 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1770 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1771 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1776 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1777 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1789 result =
C.getSValBuilder().conjureSymbolVal(
1790 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1795 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1796 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1797 C.addTransition(state);
1803 evalStrcpyCommon(
C,
Call,
1806 ConcatFnKind::none);
1812 evalStrcpyCommon(
C,
Call,
1815 ConcatFnKind::none);
1821 evalStrcpyCommon(
C,
Call,
1824 ConcatFnKind::none);
1830 evalStrcpyCommon(
C,
Call,
1840 evalStrcpyCommon(
C,
Call,
1843 ConcatFnKind::strcat);
1849 evalStrcpyCommon(
C,
Call,
1852 ConcatFnKind::strcat);
1860 evalStrcpyCommon(
C,
Call,
1863 ConcatFnKind::strlcat,
1868 bool ReturnEnd,
bool IsBounded,
1869 ConcatFnKind appendK,
1870 bool returnPtr)
const {
1871 if (appendK == ConcatFnKind::none)
1872 CurrentFunctionDescription =
"string copy function";
1874 CurrentFunctionDescription =
"string concatenation function";
1880 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1881 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1882 state = checkNonNull(
C, state, Dst, DstVal);
1887 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1888 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1889 state = checkNonNull(
C, state, srcExpr, srcVal);
1894 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1895 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1898 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1899 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<
NonLoc>();
1914 const char *boundWarning =
nullptr;
1918 SizeArgExpr SrcExprAsSizeDummy = {
1919 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1920 state = CheckOverlap(
1922 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1931 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1932 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1936 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1938 std::optional<NonLoc> lenValNL = lenVal.
getAs<
NonLoc>();
1942 if (strLengthNL && lenValNL) {
1944 case ConcatFnKind::none:
1945 case ConcatFnKind::strcat: {
1950 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1952 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1953 .castAs<DefinedOrUnknownSVal>());
1955 if (stateSourceTooLong && !stateSourceNotTooLong) {
1958 state = stateSourceTooLong;
1959 amountCopied = lenVal;
1961 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1963 state = stateSourceNotTooLong;
1964 amountCopied = strLength;
1968 case ConcatFnKind::strlcat:
1969 if (!dstStrLengthNL)
1974 *dstStrLengthNL, sizeTy);
1975 if (!isa<NonLoc>(freeSpace))
1978 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1980 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<
NonLoc>();
1987 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1990 std::tie(TrueState, FalseState) =
1994 if (TrueState && !FalseState) {
1995 amountCopied = strLength;
1999 if (!TrueState && FalseState) {
2000 amountCopied = freeSpace;
2003 if (TrueState && FalseState)
2011 case ConcatFnKind::strcat:
2017 if (dstStrLength.isUndef())
2020 if (dstStrLengthNL) {
2022 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2024 boundWarning =
"Size argument is greater than the free space in the "
2025 "destination buffer";
2028 case ConcatFnKind::none:
2029 case ConcatFnKind::strlcat:
2039 std::tie(StateZeroSize, StateNonZeroSize) =
2040 assumeZero(
C, state, *lenValNL, sizeTy);
2043 if (StateZeroSize && !StateNonZeroSize) {
2046 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
2048 if (appendK == ConcatFnKind::none) {
2050 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
2055 state, BO_Add, strLength, dstStrLength, sizeTy);
2057 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
2060 C.addTransition(StateZeroSize);
2068 maxLastElementIndex =
2069 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2070 boundWarning =
"Size argument is greater than the length of the "
2071 "destination buffer";
2078 amountCopied = strLength;
2089 if (appendK == ConcatFnKind::none && !returnPtr) {
2091 strlRetVal = strLength;
2097 if (appendK != ConcatFnKind::none) {
2100 if (dstStrLength.isUndef())
2103 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2104 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2105 *dstStrLengthNL, sizeTy);
2108 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<
NonLoc>();
2111 if (amountCopiedNL && dstStrLengthNL) {
2113 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2117 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2118 *dstStrLengthNL, sizeTy);
2127 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2128 assert(!finalStrLength.
isUndef());
2130 if (std::optional<NonLoc> finalStrLengthNL =
2132 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2136 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2143 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2161 finalStrLength = amountCopied;
2169 Result = (ReturnEnd ?
UnknownVal() : DstVal);
2171 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2173 Result = strlRetVal;
2175 Result = finalStrLength;
2182 if (std::optional<loc::MemRegionVal> dstRegVal =
2184 QualType ptrTy = Dst.Expression->getType();
2188 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<
NonLoc>()) {
2189 SVal maxLastElement =
2190 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2193 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2197 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2203 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<
NonLoc>()) {
2205 *knownStrLength, ptrTy);
2208 if (!boundWarning) {
2210 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2214 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2220 if (returnPtr && ReturnEnd)
2221 Result = lastElement;
2231 state = invalidateDestinationBufferBySize(
C, state, Dst.Expression,
2232 *dstRegVal, amountCopied,
2233 C.getASTContext().getSizeType());
2237 state = invalidateSourceBuffer(
C, state, srcExpr.Expression, srcVal);
2240 if (IsBounded && (appendK == ConcatFnKind::none)) {
2245 if (amountCopied != strLength)
2248 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2256 if (ReturnEnd && Result.isUnknown()) {
2262 state = state->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2263 C.addTransition(state);
2269 evalStrcmpCommon(
C,
Call,
false,
false);
2275 evalStrcmpCommon(
C,
Call,
true,
false);
2281 evalStrcmpCommon(
C,
Call,
false,
true);
2287 evalStrcmpCommon(
C,
Call,
true,
true);
2291 bool IsBounded,
bool IgnoreCase)
const {
2292 CurrentFunctionDescription =
"string comparison function";
2297 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2298 SVal LeftVal = state->getSVal(
Left.Expression, LCtx);
2299 state = checkNonNull(
C, state, Left, LeftVal);
2304 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2305 SVal RightVal = state->getSVal(
Right.Expression, LCtx);
2306 state = checkNonNull(
C, state, Right, RightVal);
2311 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2316 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2330 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2336 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2337 svalBuilder.makeZeroVal(
Call.getResultType()));
2338 C.addTransition(StSameBuf);
2345 assert(StNotSameBuf);
2346 state = StNotSameBuf;
2353 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2355 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2356 bool canComputeResult =
false;
2357 SVal resultVal = svalBuilder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(),
2358 LCtx,
C.blockCount());
2360 if (LeftStrLiteral && RightStrLiteral) {
2361 StringRef LeftStrRef = LeftStrLiteral->
getString();
2362 StringRef RightStrRef = RightStrLiteral->
getString();
2366 const Expr *lenExpr =
Call.getArgExpr(2);
2367 SVal lenVal = state->getSVal(lenExpr, LCtx);
2370 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2372 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2373 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2374 canComputeResult =
true;
2378 canComputeResult =
true;
2381 if (canComputeResult) {
2383 size_t s1Term = LeftStrRef.find(
'\0');
2384 if (s1Term != StringRef::npos)
2385 LeftStrRef = LeftStrRef.substr(0, s1Term);
2387 size_t s2Term = RightStrRef.find(
'\0');
2388 if (s2Term != StringRef::npos)
2389 RightStrRef = RightStrRef.substr(0, s2Term);
2392 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2393 : LeftStrRef.compare(RightStrRef);
2397 if (compareRes == 0) {
2398 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2401 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2405 SVal compareWithZero =
2406 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2407 svalBuilder.getConditionType());
2409 state = state->assume(compareWithZeroVal,
true);
2414 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2417 C.addTransition(state);
2424 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2427 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2431 CurrentFunctionDescription =
"strsep()";
2437 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2438 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2443 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2444 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2445 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2451 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<
Loc>()) {
2453 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2458 State = invalidateDestinationBufferNeverOverflows(
2459 C, State, SearchStrPtr.Expression, Result);
2464 State->bindLoc(*SearchStrLoc,
2466 LCtx, CharPtrTy,
C.blockCount()),
2476 State = State->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2477 C.addTransition(State);
2483 evalStdCopyCommon(
C,
Call);
2488 evalStdCopyCommon(
C,
Call);
2493 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2506 const Expr *Dst =
Call.getArgExpr(2);
2507 SVal DstVal = State->getSVal(Dst, LCtx);
2511 invalidateDestinationBufferAlwaysEscapeSuperRegion(
C, State, Dst, DstVal);
2517 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2519 C.addTransition(State);
2525 CurrentFunctionDescription =
"memory set function";
2527 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2528 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2529 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2535 SVal SizeVal =
C.getSVal(
Size.Expression);
2539 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2542 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2546 if (ZeroSize && !NonZeroSize) {
2547 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2548 C.addTransition(ZeroSize);
2554 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2558 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2565 if (!memsetAux(Buffer.Expression,
C.getSVal(CharE.Expression),
2566 Size.Expression,
C, State))
2569 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2570 C.addTransition(State);
2574 CurrentFunctionDescription =
"memory clearance function";
2576 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2577 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2578 SVal Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2583 SVal SizeVal =
C.getSVal(
Size.Expression);
2587 std::tie(StateZeroSize, StateNonZeroSize) =
2588 assumeZero(
C, State, SizeVal, SizeTy);
2592 if (StateZeroSize && !StateNonZeroSize) {
2593 C.addTransition(StateZeroSize);
2598 SVal MemVal =
C.getSVal(Buffer.Expression);
2602 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2606 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2610 if (!memsetAux(Buffer.Expression, Zero,
Size.Expression,
C, State))
2613 C.addTransition(State);
2618 CurrentFunctionDescription =
"'sprintf'";
2619 evalSprintfCommon(
C,
Call,
false);
2624 CurrentFunctionDescription =
"'snprintf'";
2625 evalSprintfCommon(
C,
Call,
true);
2629 bool IsBounded)
const {
2631 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
2632 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2634 const auto NumParams =
Call.parameters().size();
2635 if (CE->getNumArgs() < NumParams) {
2640 const auto AllArguments =
2641 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2642 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2644 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2647 !
type->isAnyPointerType() ||
2648 !
type->getPointeeType()->isAnyCharacterType())
2650 SourceArgExpr Source = {{ArgExpr,
unsigned(ArgIdx)}};
2653 SizeArgExpr SrcExprAsSizeDummy = {
2654 {Source.Expression, Source.ArgumentIndex}};
2655 State = CheckOverlap(
2657 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2663 C.addTransition(State);
2670CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2672 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2680 if (StdCopy.matches(
Call))
2681 return &CStringChecker::evalStdCopy;
2682 if (StdCopyBackward.matches(
Call))
2683 return &CStringChecker::evalStdCopyBackward;
2689 for (
auto I : CE->arguments()) {
2695 const FnCheck *Callback = Callbacks.lookup(
Call);
2703 FnCheck Callback = identifyCall(
Call,
C);
2710 assert(isa<CallExpr>(
Call.getOriginExpr()));
2711 Callback(
this,
C,
Call);
2719 return C.isDifferent();
2726 for (
const auto *I : DS->
decls()) {
2727 const VarDecl *
D = dyn_cast<VarDecl>(I);
2732 if (!
D->getType()->isArrayType())
2738 if (!isa<StringLiteral>(
Init))
2741 Loc VarLoc = state->getLValue(
D,
C.getLocationContext());
2747 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2751 state = state->set<CStringLength>(MR, strLength);
2754 C.addTransition(state);
2764 CStringLengthTy Entries = state->get<CStringLength>();
2765 if (Entries.isEmpty())
2773 Invalidated.insert(MR);
2775 SuperRegions.insert(MR);
2776 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2777 MR = SR->getSuperRegion();
2778 SuperRegions.insert(MR);
2782 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2785 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2787 if (SuperRegions.count(MR)) {
2788 Entries = F.remove(Entries, MR);
2794 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2795 Super = SR->getSuperRegion();
2796 if (Invalidated.count(Super)) {
2797 Entries = F.remove(Entries, MR);
2803 return state->set<CStringLength>(Entries);
2809 CStringLengthTy Entries = state->get<CStringLength>();
2811 for (
SVal Len : llvm::make_second_range(Entries)) {
2820 CStringLengthTy Entries = state->get<CStringLength>();
2821 if (Entries.isEmpty())
2824 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2825 for (
auto [Reg, Len] : Entries) {
2826 if (
SymbolRef Sym = Len.getAsSymbol()) {
2828 Entries = F.remove(Entries, Reg);
2832 state = state->set<CStringLength>(Entries);
2833 C.addTransition(state);
2840bool ento::shouldRegisterCStringModeling(
const CheckerManager &mgr) {
2844#define REGISTER_CHECKER(name) \
2845 void ento::register##name(CheckerManager &mgr) { \
2846 CStringChecker *checker = mgr.getChecker<CStringChecker>(); \
2847 checker->Filter.Check##name = true; \
2848 checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \
2851 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
Defines enum values for all the target-independent builtin functions.
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.
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedCharTy
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 ...
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
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
const llvm::APSInt & getMaxValue(const llvm::APSInt &v)
const llvm::APSInt * 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 * registerChecker(AT &&... Args)
Used to register checkers.
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
ElementRegion is used to represent both array elements and casts.
QualType getValueType() const override
MemRegion - The root abstract class for all memory regions.
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
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.
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
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
bool Zero(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
const FunctionProtoType * T