30#include "llvm/ADT/APSInt.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/StringExtras.h"
33#include "llvm/Support/Casting.h"
34#include "llvm/Support/raw_ostream.h"
40using namespace std::placeholders;
45 unsigned ArgumentIndex;
47struct SourceArgExpr : AnyArgExpr {};
48struct DestinationArgExpr : AnyArgExpr {};
49struct SizeArgExpr : AnyArgExpr {};
52enum class AccessKind { write, read };
54static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
57 llvm::raw_svector_ostream Os(Message);
61 << &FunctionDescription.data()[1];
63 if (Access == AccessKind::write) {
64 Os <<
" overflows the destination buffer";
66 Os <<
" accesses out-of-bound array element";
72enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
74enum class CharKind { Regular = 0,
Wide };
75constexpr CharKind CK_Regular = CharKind::Regular;
76constexpr CharKind CK_Wide = CharKind::Wide;
83class CStringChecker :
public Checker< eval::Call,
84 check::PreStmt<DeclStmt>,
89 mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
90 BT_NotCString, BT_AdditionOverflow, BT_UninitRead;
92 mutable const char *CurrentFunctionDescription =
nullptr;
97 struct CStringChecksFilter {
98 bool CheckCStringNullArg =
false;
99 bool CheckCStringOutOfBounds =
false;
100 bool CheckCStringBufferOverlap =
false;
101 bool CheckCStringNotNullTerm =
false;
102 bool CheckCStringUninitializedRead =
false;
111 CStringChecksFilter
Filter;
113 static void *getTag() {
static int tag;
return &tag; }
128 using FnCheck = std::function<void(
const CStringChecker *,
CheckerContext &,
132 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
133 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
134 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
135 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
136 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
137 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
138 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
139 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
140 {{CDM::CLibrary, {
"memcmp"}, 3},
141 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
142 {{CDM::CLibrary, {
"wmemcmp"}, 3},
143 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
144 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
145 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
146 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
147 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
148 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
149 &CStringChecker::evalMemset},
150 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
152 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
153 &CStringChecker::evalStrcpy},
154 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
155 &CStringChecker::evalStrncpy},
156 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
157 &CStringChecker::evalStpcpy},
158 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
159 &CStringChecker::evalStrlcpy},
160 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
161 &CStringChecker::evalStrcat},
162 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
163 &CStringChecker::evalStrncat},
164 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
165 &CStringChecker::evalStrlcat},
166 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
167 &CStringChecker::evalstrLength},
168 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
169 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
170 &CStringChecker::evalstrnLength},
171 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
172 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
173 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
174 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
175 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
176 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
177 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
178 {{CDM::CLibrary, {
"bcmp"}, 3},
179 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
180 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
181 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
182 &CStringChecker::evalBzero},
190 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
191 &CStringChecker::evalSprintf},
192 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
193 &CStringChecker::evalSnprintf},
198 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
207 DestinationArgExpr Dest, SourceArgExpr Source,
208 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
215 bool IsStrnlen =
false)
const;
222 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
223 bool returnPtr =
true)
const;
234 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
247 bool IsBounded)
const;
250 std::pair<ProgramStateRef , ProgramStateRef >
266 bool hypothetical =
false)
const;
285 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
300 InvalidationTraitOperations);
302 static bool SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
305 static bool memsetAux(
const Expr *DstBuffer,
SVal CharE,
311 AnyArgExpr Arg,
SVal l)
const;
315 AnyArgExpr Buffer,
SVal Element,
SVal Size)
const;
317 AnyArgExpr Buffer,
SVal Element,
319 CharKind CK = CharKind::Regular)
const;
321 AnyArgExpr Buffer, SizeArgExpr Size,
323 CharKind CK = CharKind::Regular)
const;
325 SizeArgExpr Size, AnyArgExpr
First,
327 CharKind CK = CharKind::Regular)
const;
331 const Stmt *Second)
const;
334 StringRef WarningMsg)
const;
336 const Stmt *S, StringRef WarningMsg)
const;
338 const Stmt *S, StringRef WarningMsg)
const;
342 StringRef Msg)
const;
364std::pair<ProgramStateRef, ProgramStateRef>
367 std::optional<DefinedSVal> val =
V.getAs<
DefinedSVal>();
369 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
373 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
378 AnyArgExpr Arg,
SVal l)
const {
384 std::tie(stateNull, stateNonNull) =
385 assumeZero(
C, State, l, Arg.Expression->getType());
387 if (stateNull && !stateNonNull) {
388 if (
Filter.CheckCStringNullArg) {
390 llvm::raw_svector_ostream OS(buf);
391 assert(CurrentFunctionDescription);
392 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
393 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
394 << CurrentFunctionDescription;
396 emitNullArgBug(
C, stateNull, Arg.Expression, OS.str());
402 assert(stateNonNull);
408 SValBuilder &SVB = State->getStateManager().getSValBuilder();
411 if (CK == CharKind::Regular) {
427 if (Offset.isUnknown())
429 return Offset.castAs<
NonLoc>();
434 Os << Idx << llvm::getOrdinalSuffix(Idx);
439 AnyArgExpr Buffer,
SVal Element,
446 const MemRegion *R = Element.getAsRegion();
447 const auto *ER = dyn_cast_or_null<ElementRegion>(R);
457 if (!SuperR->getValueType()->isArrayType())
466 std::optional<Loc> FirstElementVal =
468 if (!FirstElementVal)
472 if (
Filter.CheckCStringUninitializedRead &&
473 State->getSVal(*FirstElementVal).isUndef()) {
475 llvm::raw_svector_ostream OS(Buf);
476 OS <<
"The first element of the ";
478 OS <<
" argument is undefined";
479 emitUninitializedReadBug(
C, State, Buffer.Expression,
480 FirstElementVal->getAsRegion(), OS.str());
511 std::optional<NonLoc> Offset =
523 SVal LastElementVal =
525 if (!isa<Loc>(LastElementVal))
528 if (
Filter.CheckCStringUninitializedRead &&
529 State->getSVal(LastElementVal.
castAs<
Loc>()).isUndef()) {
530 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
538 llvm::raw_svector_ostream OS(Buf);
539 OS <<
"The last accessed element (at index ";
540 OS << IdxInt->getExtValue();
543 OS <<
" argument is undefined";
544 emitUninitializedReadBug(
C, State, Buffer.Expression,
554 AnyArgExpr Buffer,
SVal Element,
563 const MemRegion *R = Element.getAsRegion();
567 const auto *ER = dyn_cast<ElementRegion>(R);
572 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
577 const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
581 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
582 if (StOutBound && !StInBound) {
586 if (!
Filter.CheckCStringOutOfBounds)
590 ErrorMessage Message =
591 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
592 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
603 AnyArgExpr Buffer, SizeArgExpr Size,
604 AccessKind Access, CharKind CK)
const {
613 QualType PtrTy = getCharPtrType(Ctx, CK);
616 SVal BufVal =
C.getSVal(Buffer.Expression);
617 State = checkNonNull(
C, State, Buffer, BufVal);
622 if (!
Filter.CheckCStringOutOfBounds)
626 svalBuilder.
evalCast(BufVal, PtrTy, Buffer.Expression->getType());
629 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
637 SVal LengthVal =
C.getSVal(
Size.Expression);
638 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
644 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
645 if (Offset.isUnknown())
650 if (std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>()) {
653 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
654 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
655 if (Access == AccessKind::read)
656 State = checkInit(
C, State, Buffer, BufEnd, *Length);
669 SizeArgExpr Size, AnyArgExpr
First,
672 if (!
Filter.CheckCStringBufferOverlap)
686 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
687 Second.Expression->getType()->getPointeeType().getAddressSpace())
692 SVal firstVal = state->getSVal(
First.Expression, LCtx);
693 SVal secondVal = state->getSVal(Second.Expression, LCtx);
695 std::optional<Loc> firstLoc = firstVal.
getAs<
Loc>();
699 std::optional<Loc> secondLoc = secondVal.
getAs<
Loc>();
705 std::tie(stateTrue, stateFalse) =
706 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
708 if (stateTrue && !stateFalse) {
710 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
721 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
722 std::optional<DefinedOrUnknownSVal> reverseTest =
727 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
734 std::swap(firstLoc, secondLoc);
737 std::swap(
First, Second);
742 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
743 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
750 QualType CharPtrTy = getCharPtrType(Ctx, CK);
752 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
753 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<
Loc>();
760 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<
Loc>();
766 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
767 std::optional<DefinedOrUnknownSVal> OverlapTest =
772 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
774 if (stateTrue && !stateFalse) {
776 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
792 BT_Overlap.reset(
new BugType(
Filter.CheckNameCStringBufferOverlap,
796 auto report = std::make_unique<PathSensitiveBugReport>(
797 *BT_Overlap,
"Arguments must not be overlapping buffers", N);
798 report->addRange(
First->getSourceRange());
801 C.emitReport(std::move(report));
805 const Stmt *S, StringRef WarningMsg)
const {
815 std::make_unique<PathSensitiveBugReport>(*BT_Null, WarningMsg, N);
816 Report->addRange(S->getSourceRange());
817 if (
const auto *Ex = dyn_cast<Expr>(S))
819 C.emitReport(std::move(
Report));
826 StringRef Msg)
const {
829 BT_UninitRead.reset(
new BugType(
Filter.CheckNameCStringUninitializedRead,
830 "Accessing unitialized/garbage values"));
833 std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N);
834 Report->addNote(
"Other elements might also be undefined",
839 C.emitReport(std::move(
Report));
845 StringRef WarningMsg)
const {
849 ?
Filter.CheckNameCStringOutOfBounds
850 :
Filter.CheckNameCStringNullArg,
851 "Out-of-bound array access"));
857 std::make_unique<PathSensitiveBugReport>(*BT_Bounds, WarningMsg, N);
858 Report->addRange(S->getSourceRange());
859 C.emitReport(std::move(
Report));
865 StringRef WarningMsg)
const {
867 if (!BT_NotCString) {
875 std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
877 Report->addRange(S->getSourceRange());
878 C.emitReport(std::move(
Report));
885 if (!BT_AdditionOverflow) {
889 BT_AdditionOverflow.reset(
896 const char *WarningMsg =
897 "This expression will create a string whose length is too big to "
898 "be represented as a size_t";
900 auto Report = std::make_unique<PathSensitiveBugReport>(*BT_AdditionOverflow,
902 C.emitReport(std::move(
Report));
911 if (!
Filter.CheckCStringOutOfBounds)
922 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
926 if (isa<nonloc::ConcreteInt>(right)) {
927 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
932 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
937 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<
NonLoc>()) {
941 *maxMinusRightNL, cmpTy);
944 std::tie(stateOverflow, stateOkay) =
947 if (stateOverflow && !stateOkay) {
949 emitAdditionOverflowBug(
C, stateOverflow);
964 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
969 case MemRegion::StringRegionKind:
974 case MemRegion::SymbolicRegionKind:
975 case MemRegion::AllocaRegionKind:
976 case MemRegion::NonParamVarRegionKind:
977 case MemRegion::ParamVarRegionKind:
978 case MemRegion::FieldRegionKind:
979 case MemRegion::ObjCIvarRegionKind:
983 case MemRegion::ElementRegionKind:
997 return state->remove<CStringLength>(MR);
999 return state->set<CStringLength>(MR, strLength);
1006 bool hypothetical) {
1007 if (!hypothetical) {
1009 const SVal *Recorded = state->get<CStringLength>(MR);
1019 C.getLocationContext(),
1022 if (!hypothetical) {
1023 if (std::optional<NonLoc> strLn = strLength.
getAs<
NonLoc>()) {
1026 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1028 std::optional<APSIntPtr> maxLengthInt =
1031 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1035 state = state->set<CStringLength>(MR, strLength);
1043 bool hypothetical)
const {
1050 if (
Filter.CheckCStringNotNullTerm) {
1052 llvm::raw_svector_ostream os(buf);
1053 assert(CurrentFunctionDescription);
1054 os <<
"Argument to " << CurrentFunctionDescription
1055 <<
" is the address of the label '" <<
Label->getLabel()->getName()
1056 <<
"', which is not a null-terminated string";
1058 emitNotCStringBug(
C, state, Ex, os.str());
1072 case MemRegion::StringRegionKind: {
1077 const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
1080 case MemRegion::NonParamVarRegionKind: {
1083 const VarDecl *
Decl = cast<NonParamVarRegion>(MR)->getDecl();
1084 if (
Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage()) {
1086 if (
auto *StrLit = dyn_cast<StringLiteral>(
Init)) {
1089 return SvalBuilder.
makeIntVal(StrLit->getLength(), SizeTy);
1095 case MemRegion::SymbolicRegionKind:
1096 case MemRegion::AllocaRegionKind:
1097 case MemRegion::ParamVarRegionKind:
1098 case MemRegion::FieldRegionKind:
1099 case MemRegion::ObjCIvarRegionKind:
1100 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1101 case MemRegion::CompoundLiteralRegionKind:
1104 case MemRegion::ElementRegionKind:
1112 if (
Filter.CheckCStringNotNullTerm) {
1114 llvm::raw_svector_ostream os(buf);
1116 assert(CurrentFunctionDescription);
1117 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1119 if (SummarizeRegion(os,
C.getASTContext(), MR))
1120 os <<
", which is not a null-terminated string";
1122 os <<
"not a null-terminated string";
1124 emitNotCStringBug(
C, state, Ex, os.str());
1142 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1166 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
1173 if (Offset.isUnknown())
1179 std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>();
1183 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1197 "isFirstBufInBound should only be called with char* ElementRegions");
1208 return static_cast<bool>(StInBound);
1214 auto InvalidationTraitOperations =
1215 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1219 if (MemRegion::FieldRegionKind == R->
getKind() &&
1220 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1228 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1232CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1236 return isa<FieldRegion>(R);
1239 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1242ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1244 auto InvalidationTraitOperations =
1246 if (MemRegion::FieldRegionKind == R->
getKind())
1253 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1260 auto InvalidationTraitOperations =
1270 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1277 InvalidationTraitOperations) {
1278 std::optional<Loc> L =
V.getAs<
Loc>();
1298 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1300 return State->invalidateRegions(R,
E,
C.blockCount(), LCtx,
1301 CausesPointerEscape,
nullptr,
nullptr,
1308 return State->killBinding(*L);
1311bool CStringChecker::SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
1314 case MemRegion::FunctionCodeRegionKind: {
1315 if (
const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
1316 os <<
"the address of the function '" << *FD <<
'\'';
1318 os <<
"the address of a function";
1321 case MemRegion::BlockCodeRegionKind:
1324 case MemRegion::BlockDataRegionKind:
1327 case MemRegion::CXXThisRegionKind:
1328 case MemRegion::CXXTempObjectRegionKind:
1329 os <<
"a C++ temp object of type "
1330 << cast<TypedValueRegion>(MR)->getValueType();
1332 case MemRegion::NonParamVarRegionKind:
1333 os <<
"a variable of type" << cast<TypedValueRegion>(MR)->getValueType();
1335 case MemRegion::ParamVarRegionKind:
1336 os <<
"a parameter of type" << cast<TypedValueRegion>(MR)->getValueType();
1338 case MemRegion::FieldRegionKind:
1339 os <<
"a field of type " << cast<TypedValueRegion>(MR)->getValueType();
1341 case MemRegion::ObjCIvarRegionKind:
1342 os <<
"an instance variable of type "
1343 << cast<TypedValueRegion>(MR)->getValueType();
1350bool CStringChecker::memsetAux(
const Expr *DstBuffer,
SVal CharVal,
1353 SVal MemVal =
C.getSVal(DstBuffer);
1354 SVal SizeVal =
C.getSVal(Size);
1364 const MemRegion *BR = Offset.getRegion();
1366 std::optional<NonLoc> SizeNL = SizeVal.
getAs<
NonLoc>();
1375 if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
1376 Offset.getOffset() == 0) {
1381 std::tie(StateWholeReg, StateNotWholeReg) =
1382 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1389 std::tie(StateNullChar, StateNonNullChar) =
1392 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1393 !StateNonNullChar) {
1400 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1401 C.getLocationContext());
1405 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, MemVal,
1406 SizeVal,
Size->getType());
1409 if (StateNullChar && !StateNonNullChar) {
1412 State = setCStringLength(State, MR,
1414 }
else if (!StateNullChar && StateNonNullChar) {
1416 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1417 C.getLocationContext(),
C.blockCount());
1424 State = setCStringLength(
1431 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, MemVal,
1432 SizeVal,
Size->getType());
1443 DestinationArgExpr Dest,
1444 SourceArgExpr Source,
bool Restricted,
1445 bool IsMempcpy, CharKind CK)
const {
1446 CurrentFunctionDescription =
"memory copy function";
1450 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1454 std::tie(stateZeroSize, stateNonZeroSize) =
1455 assumeZero(
C, state, sizeVal, sizeTy);
1458 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1462 if (stateZeroSize && !stateNonZeroSize) {
1464 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1465 C.addTransition(stateZeroSize);
1470 if (stateNonZeroSize) {
1474 state = stateNonZeroSize;
1478 state = checkNonNull(
C, state, Dest, destVal);
1483 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1487 state = checkNonNull(
C, state, Source, srcVal);
1492 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1493 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1496 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1507 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1508 SVal DestRegCharVal =
1509 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1510 SVal lastElement =
C.getSValBuilder().evalBinOp(
1511 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1515 lastElement =
C.getSValBuilder().conjureSymbolVal(
1516 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1519 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1523 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1532 state = invalidateDestinationBufferBySize(
1533 C, state, Dest.Expression,
C.getSVal(Dest.Expression), sizeVal,
1534 Size.Expression->getType());
1538 state = invalidateSourceBuffer(
C, state, Source.Expression,
1539 C.getSVal(Source.Expression));
1541 C.addTransition(state);
1546 CharKind CK)
const {
1549 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1550 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1551 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1555 constexpr bool IsRestricted =
true;
1556 constexpr bool IsMempcpy =
false;
1557 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1561 CharKind CK)
const {
1564 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1565 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1566 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1568 constexpr bool IsRestricted =
true;
1569 constexpr bool IsMempcpy =
true;
1570 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1575 CharKind CK)
const {
1578 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1579 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1580 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1582 constexpr bool IsRestricted =
false;
1583 constexpr bool IsMempcpy =
false;
1584 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1590 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1591 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1592 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1594 constexpr bool IsRestricted =
false;
1595 constexpr bool IsMempcpy =
false;
1596 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1597 IsMempcpy, CharKind::Regular);
1601 CharKind CK)
const {
1603 CurrentFunctionDescription =
"memory comparison function";
1605 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1606 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1607 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1614 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1618 std::tie(stateZeroSize, stateNonZeroSize) =
1619 assumeZero(
C, State, sizeVal, sizeTy);
1623 if (stateZeroSize) {
1624 State = stateZeroSize;
1625 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1626 Builder.makeZeroVal(
Call.getResultType()));
1627 C.addTransition(State);
1631 if (stateNonZeroSize) {
1632 State = stateNonZeroSize;
1643 std::tie(SameBuffer, NotSameBuffer) =
1644 State->assume(Builder.evalEQ(State, LV, RV));
1648 if (SameBuffer && !NotSameBuffer) {
1650 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1652 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1653 Builder.makeZeroVal(
Call.getResultType()));
1654 C.addTransition(State);
1661 assert(NotSameBuffer);
1662 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1663 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1666 SVal CmpV = Builder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(), LCtx,
1668 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1669 C.addTransition(State);
1677 evalstrLengthCommon(
C,
Call,
false);
1683 evalstrLengthCommon(
C,
Call,
true);
1688 bool IsStrnlen)
const {
1689 CurrentFunctionDescription =
"string length function";
1694 const Expr *maxlenExpr =
Call.getArgExpr(1);
1695 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1698 std::tie(stateZeroSize, stateNonZeroSize) =
1699 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1703 if (stateZeroSize) {
1704 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1705 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1706 C.addTransition(stateZeroSize);
1710 if (!stateNonZeroSize)
1714 state = stateNonZeroSize;
1718 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1719 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1720 state = checkNonNull(
C, state, Arg, ArgVal);
1725 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1737 QualType cmpTy =
C.getSValBuilder().getConditionType();
1741 const Expr *maxlenExpr =
Call.getArgExpr(1);
1742 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1744 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1745 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<
NonLoc>();
1747 if (strLengthNL && maxlenValNL) {
1751 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1753 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1756 if (stateStringTooLong && !stateStringNotTooLong) {
1758 result = *maxlenValNL;
1759 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1761 result = *strLengthNL;
1770 result =
C.getSValBuilder().conjureSymbolVal(
1771 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1775 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1776 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1781 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1782 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1794 result =
C.getSValBuilder().conjureSymbolVal(
1795 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1800 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1801 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1802 C.addTransition(state);
1808 evalStrcpyCommon(
C,
Call,
1811 ConcatFnKind::none);
1817 evalStrcpyCommon(
C,
Call,
1820 ConcatFnKind::none);
1826 evalStrcpyCommon(
C,
Call,
1829 ConcatFnKind::none);
1835 evalStrcpyCommon(
C,
Call,
1845 evalStrcpyCommon(
C,
Call,
1848 ConcatFnKind::strcat);
1854 evalStrcpyCommon(
C,
Call,
1857 ConcatFnKind::strcat);
1865 evalStrcpyCommon(
C,
Call,
1868 ConcatFnKind::strlcat,
1873 bool ReturnEnd,
bool IsBounded,
1874 ConcatFnKind appendK,
1875 bool returnPtr)
const {
1876 if (appendK == ConcatFnKind::none)
1877 CurrentFunctionDescription =
"string copy function";
1879 CurrentFunctionDescription =
"string concatenation function";
1885 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1886 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1887 state = checkNonNull(
C, state, Dst, DstVal);
1892 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1893 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1894 state = checkNonNull(
C, state, srcExpr, srcVal);
1899 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1900 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1903 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1904 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<
NonLoc>();
1919 const char *boundWarning =
nullptr;
1923 SizeArgExpr SrcExprAsSizeDummy = {
1924 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1925 state = CheckOverlap(
1927 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1936 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1937 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1941 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1943 std::optional<NonLoc> lenValNL = lenVal.
getAs<
NonLoc>();
1947 if (strLengthNL && lenValNL) {
1949 case ConcatFnKind::none:
1950 case ConcatFnKind::strcat: {
1955 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1957 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1958 .castAs<DefinedOrUnknownSVal>());
1960 if (stateSourceTooLong && !stateSourceNotTooLong) {
1963 state = stateSourceTooLong;
1964 amountCopied = lenVal;
1966 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1968 state = stateSourceNotTooLong;
1969 amountCopied = strLength;
1973 case ConcatFnKind::strlcat:
1974 if (!dstStrLengthNL)
1979 *dstStrLengthNL, sizeTy);
1980 if (!isa<NonLoc>(freeSpace))
1983 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1985 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<
NonLoc>();
1992 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1995 std::tie(TrueState, FalseState) =
1999 if (TrueState && !FalseState) {
2000 amountCopied = strLength;
2004 if (!TrueState && FalseState) {
2005 amountCopied = freeSpace;
2008 if (TrueState && FalseState)
2016 case ConcatFnKind::strcat:
2022 if (dstStrLength.isUndef())
2025 if (dstStrLengthNL) {
2027 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2029 boundWarning =
"Size argument is greater than the free space in the "
2030 "destination buffer";
2033 case ConcatFnKind::none:
2034 case ConcatFnKind::strlcat:
2044 std::tie(StateZeroSize, StateNonZeroSize) =
2045 assumeZero(
C, state, *lenValNL, sizeTy);
2048 if (StateZeroSize && !StateNonZeroSize) {
2051 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
2053 if (appendK == ConcatFnKind::none) {
2055 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
2060 state, BO_Add, strLength, dstStrLength, sizeTy);
2062 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
2065 C.addTransition(StateZeroSize);
2073 maxLastElementIndex =
2074 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2075 boundWarning =
"Size argument is greater than the length of the "
2076 "destination buffer";
2083 amountCopied = strLength;
2094 if (appendK == ConcatFnKind::none && !returnPtr) {
2096 strlRetVal = strLength;
2102 if (appendK != ConcatFnKind::none) {
2105 if (dstStrLength.isUndef())
2108 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2109 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2110 *dstStrLengthNL, sizeTy);
2113 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<
NonLoc>();
2116 if (amountCopiedNL && dstStrLengthNL) {
2118 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2122 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2123 *dstStrLengthNL, sizeTy);
2132 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2133 assert(!finalStrLength.
isUndef());
2135 if (std::optional<NonLoc> finalStrLengthNL =
2137 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2141 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2148 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2166 finalStrLength = amountCopied;
2174 Result = (ReturnEnd ?
UnknownVal() : DstVal);
2176 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2178 Result = strlRetVal;
2180 Result = finalStrLength;
2187 if (std::optional<loc::MemRegionVal> dstRegVal =
2189 QualType ptrTy = Dst.Expression->getType();
2193 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<
NonLoc>()) {
2194 SVal maxLastElement =
2195 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2198 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2202 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2208 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<
NonLoc>()) {
2210 *knownStrLength, ptrTy);
2213 if (!boundWarning) {
2215 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2219 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2225 if (returnPtr && ReturnEnd)
2226 Result = lastElement;
2236 state = invalidateDestinationBufferBySize(
C, state, Dst.Expression,
2237 *dstRegVal, amountCopied,
2238 C.getASTContext().getSizeType());
2242 state = invalidateSourceBuffer(
C, state, srcExpr.Expression, srcVal);
2245 if (IsBounded && (appendK == ConcatFnKind::none)) {
2250 if (amountCopied != strLength)
2253 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2261 if (ReturnEnd && Result.isUnknown()) {
2267 state = state->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2268 C.addTransition(state);
2274 evalStrcmpCommon(
C,
Call,
false,
false);
2280 evalStrcmpCommon(
C,
Call,
true,
false);
2286 evalStrcmpCommon(
C,
Call,
false,
true);
2292 evalStrcmpCommon(
C,
Call,
true,
true);
2296 bool IsBounded,
bool IgnoreCase)
const {
2297 CurrentFunctionDescription =
"string comparison function";
2302 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2303 SVal LeftVal = state->getSVal(
Left.Expression, LCtx);
2304 state = checkNonNull(
C, state, Left, LeftVal);
2309 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2310 SVal RightVal = state->getSVal(
Right.Expression, LCtx);
2311 state = checkNonNull(
C, state, Right, RightVal);
2316 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2321 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2335 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2341 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2342 svalBuilder.makeZeroVal(
Call.getResultType()));
2343 C.addTransition(StSameBuf);
2350 assert(StNotSameBuf);
2351 state = StNotSameBuf;
2358 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2360 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2361 bool canComputeResult =
false;
2362 SVal resultVal = svalBuilder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(),
2363 LCtx,
C.blockCount());
2365 if (LeftStrLiteral && RightStrLiteral) {
2366 StringRef LeftStrRef = LeftStrLiteral->
getString();
2367 StringRef RightStrRef = RightStrLiteral->
getString();
2371 const Expr *lenExpr =
Call.getArgExpr(2);
2372 SVal lenVal = state->getSVal(lenExpr, LCtx);
2375 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2377 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2378 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2379 canComputeResult =
true;
2383 canComputeResult =
true;
2386 if (canComputeResult) {
2388 size_t s1Term = LeftStrRef.find(
'\0');
2389 if (s1Term != StringRef::npos)
2390 LeftStrRef = LeftStrRef.substr(0, s1Term);
2392 size_t s2Term = RightStrRef.find(
'\0');
2393 if (s2Term != StringRef::npos)
2394 RightStrRef = RightStrRef.substr(0, s2Term);
2397 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2398 : LeftStrRef.compare(RightStrRef);
2402 if (compareRes == 0) {
2403 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2406 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2410 SVal compareWithZero =
2411 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2412 svalBuilder.getConditionType());
2414 state = state->assume(compareWithZeroVal,
true);
2419 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2422 C.addTransition(state);
2429 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2432 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2436 CurrentFunctionDescription =
"strsep()";
2442 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2443 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2448 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2449 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2450 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2456 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<
Loc>()) {
2458 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2463 State = invalidateDestinationBufferNeverOverflows(
2464 C, State, SearchStrPtr.Expression, Result);
2469 State->bindLoc(*SearchStrLoc,
2471 LCtx, CharPtrTy,
C.blockCount()),
2481 State = State->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2482 C.addTransition(State);
2488 evalStdCopyCommon(
C,
Call);
2493 evalStdCopyCommon(
C,
Call);
2498 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2511 const Expr *Dst =
Call.getArgExpr(2);
2512 SVal DstVal = State->getSVal(Dst, LCtx);
2516 invalidateDestinationBufferAlwaysEscapeSuperRegion(
C, State, Dst, DstVal);
2522 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2524 C.addTransition(State);
2530 CurrentFunctionDescription =
"memory set function";
2532 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2533 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2534 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2540 SVal SizeVal =
C.getSVal(
Size.Expression);
2544 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2547 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2551 if (ZeroSize && !NonZeroSize) {
2552 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2553 C.addTransition(ZeroSize);
2559 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2563 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2570 if (!memsetAux(Buffer.Expression,
C.getSVal(CharE.Expression),
2571 Size.Expression,
C, State))
2574 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2575 C.addTransition(State);
2579 CurrentFunctionDescription =
"memory clearance function";
2581 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2582 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2583 SVal Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2588 SVal SizeVal =
C.getSVal(
Size.Expression);
2592 std::tie(StateZeroSize, StateNonZeroSize) =
2593 assumeZero(
C, State, SizeVal, SizeTy);
2597 if (StateZeroSize && !StateNonZeroSize) {
2598 C.addTransition(StateZeroSize);
2603 SVal MemVal =
C.getSVal(Buffer.Expression);
2607 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2611 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2615 if (!memsetAux(Buffer.Expression, Zero,
Size.Expression,
C, State))
2618 C.addTransition(State);
2623 CurrentFunctionDescription =
"'sprintf'";
2624 evalSprintfCommon(
C,
Call,
false);
2629 CurrentFunctionDescription =
"'snprintf'";
2630 evalSprintfCommon(
C,
Call,
true);
2634 bool IsBounded)
const {
2636 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
2637 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2639 const auto NumParams =
Call.parameters().size();
2640 if (CE->getNumArgs() < NumParams) {
2645 const auto AllArguments =
2646 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2647 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2649 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2652 !
type->isAnyPointerType() ||
2653 !
type->getPointeeType()->isAnyCharacterType())
2655 SourceArgExpr Source = {{ArgExpr,
unsigned(ArgIdx)}};
2658 SizeArgExpr SrcExprAsSizeDummy = {
2659 {Source.Expression, Source.ArgumentIndex}};
2660 State = CheckOverlap(
2662 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2668 C.addTransition(State);
2675CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2677 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2685 if (StdCopy.matches(
Call))
2686 return &CStringChecker::evalStdCopy;
2687 if (StdCopyBackward.matches(
Call))
2688 return &CStringChecker::evalStdCopyBackward;
2694 for (
auto I : CE->arguments()) {
2700 const FnCheck *Callback = Callbacks.lookup(
Call);
2708 FnCheck Callback = identifyCall(
Call,
C);
2715 assert(isa<CallExpr>(
Call.getOriginExpr()));
2716 Callback(
this,
C,
Call);
2724 return C.isDifferent();
2731 for (
const auto *I : DS->
decls()) {
2732 const VarDecl *
D = dyn_cast<VarDecl>(I);
2737 if (!
D->getType()->isArrayType())
2743 if (!isa<StringLiteral>(
Init))
2746 Loc VarLoc = state->getLValue(
D,
C.getLocationContext());
2752 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2756 state = state->set<CStringLength>(MR, strLength);
2759 C.addTransition(state);
2769 CStringLengthTy Entries = state->get<CStringLength>();
2770 if (Entries.isEmpty())
2778 Invalidated.insert(MR);
2780 SuperRegions.insert(MR);
2781 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2782 MR = SR->getSuperRegion();
2783 SuperRegions.insert(MR);
2787 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2790 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2792 if (SuperRegions.count(MR)) {
2793 Entries = F.remove(Entries, MR);
2799 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2800 Super = SR->getSuperRegion();
2801 if (Invalidated.count(Super)) {
2802 Entries = F.remove(Entries, MR);
2808 return state->set<CStringLength>(Entries);
2814 CStringLengthTy Entries = state->get<CStringLength>();
2816 for (
SVal Len : llvm::make_second_range(Entries)) {
2825 CStringLengthTy Entries = state->get<CStringLength>();
2826 if (Entries.isEmpty())
2829 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2830 for (
auto [Reg, Len] : Entries) {
2831 if (
SymbolRef Sym = Len.getAsSymbol()) {
2833 Entries = F.remove(Entries, Reg);
2837 state = state->set<CStringLength>(Entries);
2838 C.addTransition(state);
2845bool ento::shouldRegisterCStringModeling(
const CheckerManager &mgr) {
2849#define REGISTER_CHECKER(name) \
2850 void ento::register##name(CheckerManager &mgr) { \
2851 CStringChecker *checker = mgr.getChecker<CStringChecker>(); \
2852 checker->Filter.Check##name = true; \
2853 checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \
2856 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
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 * 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.
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.
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