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) {
1344 state = stateNonZeroSize;
1348 state = checkNonNull(
C, state, Dest, destVal);
1353 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1357 state = checkNonNull(
C, state, Source, srcVal);
1362 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1363 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1366 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1377 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1378 SVal DestRegCharVal =
1379 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1380 SVal lastElement =
C.getSValBuilder().evalBinOp(
1381 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1385 lastElement =
C.getSValBuilder().conjureSymbolVal(
1386 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1389 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1393 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1402 state = invalidateDestinationBufferBySize(
1403 C, state, Dest.Expression,
C.getSVal(Dest.Expression), sizeVal,
1404 Size.Expression->getType());
1408 state = invalidateSourceBuffer(
C, state, Source.Expression,
1409 C.getSVal(Source.Expression));
1411 C.addTransition(state);
1416 CharKind CK)
const {
1419 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1420 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1421 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1425 constexpr bool IsRestricted =
true;
1426 constexpr bool IsMempcpy =
false;
1427 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1431 CharKind CK)
const {
1434 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1435 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1436 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1438 constexpr bool IsRestricted =
true;
1439 constexpr bool IsMempcpy =
true;
1440 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1445 CharKind CK)
const {
1448 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1449 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1450 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1452 constexpr bool IsRestricted =
false;
1453 constexpr bool IsMempcpy =
false;
1454 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1460 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1461 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1462 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1464 constexpr bool IsRestricted =
false;
1465 constexpr bool IsMempcpy =
false;
1466 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1467 IsMempcpy, CharKind::Regular);
1471 CharKind CK)
const {
1473 CurrentFunctionDescription =
"memory comparison function";
1475 AnyArgExpr Left = {
Call.getArgExpr(0), 0};
1476 AnyArgExpr Right = {
Call.getArgExpr(1), 1};
1477 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1484 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1488 std::tie(stateZeroSize, stateNonZeroSize) =
1489 assumeZero(
C, State, sizeVal, sizeTy);
1493 if (stateZeroSize) {
1494 State = stateZeroSize;
1495 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1496 Builder.makeZeroVal(
Call.getResultType()));
1497 C.addTransition(State);
1501 if (stateNonZeroSize) {
1502 State = stateNonZeroSize;
1513 std::tie(SameBuffer, NotSameBuffer) =
1514 State->assume(Builder.evalEQ(State, LV, RV));
1518 if (SameBuffer && !NotSameBuffer) {
1520 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1522 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1523 Builder.makeZeroVal(
Call.getResultType()));
1524 C.addTransition(State);
1531 assert(NotSameBuffer);
1532 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1533 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1536 SVal CmpV = Builder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(), LCtx,
1538 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1539 C.addTransition(State);
1547 evalstrLengthCommon(
C,
Call,
false);
1553 evalstrLengthCommon(
C,
Call,
true);
1558 bool IsStrnlen)
const {
1559 CurrentFunctionDescription =
"string length function";
1564 const Expr *maxlenExpr =
Call.getArgExpr(1);
1565 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1568 std::tie(stateZeroSize, stateNonZeroSize) =
1569 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1573 if (stateZeroSize) {
1574 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1575 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1576 C.addTransition(stateZeroSize);
1580 if (!stateNonZeroSize)
1584 state = stateNonZeroSize;
1588 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1589 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1590 state = checkNonNull(
C, state, Arg, ArgVal);
1595 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1607 QualType cmpTy =
C.getSValBuilder().getConditionType();
1611 const Expr *maxlenExpr =
Call.getArgExpr(1);
1612 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1614 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1615 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<
NonLoc>();
1617 if (strLengthNL && maxlenValNL) {
1621 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1623 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1626 if (stateStringTooLong && !stateStringNotTooLong) {
1628 result = *maxlenValNL;
1629 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1631 result = *strLengthNL;
1640 result =
C.getSValBuilder().conjureSymbolVal(
1641 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1645 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1646 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1651 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1652 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1664 result =
C.getSValBuilder().conjureSymbolVal(
1665 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1670 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1671 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1672 C.addTransition(state);
1678 evalStrcpyCommon(
C,
Call,
1681 ConcatFnKind::none);
1687 evalStrcpyCommon(
C,
Call,
1690 ConcatFnKind::none);
1696 evalStrcpyCommon(
C,
Call,
1699 ConcatFnKind::none);
1705 evalStrcpyCommon(
C,
Call,
1715 evalStrcpyCommon(
C,
Call,
1718 ConcatFnKind::strcat);
1724 evalStrcpyCommon(
C,
Call,
1727 ConcatFnKind::strcat);
1735 evalStrcpyCommon(
C,
Call,
1738 ConcatFnKind::strlcat,
1743 bool ReturnEnd,
bool IsBounded,
1744 ConcatFnKind appendK,
1745 bool returnPtr)
const {
1746 if (appendK == ConcatFnKind::none)
1747 CurrentFunctionDescription =
"string copy function";
1749 CurrentFunctionDescription =
"string concatenation function";
1755 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1756 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1757 state = checkNonNull(
C, state, Dst, DstVal);
1762 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1763 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1764 state = checkNonNull(
C, state, srcExpr, srcVal);
1769 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1770 std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1773 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1774 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<
NonLoc>();
1789 const char *boundWarning =
nullptr;
1793 SizeArgExpr SrcExprAsSizeDummy = {
1794 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1795 state = CheckOverlap(
1797 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1806 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1807 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1811 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1813 std::optional<NonLoc> lenValNL = lenVal.
getAs<
NonLoc>();
1817 if (strLengthNL && lenValNL) {
1819 case ConcatFnKind::none:
1820 case ConcatFnKind::strcat: {
1825 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1827 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1828 .castAs<DefinedOrUnknownSVal>());
1830 if (stateSourceTooLong && !stateSourceNotTooLong) {
1833 state = stateSourceTooLong;
1834 amountCopied = lenVal;
1836 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1838 state = stateSourceNotTooLong;
1839 amountCopied = strLength;
1843 case ConcatFnKind::strlcat:
1844 if (!dstStrLengthNL)
1849 *dstStrLengthNL, sizeTy);
1850 if (!isa<NonLoc>(freeSpace))
1853 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1855 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<
NonLoc>();
1862 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1865 std::tie(TrueState, FalseState) =
1869 if (TrueState && !FalseState) {
1870 amountCopied = strLength;
1874 if (!TrueState && FalseState) {
1875 amountCopied = freeSpace;
1878 if (TrueState && FalseState)
1886 case ConcatFnKind::strcat:
1892 if (dstStrLength.isUndef())
1895 if (dstStrLengthNL) {
1897 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1899 boundWarning =
"Size argument is greater than the free space in the "
1900 "destination buffer";
1903 case ConcatFnKind::none:
1904 case ConcatFnKind::strlcat:
1914 std::tie(StateZeroSize, StateNonZeroSize) =
1915 assumeZero(
C, state, *lenValNL, sizeTy);
1918 if (StateZeroSize && !StateNonZeroSize) {
1921 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
1923 if (appendK == ConcatFnKind::none) {
1925 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
1930 state, BO_Add, strLength, dstStrLength, sizeTy);
1932 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
1935 C.addTransition(StateZeroSize);
1943 maxLastElementIndex =
1944 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
1945 boundWarning =
"Size argument is greater than the length of the "
1946 "destination buffer";
1953 amountCopied = strLength;
1964 if (appendK == ConcatFnKind::none && !returnPtr) {
1966 strlRetVal = strLength;
1972 if (appendK != ConcatFnKind::none) {
1975 if (dstStrLength.isUndef())
1978 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
1979 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
1980 *dstStrLengthNL, sizeTy);
1983 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<
NonLoc>();
1986 if (amountCopiedNL && dstStrLengthNL) {
1988 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
1992 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
1993 *dstStrLengthNL, sizeTy);
2002 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2003 assert(!finalStrLength.
isUndef());
2005 if (std::optional<NonLoc> finalStrLengthNL =
2007 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2011 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2018 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2036 finalStrLength = amountCopied;
2044 Result = (ReturnEnd ?
UnknownVal() : DstVal);
2046 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2048 Result = strlRetVal;
2050 Result = finalStrLength;
2057 if (std::optional<loc::MemRegionVal> dstRegVal =
2059 QualType ptrTy = Dst.Expression->getType();
2063 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<
NonLoc>()) {
2064 SVal maxLastElement =
2065 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2068 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2072 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2078 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<
NonLoc>()) {
2080 *knownStrLength, ptrTy);
2083 if (!boundWarning) {
2085 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2089 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2095 if (returnPtr && ReturnEnd)
2096 Result = lastElement;
2106 state = invalidateDestinationBufferBySize(
C, state, Dst.Expression,
2107 *dstRegVal, amountCopied,
2108 C.getASTContext().getSizeType());
2112 state = invalidateSourceBuffer(
C, state, srcExpr.Expression, srcVal);
2115 if (IsBounded && (appendK == ConcatFnKind::none)) {
2120 if (amountCopied != strLength)
2123 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2131 if (ReturnEnd && Result.isUnknown()) {
2137 state = state->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2138 C.addTransition(state);
2144 evalStrcmpCommon(
C,
Call,
false,
false);
2150 evalStrcmpCommon(
C,
Call,
true,
false);
2156 evalStrcmpCommon(
C,
Call,
false,
true);
2162 evalStrcmpCommon(
C,
Call,
true,
true);
2166 bool IsBounded,
bool IgnoreCase)
const {
2167 CurrentFunctionDescription =
"string comparison function";
2172 AnyArgExpr Left = {
Call.getArgExpr(0), 0};
2173 SVal LeftVal = state->getSVal(Left.Expression, LCtx);
2174 state = checkNonNull(
C, state, Left, LeftVal);
2179 AnyArgExpr Right = {
Call.getArgExpr(1), 1};
2180 SVal RightVal = state->getSVal(Right.Expression, LCtx);
2181 state = checkNonNull(
C, state, Right, RightVal);
2186 SVal LeftLength = getCStringLength(
C, state, Left.Expression, LeftVal);
2191 SVal RightLength = getCStringLength(
C, state, Right.Expression, RightVal);
2205 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2211 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2212 svalBuilder.makeZeroVal(
Call.getResultType()));
2213 C.addTransition(StSameBuf);
2220 assert(StNotSameBuf);
2221 state = StNotSameBuf;
2228 getCStringLiteral(
C, state, Left.Expression, LeftVal);
2230 getCStringLiteral(
C, state, Right.Expression, RightVal);
2231 bool canComputeResult =
false;
2232 SVal resultVal = svalBuilder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(),
2233 LCtx,
C.blockCount());
2235 if (LeftStrLiteral && RightStrLiteral) {
2236 StringRef LeftStrRef = LeftStrLiteral->
getString();
2237 StringRef RightStrRef = RightStrLiteral->
getString();
2241 const Expr *lenExpr =
Call.getArgExpr(2);
2242 SVal lenVal = state->getSVal(lenExpr, LCtx);
2245 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2247 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2248 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2249 canComputeResult =
true;
2253 canComputeResult =
true;
2256 if (canComputeResult) {
2258 size_t s1Term = LeftStrRef.find(
'\0');
2259 if (s1Term != StringRef::npos)
2260 LeftStrRef = LeftStrRef.substr(0, s1Term);
2262 size_t s2Term = RightStrRef.find(
'\0');
2263 if (s2Term != StringRef::npos)
2264 RightStrRef = RightStrRef.substr(0, s2Term);
2267 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2268 : LeftStrRef.compare(RightStrRef);
2272 if (compareRes == 0) {
2273 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2276 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2280 SVal compareWithZero =
2281 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2282 svalBuilder.getConditionType());
2284 state = state->assume(compareWithZeroVal,
true);
2289 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2292 C.addTransition(state);
2299 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2302 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2306 CurrentFunctionDescription =
"strsep()";
2312 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2313 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2318 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2319 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2320 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2326 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<
Loc>()) {
2328 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2333 State = invalidateDestinationBufferNeverOverflows(
2334 C, State, SearchStrPtr.Expression, Result);
2339 State->bindLoc(*SearchStrLoc,
2341 LCtx, CharPtrTy,
C.blockCount()),
2351 State = State->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2352 C.addTransition(State);
2358 evalStdCopyCommon(
C,
Call);
2363 evalStdCopyCommon(
C,
Call);
2368 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2381 const Expr *Dst =
Call.getArgExpr(2);
2382 SVal DstVal = State->getSVal(Dst, LCtx);
2386 invalidateDestinationBufferAlwaysEscapeSuperRegion(
C, State, Dst, DstVal);
2392 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2394 C.addTransition(State);
2400 CurrentFunctionDescription =
"memory set function";
2402 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2403 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2404 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2410 SVal SizeVal =
C.getSVal(
Size.Expression);
2414 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2417 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2421 if (ZeroSize && !NonZeroSize) {
2422 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2423 C.addTransition(ZeroSize);
2429 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2433 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2440 if (!memsetAux(Buffer.Expression,
C.getSVal(CharE.Expression),
2441 Size.Expression,
C, State))
2444 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2445 C.addTransition(State);
2449 CurrentFunctionDescription =
"memory clearance function";
2451 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2452 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2453 SVal Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2458 SVal SizeVal =
C.getSVal(
Size.Expression);
2462 std::tie(StateZeroSize, StateNonZeroSize) =
2463 assumeZero(
C, State, SizeVal, SizeTy);
2467 if (StateZeroSize && !StateNonZeroSize) {
2468 C.addTransition(StateZeroSize);
2473 SVal MemVal =
C.getSVal(Buffer.Expression);
2477 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2481 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2485 if (!memsetAux(Buffer.Expression, Zero,
Size.Expression,
C, State))
2488 C.addTransition(State);
2493 CurrentFunctionDescription =
"'sprintf'";
2494 evalSprintfCommon(
C,
Call,
false);
2499 CurrentFunctionDescription =
"'snprintf'";
2500 evalSprintfCommon(
C,
Call,
true);
2504 bool IsBounded)
const {
2506 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
2507 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2509 const auto NumParams =
Call.parameters().size();
2510 if (CE->getNumArgs() < NumParams) {
2515 const auto AllArguments =
2516 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2517 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2519 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2522 !
type->isAnyPointerType() ||
2523 !
type->getPointeeType()->isAnyCharacterType())
2525 SourceArgExpr Source = {{ArgExpr,
unsigned(ArgIdx)}};
2528 SizeArgExpr SrcExprAsSizeDummy = {
2529 {Source.Expression, Source.ArgumentIndex}};
2530 State = CheckOverlap(
2532 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2538 C.addTransition(State);
2545CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2547 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2555 if (StdCopy.matches(
Call))
2556 return &CStringChecker::evalStdCopy;
2557 if (StdCopyBackward.matches(
Call))
2558 return &CStringChecker::evalStdCopyBackward;
2564 for (
auto I : CE->arguments()) {
2570 const FnCheck *Callback = Callbacks.lookup(
Call);
2578 FnCheck Callback = identifyCall(
Call,
C);
2585 assert(isa<CallExpr>(
Call.getOriginExpr()));
2586 Callback(
this,
C,
Call);
2594 return C.isDifferent();
2601 for (
const auto *I : DS->
decls()) {
2602 const VarDecl *D = dyn_cast<VarDecl>(I);
2613 if (!isa<StringLiteral>(
Init))
2616 Loc VarLoc = state->getLValue(D,
C.getLocationContext());
2622 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2626 state = state->set<CStringLength>(MR, strLength);
2629 C.addTransition(state);
2639 CStringLengthTy Entries = state->get<CStringLength>();
2640 if (Entries.isEmpty())
2648 Invalidated.insert(MR);
2650 SuperRegions.insert(MR);
2651 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2652 MR = SR->getSuperRegion();
2653 SuperRegions.insert(MR);
2657 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2660 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2662 if (SuperRegions.count(MR)) {
2663 Entries = F.remove(Entries, MR);
2669 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2670 Super = SR->getSuperRegion();
2671 if (Invalidated.count(Super)) {
2672 Entries = F.remove(Entries, MR);
2678 return state->set<CStringLength>(Entries);
2684 CStringLengthTy Entries = state->get<CStringLength>();
2686 for (
SVal Len : llvm::make_second_range(Entries)) {
2695 CStringLengthTy Entries = state->get<CStringLength>();
2696 if (Entries.isEmpty())
2699 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2700 for (
auto [Reg, Len] : Entries) {
2701 if (
SymbolRef Sym = Len.getAsSymbol()) {
2703 Entries = F.remove(Entries, Reg);
2707 state = state->set<CStringLength>(Entries);
2708 C.addTransition(state);
2715bool ento::shouldRegisterCStringModeling(
const CheckerManager &mgr) {
2719#define REGISTER_CHECKER(name) \
2720 void ento::register##name(CheckerManager &mgr) { \
2721 CStringChecker *checker = mgr.getChecker<CStringChecker>(); \
2722 checker->Filter.Check##name = true; \
2723 checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \
2726 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