26#include "llvm/ADT/STLExtras.h"
27#include "llvm/ADT/SmallString.h"
28#include "llvm/ADT/StringExtras.h"
29#include "llvm/Support/raw_ostream.h"
35using namespace std::placeholders;
40 unsigned ArgumentIndex;
42struct SourceArgExpr : AnyArgExpr {};
43struct DestinationArgExpr : AnyArgExpr {};
44struct SizeArgExpr : AnyArgExpr {};
47enum class AccessKind { write, read };
49static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
52 llvm::raw_svector_ostream Os(Message);
56 << &FunctionDescription.data()[1];
58 if (Access == AccessKind::write) {
59 Os <<
" overflows the destination buffer";
61 Os <<
" accesses out-of-bound array element";
67enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
69enum class CharKind { Regular = 0,
Wide };
70constexpr CharKind CK_Regular = CharKind::Regular;
71constexpr CharKind CK_Wide = CharKind::Wide;
78class CStringChecker :
public Checker< eval::Call,
79 check::PreStmt<DeclStmt>,
84 mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
85 BT_NotCString, BT_AdditionOverflow, BT_UninitRead;
87 mutable const char *CurrentFunctionDescription =
nullptr;
92 struct CStringChecksFilter {
93 bool CheckCStringNullArg =
false;
94 bool CheckCStringOutOfBounds =
false;
95 bool CheckCStringBufferOverlap =
false;
96 bool CheckCStringNotNullTerm =
false;
97 bool CheckCStringUninitializedRead =
false;
106 CStringChecksFilter
Filter;
108 static void *getTag() {
static int tag;
return &tag; }
123 using FnCheck = std::function<void(
const CStringChecker *,
CheckerContext &,
127 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
128 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
129 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
130 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
131 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
132 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
133 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
134 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
135 {{CDM::CLibrary, {
"memcmp"}, 3},
136 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
137 {{CDM::CLibrary, {
"wmemcmp"}, 3},
138 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
139 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
140 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
141 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
142 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
143 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
144 &CStringChecker::evalMemset},
145 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
147 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
148 &CStringChecker::evalStrcpy},
149 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
150 &CStringChecker::evalStrncpy},
151 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
152 &CStringChecker::evalStpcpy},
153 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
154 &CStringChecker::evalStrlcpy},
155 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
156 &CStringChecker::evalStrcat},
157 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
158 &CStringChecker::evalStrncat},
159 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
160 &CStringChecker::evalStrlcat},
161 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
162 &CStringChecker::evalstrLength},
163 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
164 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
165 &CStringChecker::evalstrnLength},
166 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
167 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
168 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
169 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
170 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
171 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
172 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
173 {{CDM::CLibrary, {
"bcmp"}, 3},
174 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
175 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
176 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
177 &CStringChecker::evalBzero},
185 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
186 &CStringChecker::evalSprintf},
187 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
188 &CStringChecker::evalSnprintf},
193 StdCopyBackward{{
"std",
"copy_backward"}, 3};
202 DestinationArgExpr Dest, SourceArgExpr Source,
203 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
210 bool IsStrnlen =
false)
const;
217 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
218 bool returnPtr =
true)
const;
229 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
242 bool IsBounded)
const;
245 std::pair<ProgramStateRef , ProgramStateRef >
261 bool hypothetical =
false)
const;
280 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
295 InvalidationTraitOperations);
297 static bool SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
300 static bool memsetAux(
const Expr *DstBuffer,
SVal CharE,
306 AnyArgExpr Arg,
SVal l)
const;
308 AnyArgExpr Buffer,
SVal Element,
310 CharKind CK = CharKind::Regular)
const;
312 AnyArgExpr Buffer, SizeArgExpr Size,
314 CharKind CK = CharKind::Regular)
const;
316 SizeArgExpr Size, AnyArgExpr
First,
318 CharKind CK = CharKind::Regular)
const;
322 const Stmt *Second)
const;
325 StringRef WarningMsg)
const;
327 const Stmt *S, StringRef WarningMsg)
const;
329 const Stmt *S, StringRef WarningMsg)
const;
332 const Expr *E)
const;
354std::pair<ProgramStateRef , ProgramStateRef >
357 std::optional<DefinedSVal> val =
V.getAs<
DefinedSVal>();
359 return std::pair<ProgramStateRef , ProgramStateRef >(state, state);
363 return state->assume(svalBuilder.
evalEQ(state, *val, zero));
368 AnyArgExpr Arg,
SVal l)
const {
374 std::tie(stateNull, stateNonNull) =
375 assumeZero(
C, State, l, Arg.Expression->getType());
377 if (stateNull && !stateNonNull) {
378 if (
Filter.CheckCStringNullArg) {
380 llvm::raw_svector_ostream OS(buf);
381 assert(CurrentFunctionDescription);
382 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
383 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
384 << CurrentFunctionDescription;
386 emitNullArgBug(
C, stateNull, Arg.Expression, OS.str());
392 assert(stateNonNull);
399 AnyArgExpr Buffer,
SVal Element,
408 const MemRegion *R = Element.getAsRegion();
412 const auto *ER = dyn_cast<ElementRegion>(R);
420 NonLoc Idx = ER->getIndex();
422 if (CK == CharKind::Regular) {
423 if (ER->getValueType() != Ctx.
CharTy)
435 SVal Offset = svalBuilder.
evalBinOpNN(state, BO_Mul, Idx, WideSize, SizeTy);
436 if (Offset.isUnknown())
438 Idx = Offset.castAs<
NonLoc>();
442 const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
447 std::tie(StInBound, StOutBound) = state->assumeInBoundDual(Idx, Size);
448 if (StOutBound && !StInBound) {
452 if (!
Filter.CheckCStringOutOfBounds)
456 ErrorMessage Message =
457 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
458 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
463 if (Access == AccessKind::read) {
464 if (
Filter.CheckCStringUninitializedRead &&
465 StInBound->getSVal(ER).isUndef()) {
466 emitUninitializedReadBug(
C, StInBound, Buffer.Expression);
478 AnyArgExpr Buffer, SizeArgExpr Size,
479 AccessKind Access, CharKind CK)
const {
488 QualType PtrTy = getCharPtrType(Ctx, CK);
491 SVal BufVal =
C.getSVal(Buffer.Expression);
492 State = checkNonNull(
C, State, Buffer, BufVal);
497 if (!
Filter.CheckCStringOutOfBounds)
501 svalBuilder.
evalCast(BufVal, PtrTy, Buffer.Expression->getType());
504 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
511 SVal LengthVal =
C.getSVal(
Size.Expression);
512 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
518 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
519 if (Offset.isUnknown())
524 if (std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>()) {
527 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
528 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
541 SizeArgExpr Size, AnyArgExpr
First,
544 if (!
Filter.CheckCStringBufferOverlap)
558 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
559 Second.Expression->getType()->getPointeeType().getAddressSpace())
564 SVal firstVal = state->getSVal(
First.Expression, LCtx);
565 SVal secondVal = state->getSVal(Second.Expression, LCtx);
567 std::optional<Loc> firstLoc = firstVal.
getAs<
Loc>();
571 std::optional<Loc> secondLoc = secondVal.
getAs<
Loc>();
577 std::tie(stateTrue, stateFalse) =
578 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
580 if (stateTrue && !stateFalse) {
582 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
593 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
594 std::optional<DefinedOrUnknownSVal> reverseTest =
599 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
606 std::swap(firstLoc, secondLoc);
609 std::swap(
First, Second);
614 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
615 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
622 QualType CharPtrTy = getCharPtrType(Ctx, CK);
624 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
625 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<
Loc>();
632 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<
Loc>();
638 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
639 std::optional<DefinedOrUnknownSVal> OverlapTest =
644 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
646 if (stateTrue && !stateFalse) {
648 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
664 BT_Overlap.reset(
new BugType(
Filter.CheckNameCStringBufferOverlap,
668 auto report = std::make_unique<PathSensitiveBugReport>(
669 *BT_Overlap,
"Arguments must not be overlapping buffers", N);
670 report->addRange(
First->getSourceRange());
673 C.emitReport(std::move(report));
677 const Stmt *S, StringRef WarningMsg)
const {
687 std::make_unique<PathSensitiveBugReport>(*BT_Null, WarningMsg, N);
688 Report->addRange(S->getSourceRange());
689 if (
const auto *Ex = dyn_cast<Expr>(S))
691 C.emitReport(std::move(Report));
697 const Expr *E)
const {
700 "Bytes string function accesses uninitialized/garbage values";
702 BT_UninitRead.reset(
new BugType(
Filter.CheckNameCStringUninitializedRead,
703 "Accessing unitialized/garbage values"));
706 std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N);
709 C.emitReport(std::move(Report));
715 StringRef WarningMsg)
const {
719 ?
Filter.CheckNameCStringOutOfBounds
720 :
Filter.CheckNameCStringNullArg,
721 "Out-of-bound array access"));
727 std::make_unique<PathSensitiveBugReport>(*BT_Bounds, WarningMsg, N);
728 Report->addRange(S->getSourceRange());
729 C.emitReport(std::move(Report));
735 StringRef WarningMsg)
const {
737 if (!BT_NotCString) {
745 std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
747 Report->addRange(S->getSourceRange());
748 C.emitReport(std::move(Report));
755 if (!BT_AdditionOverflow) {
759 BT_AdditionOverflow.reset(
766 const char *WarningMsg =
767 "This expression will create a string whose length is too big to "
768 "be represented as a size_t";
770 auto Report = std::make_unique<PathSensitiveBugReport>(*BT_AdditionOverflow,
772 C.emitReport(std::move(Report));
781 if (!
Filter.CheckCStringOutOfBounds)
792 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
796 if (isa<nonloc::ConcreteInt>(right)) {
797 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
802 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
807 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<
NonLoc>()) {
811 *maxMinusRightNL, cmpTy);
814 std::tie(stateOverflow, stateOkay) =
817 if (stateOverflow && !stateOkay) {
819 emitAdditionOverflowBug(
C, stateOverflow);
834 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
839 case MemRegion::StringRegionKind:
844 case MemRegion::SymbolicRegionKind:
845 case MemRegion::AllocaRegionKind:
846 case MemRegion::NonParamVarRegionKind:
847 case MemRegion::ParamVarRegionKind:
848 case MemRegion::FieldRegionKind:
849 case MemRegion::ObjCIvarRegionKind:
853 case MemRegion::ElementRegionKind:
867 return state->remove<CStringLength>(MR);
869 return state->set<CStringLength>(MR, strLength);
879 const SVal *Recorded = state->get<CStringLength>(MR);
889 C.getLocationContext(),
893 if (std::optional<NonLoc> strLn = strLength.
getAs<
NonLoc>()) {
896 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
898 const llvm::APSInt *maxLengthInt = BVF.
evalAPSInt(BO_Div, maxValInt,
901 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
905 state = state->set<CStringLength>(MR, strLength);
913 bool hypothetical)
const {
920 if (
Filter.CheckCStringNotNullTerm) {
922 llvm::raw_svector_ostream os(buf);
923 assert(CurrentFunctionDescription);
924 os <<
"Argument to " << CurrentFunctionDescription
925 <<
" is the address of the label '" <<
Label->getLabel()->getName()
926 <<
"', which is not a null-terminated string";
928 emitNotCStringBug(
C, state, Ex, os.str());
942 case MemRegion::StringRegionKind: {
947 const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
950 case MemRegion::NonParamVarRegionKind: {
953 const VarDecl *
Decl = cast<NonParamVarRegion>(MR)->getDecl();
954 if (
Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage()) {
956 if (
auto *StrLit = dyn_cast<StringLiteral>(
Init)) {
959 return SvalBuilder.
makeIntVal(StrLit->getLength(), SizeTy);
965 case MemRegion::SymbolicRegionKind:
966 case MemRegion::AllocaRegionKind:
967 case MemRegion::ParamVarRegionKind:
968 case MemRegion::FieldRegionKind:
969 case MemRegion::ObjCIvarRegionKind:
970 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
971 case MemRegion::CompoundLiteralRegionKind:
974 case MemRegion::ElementRegionKind:
982 if (
Filter.CheckCStringNotNullTerm) {
984 llvm::raw_svector_ostream os(buf);
986 assert(CurrentFunctionDescription);
987 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
989 if (SummarizeRegion(os,
C.getASTContext(), MR))
990 os <<
", which is not a null-terminated string";
992 os <<
"not a null-terminated string";
994 emitNotCStringBug(
C, state, Ex, os.str());
1012 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1036 std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
1043 if (Offset.isUnknown())
1049 std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>();
1053 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1067 "isFirstBufInBound should only be called with char* ElementRegions");
1078 return static_cast<bool>(StInBound);
1084 auto InvalidationTraitOperations =
1085 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1089 if (MemRegion::FieldRegionKind == R->
getKind() &&
1090 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1098 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1102CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1106 return isa<FieldRegion>(R);
1109 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1112ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1114 auto InvalidationTraitOperations =
1116 if (MemRegion::FieldRegionKind == R->
getKind())
1123 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1130 auto InvalidationTraitOperations =
1140 return invalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1147 InvalidationTraitOperations) {
1148 std::optional<Loc> L =
V.getAs<
Loc>();
1168 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1170 return State->invalidateRegions(R, E,
C.blockCount(), LCtx,
1171 CausesPointerEscape,
nullptr,
nullptr,
1178 return State->killBinding(*L);
1181bool CStringChecker::SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
1184 case MemRegion::FunctionCodeRegionKind: {
1185 if (
const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
1186 os <<
"the address of the function '" << *FD <<
'\'';
1188 os <<
"the address of a function";
1191 case MemRegion::BlockCodeRegionKind:
1194 case MemRegion::BlockDataRegionKind:
1197 case MemRegion::CXXThisRegionKind:
1198 case MemRegion::CXXTempObjectRegionKind:
1199 os <<
"a C++ temp object of type "
1200 << cast<TypedValueRegion>(MR)->getValueType();
1202 case MemRegion::NonParamVarRegionKind:
1203 os <<
"a variable of type" << cast<TypedValueRegion>(MR)->getValueType();
1205 case MemRegion::ParamVarRegionKind:
1206 os <<
"a parameter of type" << cast<TypedValueRegion>(MR)->getValueType();
1208 case MemRegion::FieldRegionKind:
1209 os <<
"a field of type " << cast<TypedValueRegion>(MR)->getValueType();
1211 case MemRegion::ObjCIvarRegionKind:
1212 os <<
"an instance variable of type "
1213 << cast<TypedValueRegion>(MR)->getValueType();
1220bool CStringChecker::memsetAux(
const Expr *DstBuffer,
SVal CharVal,
1223 SVal MemVal =
C.getSVal(DstBuffer);
1224 SVal SizeVal =
C.getSVal(Size);
1234 const MemRegion *BR = Offset.getRegion();
1236 std::optional<NonLoc> SizeNL = SizeVal.
getAs<
NonLoc>();
1245 if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
1246 Offset.getOffset() == 0) {
1251 std::tie(StateWholeReg, StateNotWholeReg) =
1252 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1259 std::tie(StateNullChar, StateNonNullChar) =
1262 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1263 !StateNonNullChar) {
1270 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1271 C.getLocationContext());
1275 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, MemVal,
1276 SizeVal,
Size->getType());
1279 if (StateNullChar && !StateNonNullChar) {
1282 State = setCStringLength(State, MR,
1284 }
else if (!StateNullChar && StateNonNullChar) {
1286 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1287 C.getLocationContext(),
C.blockCount());
1294 State = setCStringLength(
1301 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, MemVal,
1302 SizeVal,
Size->getType());
1313 DestinationArgExpr Dest,
1314 SourceArgExpr Source,
bool Restricted,
1315 bool IsMempcpy, CharKind CK)
const {
1316 CurrentFunctionDescription =
"memory copy function";
1320 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1324 std::tie(stateZeroSize, stateNonZeroSize) =
1325 assumeZero(
C, state, sizeVal, sizeTy);
1328 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1332 if (stateZeroSize && !stateNonZeroSize) {
1334 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1335 C.addTransition(stateZeroSize);
1340 if (stateNonZeroSize) {
1341 state = stateNonZeroSize;
1345 state = checkNonNull(
C, state, Dest, destVal);
1350 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1354 state = checkNonNull(
C, state, Source, srcVal);
1359 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1360 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1363 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1374 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1375 SVal DestRegCharVal =
1376 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1377 SVal lastElement =
C.getSValBuilder().evalBinOp(
1378 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1382 lastElement =
C.getSValBuilder().conjureSymbolVal(
1383 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1386 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1390 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1399 state = invalidateDestinationBufferBySize(
1400 C, state, Dest.Expression,
C.getSVal(Dest.Expression), sizeVal,
1401 Size.Expression->getType());
1405 state = invalidateSourceBuffer(
C, state, Source.Expression,
1406 C.getSVal(Source.Expression));
1408 C.addTransition(state);
1413 CharKind CK)
const {
1416 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1417 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1418 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1422 constexpr bool IsRestricted =
true;
1423 constexpr bool IsMempcpy =
false;
1424 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1428 CharKind CK)
const {
1431 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1432 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1433 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1435 constexpr bool IsRestricted =
true;
1436 constexpr bool IsMempcpy =
true;
1437 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1442 CharKind CK)
const {
1445 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1446 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1447 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1449 constexpr bool IsRestricted =
false;
1450 constexpr bool IsMempcpy =
false;
1451 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1457 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1458 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1459 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1461 constexpr bool IsRestricted =
false;
1462 constexpr bool IsMempcpy =
false;
1463 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1464 IsMempcpy, CharKind::Regular);
1468 CharKind CK)
const {
1470 CurrentFunctionDescription =
"memory comparison function";
1472 AnyArgExpr Left = {
Call.getArgExpr(0), 0};
1473 AnyArgExpr Right = {
Call.getArgExpr(1), 1};
1474 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1481 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1485 std::tie(stateZeroSize, stateNonZeroSize) =
1486 assumeZero(
C, State, sizeVal, sizeTy);
1490 if (stateZeroSize) {
1491 State = stateZeroSize;
1492 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1493 Builder.makeZeroVal(
Call.getResultType()));
1494 C.addTransition(State);
1498 if (stateNonZeroSize) {
1499 State = stateNonZeroSize;
1510 std::tie(SameBuffer, NotSameBuffer) =
1511 State->assume(Builder.evalEQ(State, LV, RV));
1515 if (SameBuffer && !NotSameBuffer) {
1517 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1519 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1520 Builder.makeZeroVal(
Call.getResultType()));
1521 C.addTransition(State);
1528 assert(NotSameBuffer);
1529 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1530 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1533 SVal CmpV = Builder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(), LCtx,
1535 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1536 C.addTransition(State);
1544 evalstrLengthCommon(
C,
Call,
false);
1550 evalstrLengthCommon(
C,
Call,
true);
1555 bool IsStrnlen)
const {
1556 CurrentFunctionDescription =
"string length function";
1561 const Expr *maxlenExpr =
Call.getArgExpr(1);
1562 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1565 std::tie(stateZeroSize, stateNonZeroSize) =
1566 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1570 if (stateZeroSize) {
1571 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1572 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1573 C.addTransition(stateZeroSize);
1577 if (!stateNonZeroSize)
1581 state = stateNonZeroSize;
1585 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1586 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1587 state = checkNonNull(
C, state, Arg, ArgVal);
1592 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1604 QualType cmpTy =
C.getSValBuilder().getConditionType();
1608 const Expr *maxlenExpr =
Call.getArgExpr(1);
1609 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1611 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1612 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<
NonLoc>();
1614 if (strLengthNL && maxlenValNL) {
1618 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1620 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1623 if (stateStringTooLong && !stateStringNotTooLong) {
1625 result = *maxlenValNL;
1626 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1628 result = *strLengthNL;
1637 result =
C.getSValBuilder().conjureSymbolVal(
1638 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1642 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1643 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1648 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1649 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1661 result =
C.getSValBuilder().conjureSymbolVal(
1662 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1667 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1668 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1669 C.addTransition(state);
1675 evalStrcpyCommon(
C,
Call,
1678 ConcatFnKind::none);
1684 evalStrcpyCommon(
C,
Call,
1687 ConcatFnKind::none);
1693 evalStrcpyCommon(
C,
Call,
1696 ConcatFnKind::none);
1702 evalStrcpyCommon(
C,
Call,
1712 evalStrcpyCommon(
C,
Call,
1715 ConcatFnKind::strcat);
1721 evalStrcpyCommon(
C,
Call,
1724 ConcatFnKind::strcat);
1732 evalStrcpyCommon(
C,
Call,
1735 ConcatFnKind::strlcat,
1740 bool ReturnEnd,
bool IsBounded,
1741 ConcatFnKind appendK,
1742 bool returnPtr)
const {
1743 if (appendK == ConcatFnKind::none)
1744 CurrentFunctionDescription =
"string copy function";
1746 CurrentFunctionDescription =
"string concatenation function";
1752 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1753 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1754 state = checkNonNull(
C, state, Dst, DstVal);
1759 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1760 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1761 state = checkNonNull(
C, state, srcExpr, srcVal);
1766 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1767 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1770 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1771 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<
NonLoc>();
1786 const char *boundWarning =
nullptr;
1790 SizeArgExpr SrcExprAsSizeDummy = {
1791 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1792 state = CheckOverlap(
1794 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1803 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1804 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1808 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1810 std::optional<NonLoc> lenValNL = lenVal.
getAs<
NonLoc>();
1814 if (strLengthNL && lenValNL) {
1816 case ConcatFnKind::none:
1817 case ConcatFnKind::strcat: {
1822 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1824 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1825 .castAs<DefinedOrUnknownSVal>());
1827 if (stateSourceTooLong && !stateSourceNotTooLong) {
1830 state = stateSourceTooLong;
1831 amountCopied = lenVal;
1833 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1835 state = stateSourceNotTooLong;
1836 amountCopied = strLength;
1840 case ConcatFnKind::strlcat:
1841 if (!dstStrLengthNL)
1846 *dstStrLengthNL, sizeTy);
1847 if (!isa<NonLoc>(freeSpace))
1850 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1852 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<
NonLoc>();
1859 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1862 std::tie(TrueState, FalseState) =
1866 if (TrueState && !FalseState) {
1867 amountCopied = strLength;
1871 if (!TrueState && FalseState) {
1872 amountCopied = freeSpace;
1875 if (TrueState && FalseState)
1883 case ConcatFnKind::strcat:
1889 if (dstStrLength.isUndef())
1892 if (dstStrLengthNL) {
1894 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1896 boundWarning =
"Size argument is greater than the free space in the "
1897 "destination buffer";
1900 case ConcatFnKind::none:
1901 case ConcatFnKind::strlcat:
1911 std::tie(StateZeroSize, StateNonZeroSize) =
1912 assumeZero(
C, state, *lenValNL, sizeTy);
1915 if (StateZeroSize && !StateNonZeroSize) {
1918 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
1920 if (appendK == ConcatFnKind::none) {
1922 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
1927 state, BO_Add, strLength, dstStrLength, sizeTy);
1929 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
1932 C.addTransition(StateZeroSize);
1940 maxLastElementIndex =
1941 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
1942 boundWarning =
"Size argument is greater than the length of the "
1943 "destination buffer";
1950 amountCopied = strLength;
1961 if (appendK == ConcatFnKind::none && !returnPtr) {
1963 strlRetVal = strLength;
1969 if (appendK != ConcatFnKind::none) {
1972 if (dstStrLength.isUndef())
1975 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
1976 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
1977 *dstStrLengthNL, sizeTy);
1980 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<
NonLoc>();
1983 if (amountCopiedNL && dstStrLengthNL) {
1985 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
1989 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
1990 *dstStrLengthNL, sizeTy);
1999 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2000 assert(!finalStrLength.
isUndef());
2002 if (std::optional<NonLoc> finalStrLengthNL =
2004 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2008 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2015 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2033 finalStrLength = amountCopied;
2041 Result = (ReturnEnd ?
UnknownVal() : DstVal);
2043 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2045 Result = strlRetVal;
2047 Result = finalStrLength;
2054 if (std::optional<loc::MemRegionVal> dstRegVal =
2056 QualType ptrTy = Dst.Expression->getType();
2060 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<
NonLoc>()) {
2061 SVal maxLastElement =
2062 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2065 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2069 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2075 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<
NonLoc>()) {
2077 *knownStrLength, ptrTy);
2080 if (!boundWarning) {
2082 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2086 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2092 if (returnPtr && ReturnEnd)
2093 Result = lastElement;
2103 state = invalidateDestinationBufferBySize(
C, state, Dst.Expression,
2104 *dstRegVal, amountCopied,
2105 C.getASTContext().getSizeType());
2109 state = invalidateSourceBuffer(
C, state, srcExpr.Expression, srcVal);
2112 if (IsBounded && (appendK == ConcatFnKind::none)) {
2117 if (amountCopied != strLength)
2120 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2128 if (ReturnEnd && Result.isUnknown()) {
2134 state = state->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2135 C.addTransition(state);
2141 evalStrcmpCommon(
C,
Call,
false,
false);
2147 evalStrcmpCommon(
C,
Call,
true,
false);
2153 evalStrcmpCommon(
C,
Call,
false,
true);
2159 evalStrcmpCommon(
C,
Call,
true,
true);
2163 bool IsBounded,
bool IgnoreCase)
const {
2164 CurrentFunctionDescription =
"string comparison function";
2169 AnyArgExpr Left = {
Call.getArgExpr(0), 0};
2170 SVal LeftVal = state->getSVal(Left.Expression, LCtx);
2171 state = checkNonNull(
C, state, Left, LeftVal);
2176 AnyArgExpr Right = {
Call.getArgExpr(1), 1};
2177 SVal RightVal = state->getSVal(Right.Expression, LCtx);
2178 state = checkNonNull(
C, state, Right, RightVal);
2183 SVal LeftLength = getCStringLength(
C, state, Left.Expression, LeftVal);
2188 SVal RightLength = getCStringLength(
C, state, Right.Expression, RightVal);
2202 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2208 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2209 svalBuilder.makeZeroVal(
Call.getResultType()));
2210 C.addTransition(StSameBuf);
2217 assert(StNotSameBuf);
2218 state = StNotSameBuf;
2225 getCStringLiteral(
C, state, Left.Expression, LeftVal);
2227 getCStringLiteral(
C, state, Right.Expression, RightVal);
2228 bool canComputeResult =
false;
2229 SVal resultVal = svalBuilder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(),
2230 LCtx,
C.blockCount());
2232 if (LeftStrLiteral && RightStrLiteral) {
2233 StringRef LeftStrRef = LeftStrLiteral->
getString();
2234 StringRef RightStrRef = RightStrLiteral->
getString();
2238 const Expr *lenExpr =
Call.getArgExpr(2);
2239 SVal lenVal = state->getSVal(lenExpr, LCtx);
2242 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2244 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2245 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2246 canComputeResult =
true;
2250 canComputeResult =
true;
2253 if (canComputeResult) {
2255 size_t s1Term = LeftStrRef.find(
'\0');
2256 if (s1Term != StringRef::npos)
2257 LeftStrRef = LeftStrRef.substr(0, s1Term);
2259 size_t s2Term = RightStrRef.find(
'\0');
2260 if (s2Term != StringRef::npos)
2261 RightStrRef = RightStrRef.substr(0, s2Term);
2264 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2265 : LeftStrRef.compare(RightStrRef);
2269 if (compareRes == 0) {
2270 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2273 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2277 SVal compareWithZero =
2278 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2279 svalBuilder.getConditionType());
2281 state = state->assume(compareWithZeroVal,
true);
2286 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2289 C.addTransition(state);
2296 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2299 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2303 CurrentFunctionDescription =
"strsep()";
2309 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2310 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2315 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2316 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2317 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2323 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<
Loc>()) {
2325 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2330 State = invalidateDestinationBufferNeverOverflows(
2331 C, State, SearchStrPtr.Expression, Result);
2336 State->bindLoc(*SearchStrLoc,
2338 LCtx, CharPtrTy,
C.blockCount()),
2348 State = State->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2349 C.addTransition(State);
2355 evalStdCopyCommon(
C,
Call);
2360 evalStdCopyCommon(
C,
Call);
2365 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2378 const Expr *Dst =
Call.getArgExpr(2);
2379 SVal DstVal = State->getSVal(Dst, LCtx);
2383 invalidateDestinationBufferAlwaysEscapeSuperRegion(
C, State, Dst, DstVal);
2389 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2391 C.addTransition(State);
2397 CurrentFunctionDescription =
"memory set function";
2399 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2400 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2401 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2407 SVal SizeVal =
C.getSVal(
Size.Expression);
2411 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2414 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2418 if (ZeroSize && !NonZeroSize) {
2419 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2420 C.addTransition(ZeroSize);
2426 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2430 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2437 if (!memsetAux(Buffer.Expression,
C.getSVal(CharE.Expression),
2438 Size.Expression,
C, State))
2441 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2442 C.addTransition(State);
2446 CurrentFunctionDescription =
"memory clearance function";
2448 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2449 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2450 SVal Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2455 SVal SizeVal =
C.getSVal(
Size.Expression);
2459 std::tie(StateZeroSize, StateNonZeroSize) =
2460 assumeZero(
C, State, SizeVal, SizeTy);
2464 if (StateZeroSize && !StateNonZeroSize) {
2465 C.addTransition(StateZeroSize);
2470 SVal MemVal =
C.getSVal(Buffer.Expression);
2474 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2478 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2482 if (!memsetAux(Buffer.Expression, Zero,
Size.Expression,
C, State))
2485 C.addTransition(State);
2490 CurrentFunctionDescription =
"'sprintf'";
2491 evalSprintfCommon(
C,
Call,
false);
2496 CurrentFunctionDescription =
"'snprintf'";
2497 evalSprintfCommon(
C,
Call,
true);
2501 bool IsBounded)
const {
2503 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
2504 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2506 const auto NumParams =
Call.parameters().size();
2507 if (CE->getNumArgs() < NumParams) {
2512 const auto AllArguments =
2513 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2514 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2516 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2519 !
type->isAnyPointerType() ||
2520 !
type->getPointeeType()->isAnyCharacterType())
2522 SourceArgExpr Source = {{ArgExpr,
unsigned(ArgIdx)}};
2525 SizeArgExpr SrcExprAsSizeDummy = {
2526 {Source.Expression, Source.ArgumentIndex}};
2527 State = CheckOverlap(
2529 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2535 C.addTransition(State);
2542CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2544 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2552 if (StdCopy.matches(
Call))
2553 return &CStringChecker::evalStdCopy;
2554 if (StdCopyBackward.matches(
Call))
2555 return &CStringChecker::evalStdCopyBackward;
2561 for (
auto I : CE->arguments()) {
2567 const FnCheck *Callback = Callbacks.lookup(
Call);
2575 FnCheck Callback = identifyCall(
Call,
C);
2582 assert(isa<CallExpr>(
Call.getOriginExpr()));
2583 Callback(
this,
C,
Call);
2591 return C.isDifferent();
2598 for (
const auto *I : DS->
decls()) {
2599 const VarDecl *D = dyn_cast<VarDecl>(I);
2610 if (!isa<StringLiteral>(
Init))
2613 Loc VarLoc = state->getLValue(D,
C.getLocationContext());
2619 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2623 state = state->set<CStringLength>(MR, strLength);
2626 C.addTransition(state);
2636 CStringLengthTy Entries = state->get<CStringLength>();
2637 if (Entries.isEmpty())
2645 Invalidated.insert(MR);
2647 SuperRegions.insert(MR);
2648 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2649 MR = SR->getSuperRegion();
2650 SuperRegions.insert(MR);
2654 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2657 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2659 if (SuperRegions.count(MR)) {
2660 Entries = F.remove(Entries, MR);
2666 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2667 Super = SR->getSuperRegion();
2668 if (Invalidated.count(Super)) {
2669 Entries = F.remove(Entries, MR);
2675 return state->set<CStringLength>(Entries);
2681 CStringLengthTy Entries = state->get<CStringLength>();
2683 for (
SVal Len : llvm::make_second_range(Entries)) {
2692 CStringLengthTy Entries = state->get<CStringLength>();
2693 if (Entries.isEmpty())
2696 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2697 for (
auto [Reg, Len] : Entries) {
2698 if (
SymbolRef Sym = Len.getAsSymbol()) {
2700 Entries = F.remove(Entries, Reg);
2704 state = state->set<CStringLength>(Entries);
2705 C.addTransition(state);
2712bool ento::shouldRegisterCStringModeling(
const CheckerManager &mgr) {
2716#define REGISTER_CHECKER(name) \
2717 void ento::register##name(CheckerManager &mgr) { \
2718 CStringChecker *checker = mgr.getChecker<CStringChecker>(); \
2719 checker->Filter.Check##name = true; \
2720 checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \
2723 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
Defines enum values for all the target-independent builtin functions.
#define REGISTER_CHECKER(name)
#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.
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.
const Expr * getInit() const
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)
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)
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.
__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)
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