29#include "llvm/ADT/APSInt.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/STLForwardCompat.h"
32#include "llvm/ADT/StringExtras.h"
33#include "llvm/Support/raw_ostream.h"
39using namespace std::placeholders;
43 const Expr *Expression;
44 unsigned ArgumentIndex;
46struct SourceArgExpr : AnyArgExpr {};
47struct DestinationArgExpr : AnyArgExpr {};
48struct SizeArgExpr : AnyArgExpr {};
51enum class AccessKind { write, read };
53static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
56 llvm::raw_svector_ostream Os(Message);
60 << &FunctionDescription.data()[1];
62 if (Access == AccessKind::write) {
63 Os <<
" overflows the destination buffer";
65 Os <<
" accesses out-of-bound array element";
71enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
73enum class CharKind { Regular = 0,
Wide };
74constexpr CharKind CK_Regular = CharKind::Regular;
75constexpr CharKind CK_Wide = CharKind::Wide;
84 check::LiveSymbols, check::DeadSymbols,
85 check::RegionChanges> {
86 mutable StringRef CurrentFunctionDescription;
94 CheckerFrontendWithBugType OutOfBounds{
"Out-of-bound array access"};
96 "Improper arguments"};
98 CheckerFrontendWithBugType UninitializedRead{
99 "Accessing unitialized/garbage values"};
101 StringRef getDebugTag()
const override {
return "MallocChecker"; }
103 static void *getTag() {
static int tag;
return &tag; }
105 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
106 void checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const;
108 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &
C)
const;
112 ArrayRef<const MemRegion *> ExplicitRegions,
113 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
114 const CallEvent *
Call)
const;
116 using FnCheck =
std::function<void(
const CStringChecker *, CheckerContext &,
119 CallDescriptionMap<FnCheck> Callbacks = {
120 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
121 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
122 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
123 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
124 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
125 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
126 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
127 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
128 {{CDM::CLibrary, {
"memcmp"}, 3},
129 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
130 {{CDM::CLibrary, {
"wmemcmp"}, 3},
131 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
132 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
133 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
134 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
135 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
136 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
137 &CStringChecker::evalMemset},
138 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
140 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
141 &CStringChecker::evalStrcpy},
142 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
143 &CStringChecker::evalStrncpy},
144 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
145 &CStringChecker::evalStpcpy},
146 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
147 &CStringChecker::evalStrlcpy},
148 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
149 &CStringChecker::evalStrcat},
150 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
151 &CStringChecker::evalStrncat},
152 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
153 &CStringChecker::evalStrlcat},
154 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
155 &CStringChecker::evalstrLength},
156 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
157 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
158 &CStringChecker::evalstrnLength},
159 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
160 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
161 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
162 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
163 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
164 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
165 {{CDM::CLibrary, {
"strxfrm"}, 3}, &CStringChecker::evalStrxfrm},
166 {{CDM::CLibraryMaybeHardened, {
"strchr"}, 2},
167 llvm::bind_back(&CStringChecker::evalStrchrCommon,
"strchr()",
169 {{CDM::CLibraryMaybeHardened, {
"strrchr"}, 2},
170 llvm::bind_back(&CStringChecker::evalStrchrCommon,
"strrchr()",
172 {{CDM::CLibraryMaybeHardened, {
"memchr"}, 3},
173 llvm::bind_back(&CStringChecker::evalStrchrCommon,
"memchr()",
175 {{CDM::CLibrary, {
"strstr"}, 2},
176 llvm::bind_back(&CStringChecker::evalStrchrCommon,
"strstr()",
178 {{CDM::CLibrary, {
"strpbrk"}, 2},
179 llvm::bind_back(&CStringChecker::evalStrchrCommon,
"strpbrk()",
181 {{CDM::CLibrary, {
"strchrnul"}, 2},
182 llvm::bind_back(&CStringChecker::evalStrchrCommon,
"strchrnul()",
184 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
185 {{CDM::CLibrary, {
"bcmp"}, 3},
186 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
187 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
188 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
189 &CStringChecker::evalBzero},
197 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
198 &CStringChecker::evalSprintf},
199 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
200 &CStringChecker::evalSnprintf},
204 CallDescription StdCopy{CDM::SimpleFunc, {
"std",
"copy"}, 3},
205 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
207 FnCheck identifyCall(
const CallEvent &
Call, CheckerContext &
C)
const;
208 void evalMemcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
209 void evalMempcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
210 void evalMemmove(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
211 void evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const;
212 void evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
214 DestinationArgExpr Dest, SourceArgExpr Source,
215 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
217 void evalMemcmp(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
219 void evalstrLength(CheckerContext &
C,
const CallEvent &
Call)
const;
220 void evalstrnLength(CheckerContext &
C,
const CallEvent &
Call)
const;
221 void evalstrLengthCommon(CheckerContext &
C,
const CallEvent &
Call,
222 bool IsStrnlen =
false)
const;
224 void evalStrcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
225 void evalStrncpy(CheckerContext &
C,
const CallEvent &
Call)
const;
226 void evalStpcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
227 void evalStrlcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
228 void evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
229 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
230 bool returnPtr =
true)
const;
232 void evalStrxfrm(CheckerContext &
C,
const CallEvent &
Call)
const;
234 void evalStrcat(CheckerContext &
C,
const CallEvent &
Call)
const;
235 void evalStrncat(CheckerContext &
C,
const CallEvent &
Call)
const;
236 void evalStrlcat(CheckerContext &
C,
const CallEvent &
Call)
const;
238 void evalStrcmp(CheckerContext &
C,
const CallEvent &
Call)
const;
239 void evalStrncmp(CheckerContext &
C,
const CallEvent &
Call)
const;
240 void evalStrcasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
241 void evalStrncasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
242 void evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
243 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
245 void evalStrsep(CheckerContext &
C,
const CallEvent &
Call)
const;
247 void evalStrchrCommon(CheckerContext &
C,
const CallEvent &
Call,
248 StringRef FnName,
bool CanReturnNull)
const;
250 void evalStdCopy(CheckerContext &
C,
const CallEvent &
Call)
const;
251 void evalStdCopyBackward(CheckerContext &
C,
const CallEvent &
Call)
const;
252 void evalStdCopyCommon(CheckerContext &
C,
const CallEvent &
Call)
const;
253 void evalMemset(CheckerContext &
C,
const CallEvent &
Call)
const;
254 void evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const;
256 void evalSprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
257 void evalSnprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
258 void evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
259 bool IsBounded)
const;
262 std::pair<ProgramStateRef , ProgramStateRef >
263 static assumeZero(CheckerContext &
C,
269 static SVal getCStringLengthForRegion(CheckerContext &
C,
274 static const StringLiteral *getStringLiteralFromRegion(
const MemRegion *MR);
276 SVal getCStringLength(CheckerContext &
C,
280 bool hypothetical =
false)
const;
282 const StringLiteral *getCStringLiteral(CheckerContext &
C,
291 SVal BufV, SVal SizeV, QualType SizeTy);
299 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
313 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
315 InvalidationTraitOperations);
317 static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
318 const MemRegion *MR);
321 SVal CharE,
const Expr *Size, CheckerContext &
C,
326 AnyArgExpr Arg, SVal l)
const;
330 AnyArgExpr Buffer, SVal Element, SVal Size)
const;
332 AnyArgExpr Buffer, SVal Element,
334 CharKind CK = CharKind::Regular)
const;
336 AnyArgExpr Buffer, SizeArgExpr Size,
338 CharKind CK = CharKind::Regular)
const;
340 SizeArgExpr Size, AnyArgExpr
First,
342 CharKind CK = CharKind::Regular)
const;
343 void emitOverlapBug(CheckerContext &
C,
346 const Stmt *Second)
const;
348 void emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
const Stmt *S,
349 StringRef WarningMsg)
const;
351 const Stmt *S, StringRef WarningMsg)
const;
353 const Stmt *S, StringRef WarningMsg)
const;
355 const Expr *E,
const MemRegion *R,
356 StringRef Msg)
const;
366 SVal BufVal, QualType BufTy, SVal LengthVal,
378std::pair<ProgramStateRef, ProgramStateRef>
381 std::optional<DefinedSVal> val =
V.getAs<DefinedSVal>();
383 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
385 SValBuilder &svalBuilder =
C.getSValBuilder();
386 DefinedOrUnknownSVal zero = svalBuilder.
makeZeroVal(Ty);
387 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
392 AnyArgExpr Arg, SVal l)
const {
398 std::tie(stateNull, stateNonNull) =
399 assumeZero(
C, State, l, Arg.Expression->
getType());
401 if (stateNull && !stateNonNull) {
404 llvm::raw_svector_ostream
OS(buf);
405 assert(!CurrentFunctionDescription.empty());
406 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
407 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
408 << CurrentFunctionDescription;
410 emitNullArgBug(
C, stateNull, Arg.Expression,
OS.str());
416 assert(stateNonNull);
425 if (CK == CharKind::Regular) {
441 if (Offset.isUnknown())
448 Os << Idx << llvm::getOrdinalSuffix(Idx);
453 AnyArgExpr Buffer, SVal Element,
460 SVal BufVal =
C.getSVal(Buffer.Expression);
461 const auto *ER = dyn_cast_or_null<ElementRegion>(BufVal.
getAsRegion());
465 const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
471 if (!SuperR->getValueType()->isArrayType())
474 SValBuilder &SVB =
C.getSValBuilder();
479 std::optional<Loc> FirstElementVal =
481 if (!FirstElementVal)
486 State->getSVal(*FirstElementVal).isUndef()) {
487 llvm::SmallString<258> Buf;
488 llvm::raw_svector_ostream
OS(Buf);
489 OS <<
"The first element of the ";
491 OS <<
" argument is undefined";
492 emitUninitializedReadBug(
C, State, Buffer.Expression,
493 FirstElementVal->getAsRegion(),
OS.str());
524 std::optional<NonLoc> Offset =
534 SVal LastIdx = SVB.
evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);
536 SVal LastElementVal = State->getLValue(ElemTy, LastIdx, BufVal);
541 State->getSVal(LastElementVal.
castAs<Loc>()).isUndef()) {
542 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
549 llvm::SmallString<258> Buf;
550 llvm::raw_svector_ostream
OS(Buf);
551 OS <<
"The last accessed element (at index ";
552 OS << IdxInt->getExtValue();
555 OS <<
" argument is undefined";
556 emitUninitializedReadBug(
C, State, Buffer.Expression,
568 AnyArgExpr Buffer, SVal Element,
581 const auto *ER = dyn_cast<ElementRegion>(R);
586 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
592 DefinedOrUnknownSVal
Size =
595 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
596 if (StOutBound && !StInBound) {
613 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
614 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
625 AnyArgExpr Buffer, SizeArgExpr Size,
626 AccessKind Access, CharKind CK)
const {
631 SValBuilder &svalBuilder =
C.getSValBuilder();
634 QualType SizeTy =
Size.Expression->getType();
635 QualType PtrTy = getCharPtrType(Ctx, CK);
638 SVal BufVal =
C.getSVal(Buffer.Expression);
639 State = checkNonNull(
C, State, Buffer, BufVal);
647 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
655 SVal LengthVal =
C.getSVal(
Size.Expression);
656 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
662 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
663 if (Offset.isUnknown())
665 NonLoc LastOffset = Offset.
castAs<NonLoc>();
668 if (std::optional<Loc> BufLoc = BufStart.
getAs<Loc>()) {
671 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
672 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
673 if (Access == AccessKind::read)
674 State = checkInit(
C, State, Buffer, BufStart, *Length);
687 SizeArgExpr Size, AnyArgExpr
First,
700 if (!
First.Expression->getType()->isAnyPointerType() ||
705 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
710 const StackFrame *SF =
C.getStackFrame();
711 SVal firstVal = state->getSVal(
First.Expression, SF);
712 SVal secondVal = state->getSVal(Second.Expression, SF);
714 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
718 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
723 SValBuilder &svalBuilder =
C.getSValBuilder();
724 std::tie(stateTrue, stateFalse) =
725 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
727 if (stateTrue && !stateFalse) {
730 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
755 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
756 std::optional<DefinedOrUnknownSVal> reverseTest =
757 reverse.
getAs<DefinedOrUnknownSVal>();
761 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
768 std::swap(firstLoc, secondLoc);
771 std::swap(
First, Second);
776 SVal LengthVal = state->getSVal(
Size.Expression, SF);
777 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
784 QualType CharPtrTy = getCharPtrType(Ctx, CK);
786 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
787 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
792 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
794 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
800 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
801 std::optional<DefinedOrUnknownSVal> OverlapTest =
802 Overlap.
getAs<DefinedOrUnknownSVal>();
806 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
808 if (stateTrue && !stateFalse) {
810 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
830void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
832 const Stmt *Second)
const {
834 "Can't emit from a checker that is not enabled!");
835 ExplodedNode *N =
C.generateErrorNode(state);
840 auto report = std::make_unique<PathSensitiveBugReport>(
841 BufferOverlap,
"Arguments must not be overlapping buffers", N);
842 report->addRange(
First->getSourceRange());
845 C.emitReport(std::move(report));
848void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
849 const Stmt *S, StringRef WarningMsg)
const {
851 "Can't emit from a checker that is not enabled!");
852 if (ExplodedNode *N =
C.generateErrorNode(State)) {
854 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
856 if (
const auto *Ex = dyn_cast<Expr>(S))
858 C.emitReport(std::move(
Report));
862void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
864 const Expr *E,
const MemRegion *R,
865 StringRef Msg)
const {
867 "Can't emit from a checker that is not enabled!");
868 if (ExplodedNode *N =
C.generateErrorNode(State)) {
870 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
871 Report->addNote(
"Other elements might also be undefined",
875 Report->addVisitor<NoStoreFuncVisitor>(
R->castAs<SubRegion>());
876 C.emitReport(std::move(
Report));
880void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
882 StringRef WarningMsg)
const {
884 "Can't emit from a checker that is not enabled!");
885 if (ExplodedNode *N =
C.generateErrorNode(State)) {
890 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
892 C.emitReport(std::move(
Report));
896void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
898 StringRef WarningMsg)
const {
900 "Can't emit from a checker that is not enabled!");
901 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
903 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
906 C.emitReport(std::move(
Report));
913 NonLoc right)
const {
918 SValBuilder &svalBuilder =
C.getSValBuilder();
922 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
923 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
927 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
932 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
937 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
940 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
941 *maxMinusRightNL, cmpTy);
943 auto [StateOverflow, StateOkay] =
944 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
946 if (StateOverflow && !StateOkay) {
952 C.addSink(StateOverflow);
967 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
972 case MemRegion::StringRegionKind:
977 case MemRegion::SymbolicRegionKind:
978 case MemRegion::AllocaRegionKind:
979 case MemRegion::NonParamVarRegionKind:
980 case MemRegion::ParamVarRegionKind:
981 case MemRegion::FieldRegionKind:
982 case MemRegion::ObjCIvarRegionKind:
986 case MemRegion::ElementRegionKind:
1000 return state->remove<CStringLength>(MR);
1002 return state->set<CStringLength>(MR, strLength);
1005SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
1008 const MemRegion *MR,
1009 bool hypothetical) {
1010 if (!hypothetical) {
1012 const SVal *Recorded = state->get<CStringLength>(MR);
1018 SValBuilder &svalBuilder =
C.getSValBuilder();
1022 C.getStackFrame(),
C.blockCount());
1024 if (!hypothetical) {
1025 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
1028 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1029 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
1030 std::optional<APSIntPtr> maxLengthInt =
1032 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
1033 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1035 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
1037 state = state->set<CStringLength>(MR, strLength);
1043const StringLiteral *
1044CStringChecker::getStringLiteralFromRegion(
const MemRegion *MR) {
1046 case MemRegion::StringRegionKind:
1048 case MemRegion::NonParamVarRegionKind:
1050 Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage())
1051 return dyn_cast_or_null<StringLiteral>(
Decl->getInit());
1058SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
1059 const Expr *Ex, SVal Buf,
1060 bool hypothetical)
const {
1066 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
1068 SmallString<120> buf;
1069 llvm::raw_svector_ostream os(buf);
1070 assert(!CurrentFunctionDescription.empty());
1071 os <<
"Argument to " << CurrentFunctionDescription
1072 <<
" is the address of the label '" << Label->getLabel()->getName()
1073 <<
"', which is not a null-terminated string";
1075 emitNotCStringBug(
C, state, Ex, os.str());
1077 return UndefinedVal();
1081 return UnknownVal();
1088 if (
const StringLiteral *StrLit = getStringLiteralFromRegion(MR)) {
1094 SValBuilder &SVB =
C.getSValBuilder();
1099 case MemRegion::StringRegionKind:
1100 case MemRegion::NonParamVarRegionKind:
1101 case MemRegion::SymbolicRegionKind:
1102 case MemRegion::AllocaRegionKind:
1103 case MemRegion::ParamVarRegionKind:
1104 case MemRegion::FieldRegionKind:
1105 case MemRegion::ObjCIvarRegionKind:
1106 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1107 case MemRegion::CompoundLiteralRegionKind:
1109 return UnknownVal();
1110 case MemRegion::ElementRegionKind: {
1115 const SubRegion *SuperReg =
1117 const StringLiteral *StrLit = getStringLiteralFromRegion(SuperReg);
1119 return UnknownVal();
1120 SValBuilder &SVB =
C.getSValBuilder();
1125 if (state->assume(SVB.
evalBinOpNN(state, BO_LE, Idx, LengthVal,
1127 .
castAs<DefinedOrUnknownSVal>(),
1129 return SVB.
evalBinOp(state, BO_Sub, LengthVal, Idx, SizeTy);
1130 return UnknownVal();
1137 SmallString<120> buf;
1138 llvm::raw_svector_ostream os(buf);
1140 assert(!CurrentFunctionDescription.empty());
1141 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1143 if (SummarizeRegion(os,
C.getASTContext(), MR))
1144 os <<
", which is not a null-terminated string";
1146 os <<
"not a null-terminated string";
1148 emitNotCStringBug(
C, state, Ex, os.str());
1150 return UndefinedVal();
1154const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1167 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1175bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1176 SVal BufVal, QualType BufTy,
1177 SVal LengthVal, QualType LengthTy) {
1186 SValBuilder &SB =
C.getSValBuilder();
1187 ASTContext &Ctx =
C.getASTContext();
1191 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1197 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1198 if (Offset.isUnknown())
1200 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1203 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1204 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1208 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1215 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1221 C.getASTContext().CharTy &&
1222 "isFirstBufInBound should only be called with char* ElementRegions");
1229 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1233 return static_cast<bool>(StInBound);
1239 auto InvalidationTraitOperations =
1240 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1241 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1244 if (MemRegion::FieldRegionKind ==
R->getKind() &&
1245 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1253 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1257CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1259 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1260 const MemRegion *
R) {
1264 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1267ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1269 auto InvalidationTraitOperations =
1270 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1271 if (MemRegion::FieldRegionKind ==
R->getKind())
1278 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1285 auto InvalidationTraitOperations =
1286 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1295 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1300 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1302 InvalidationTraitOperations) {
1303 std::optional<Loc> L =
V.getAs<Loc>();
1310 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1311 const MemRegion *
R = MR->getRegion()->
StripCasts();
1315 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1321 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
1322 RegionAndSymbolInvalidationTraits ITraits;
1323 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1325 return State->invalidateRegions(R, Elem,
C.blockCount(), SF,
1326 CausesPointerEscape,
nullptr,
nullptr,
1333 return State->killBinding(*L);
1336bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1337 const MemRegion *MR) {
1339 case MemRegion::FunctionCodeRegionKind: {
1341 os <<
"the address of the function '" << *FD <<
'\'';
1343 os <<
"the address of a function";
1346 case MemRegion::BlockCodeRegionKind:
1349 case MemRegion::BlockDataRegionKind:
1352 case MemRegion::CXXThisRegionKind:
1353 case MemRegion::CXXTempObjectRegionKind:
1354 os <<
"a C++ temp object of type "
1357 case MemRegion::NonParamVarRegionKind:
1360 case MemRegion::ParamVarRegionKind:
1363 case MemRegion::FieldRegionKind:
1366 case MemRegion::ObjCIvarRegionKind:
1367 os <<
"an instance variable of type "
1376 SVal CharVal,
const Expr *Size,
1378 SVal MemVal =
C.getSVal(DstBuffer);
1379 SVal SizeVal =
C.getSVal(Size);
1389 const MemRegion *BR = Offset.
getRegion();
1391 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1395 SValBuilder &svalBuilder =
C.getSValBuilder();
1396 ASTContext &Ctx =
C.getASTContext();
1406 std::tie(StateWholeReg, StateNotWholeReg) =
1407 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1414 std::tie(StateNullChar, StateNonNullChar) =
1417 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1418 !StateNonNullChar) {
1426 State->bindDefaultZero(svalBuilder.
makeLoc(BR),
C.getStackFrame());
1430 State = invalidateDestinationBufferBySize(
1431 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1434 if (StateNullChar && !StateNonNullChar) {
1437 State = setCStringLength(State, MR,
1439 }
else if (!StateNullChar && StateNonNullChar) {
1441 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1442 C.getStackFrame(),
C.blockCount());
1446 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1449 State = setCStringLength(
1450 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1456 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1457 SizeVal,
Size->getType());
1466void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1468 DestinationArgExpr Dest,
1469 SourceArgExpr Source,
bool Restricted,
1470 bool IsMempcpy, CharKind CK)
const {
1471 CurrentFunctionDescription =
"memory copy function";
1474 const StackFrame *SF =
C.getStackFrame();
1475 SVal sizeVal = state->getSVal(
Size.Expression, SF);
1476 QualType sizeTy =
Size.Expression->getType();
1479 std::tie(stateZeroSize, stateNonZeroSize) =
1480 assumeZero(
C, state, sizeVal, sizeTy);
1483 SVal destVal = state->getSVal(Dest.Expression, SF);
1487 if (stateZeroSize && !stateNonZeroSize) {
1488 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), SF, destVal);
1489 C.addTransition(stateZeroSize);
1494 if (stateNonZeroSize) {
1498 state = stateNonZeroSize;
1502 state = checkNonNull(
C, state, Dest, destVal);
1507 SVal srcVal = state->getSVal(Source.Expression, SF);
1511 state = checkNonNull(
C, state, Source, srcVal);
1516 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1517 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1520 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1529 SValBuilder &SvalBuilder =
C.getSValBuilder();
1531 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1532 SVal DestRegCharVal =
1533 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1534 SVal lastElement =
C.getSValBuilder().evalBinOp(
1535 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1539 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1542 state = state->BindExpr(
Call.getOriginExpr(), SF, lastElement);
1546 state = state->BindExpr(
Call.getOriginExpr(), SF, destVal);
1555 state = invalidateDestinationBufferBySize(
1556 C, state, Dest.Expression,
Call.getCFGElementRef(),
1557 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1561 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1562 C.getSVal(Source.Expression));
1564 C.addTransition(state);
1568void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1569 CharKind CK)
const {
1572 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1573 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1574 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1578 constexpr bool IsRestricted =
true;
1579 constexpr bool IsMempcpy =
false;
1580 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1583void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1584 CharKind CK)
const {
1587 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1588 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1589 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1591 constexpr bool IsRestricted =
true;
1592 constexpr bool IsMempcpy =
true;
1593 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1597void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1598 CharKind CK)
const {
1601 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1602 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1603 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1605 constexpr bool IsRestricted =
false;
1606 constexpr bool IsMempcpy =
false;
1607 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1611void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1613 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1614 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1615 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1617 constexpr bool IsRestricted =
false;
1618 constexpr bool IsMempcpy =
false;
1619 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1620 IsMempcpy, CharKind::Regular);
1623void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1624 CharKind CK)
const {
1626 CurrentFunctionDescription =
"memory comparison function";
1628 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1629 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1630 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1633 SValBuilder &Builder =
C.getSValBuilder();
1634 const StackFrame *SF =
C.getStackFrame();
1637 SVal sizeVal = State->getSVal(
Size.Expression, SF);
1638 QualType sizeTy =
Size.Expression->getType();
1641 std::tie(stateZeroSize, stateNonZeroSize) =
1642 assumeZero(
C, State, sizeVal, sizeTy);
1646 if (stateZeroSize) {
1647 State = stateZeroSize;
1648 State = State->BindExpr(
Call.getOriginExpr(), SF,
1649 Builder.makeZeroVal(
Call.getResultType()));
1650 C.addTransition(State);
1654 if (stateNonZeroSize) {
1655 State = stateNonZeroSize;
1659 DefinedOrUnknownSVal LV =
1660 State->getSVal(
Left.Expression, SF).castAs<DefinedOrUnknownSVal>();
1661 DefinedOrUnknownSVal RV =
1662 State->getSVal(
Right.Expression, SF).castAs<DefinedOrUnknownSVal>();
1666 std::tie(SameBuffer, NotSameBuffer) =
1667 State->assume(Builder.evalEQ(State, LV, RV));
1671 if (SameBuffer && !NotSameBuffer) {
1673 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1675 State = SameBuffer->BindExpr(
Call.getOriginExpr(), SF,
1676 Builder.makeZeroVal(
Call.getResultType()));
1677 C.addTransition(State);
1684 assert(NotSameBuffer);
1685 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1686 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1689 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1690 State = State->BindExpr(
Call.getOriginExpr(), SF, CmpV);
1691 C.addTransition(State);
1696void CStringChecker::evalstrLength(CheckerContext &
C,
1697 const CallEvent &
Call)
const {
1699 evalstrLengthCommon(
C,
Call,
false);
1702void CStringChecker::evalstrnLength(CheckerContext &
C,
1703 const CallEvent &
Call)
const {
1705 evalstrLengthCommon(
C,
Call,
true);
1708void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1709 const CallEvent &
Call,
1710 bool IsStrnlen)
const {
1711 CurrentFunctionDescription =
"string length function";
1713 const StackFrame *SF =
C.getStackFrame();
1716 const Expr *maxlenExpr =
Call.getArgExpr(1);
1717 SVal maxlenVal = state->getSVal(maxlenExpr, SF);
1720 std::tie(stateZeroSize, stateNonZeroSize) =
1721 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1725 if (stateZeroSize) {
1726 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1727 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), SF, zero);
1728 C.addTransition(stateZeroSize);
1732 if (!stateNonZeroSize)
1736 state = stateNonZeroSize;
1740 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1741 SVal ArgVal = state->getSVal(Arg.Expression, SF);
1742 state = checkNonNull(
C, state, Arg, ArgVal);
1747 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1754 DefinedOrUnknownSVal result = UnknownVal();
1759 QualType cmpTy =
C.getSValBuilder().getConditionType();
1763 const Expr *maxlenExpr =
Call.getArgExpr(1);
1764 SVal maxlenVal = state->getSVal(maxlenExpr, SF);
1766 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1767 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1769 if (strLengthNL && maxlenValNL) {
1773 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1775 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1776 .castAs<DefinedOrUnknownSVal>());
1778 if (stateStringTooLong && !stateStringNotTooLong) {
1780 result = *maxlenValNL;
1781 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1783 result = *strLengthNL;
1792 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1793 NonLoc resultNL = result.
castAs<NonLoc>();
1796 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1797 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1798 .castAs<DefinedOrUnknownSVal>(),
true);
1802 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1803 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1804 .castAs<DefinedOrUnknownSVal>(),
true);
1810 result = strLength.
castAs<DefinedOrUnknownSVal>();
1815 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1820 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1821 state = state->BindExpr(
Call.getOriginExpr(), SF, result);
1822 C.addTransition(state);
1825void CStringChecker::evalStrcpy(CheckerContext &
C,
1826 const CallEvent &
Call)
const {
1828 evalStrcpyCommon(
C,
Call,
1831 ConcatFnKind::none);
1834void CStringChecker::evalStrncpy(CheckerContext &
C,
1835 const CallEvent &
Call)
const {
1837 evalStrcpyCommon(
C,
Call,
1840 ConcatFnKind::none);
1843void CStringChecker::evalStpcpy(CheckerContext &
C,
1844 const CallEvent &
Call)
const {
1846 evalStrcpyCommon(
C,
Call,
1849 ConcatFnKind::none);
1852void CStringChecker::evalStrlcpy(CheckerContext &
C,
1853 const CallEvent &
Call)
const {
1855 evalStrcpyCommon(
C,
Call,
1862void CStringChecker::evalStrcat(CheckerContext &
C,
1863 const CallEvent &
Call)
const {
1865 evalStrcpyCommon(
C,
Call,
1868 ConcatFnKind::strcat);
1871void CStringChecker::evalStrncat(CheckerContext &
C,
1872 const CallEvent &
Call)
const {
1874 evalStrcpyCommon(
C,
Call,
1877 ConcatFnKind::strcat);
1880void CStringChecker::evalStrlcat(CheckerContext &
C,
1881 const CallEvent &
Call)
const {
1885 evalStrcpyCommon(
C,
Call,
1888 ConcatFnKind::strlcat,
1892void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1893 bool ReturnEnd,
bool IsBounded,
1894 ConcatFnKind appendK,
1895 bool returnPtr)
const {
1896 if (appendK == ConcatFnKind::none)
1897 CurrentFunctionDescription =
"string copy function";
1899 CurrentFunctionDescription =
"string concatenation function";
1902 const StackFrame *SF =
C.getStackFrame();
1905 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1906 SVal DstVal = state->getSVal(Dst.Expression, SF);
1907 state = checkNonNull(
C, state, Dst, DstVal);
1912 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1913 SVal srcVal = state->getSVal(srcExpr.Expression, SF);
1914 state = checkNonNull(
C, state, srcExpr, srcVal);
1919 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1920 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1923 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1924 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1930 SValBuilder &svalBuilder =
C.getSValBuilder();
1937 SVal amountCopied = UnknownVal();
1938 SVal maxLastElementIndex = UnknownVal();
1939 const char *boundWarning =
nullptr;
1943 SizeArgExpr SrcExprAsSizeDummy = {
1944 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1945 state = CheckOverlap(
1947 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1956 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1957 SVal lenVal = state->getSVal(lenExpr.Expression, SF);
1961 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1963 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1967 if (strLengthNL && lenValNL) {
1969 case ConcatFnKind::none:
1970 case ConcatFnKind::strcat: {
1975 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1977 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1978 .castAs<DefinedOrUnknownSVal>());
1980 if (stateSourceTooLong && !stateSourceNotTooLong) {
1983 state = stateSourceTooLong;
1984 amountCopied = lenVal;
1986 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1988 state = stateSourceNotTooLong;
1989 amountCopied = strLength;
1993 case ConcatFnKind::strlcat:
1994 if (!dstStrLengthNL)
1998 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
1999 *dstStrLengthNL, sizeTy);
2003 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
2005 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
2012 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
2015 std::tie(TrueState, FalseState) =
2016 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
2019 if (TrueState && !FalseState) {
2020 amountCopied = strLength;
2024 if (!TrueState && FalseState) {
2025 amountCopied = freeSpace;
2028 if (TrueState && FalseState)
2029 amountCopied = UnknownVal();
2036 case ConcatFnKind::strcat:
2042 if (dstStrLength.isUndef())
2045 if (dstStrLengthNL) {
2047 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2049 boundWarning =
"Size argument is greater than the free space in the "
2050 "destination buffer";
2053 case ConcatFnKind::none:
2054 case ConcatFnKind::strlcat:
2064 std::tie(StateZeroSize, StateNonZeroSize) =
2065 assumeZero(
C, state, *lenValNL, sizeTy);
2068 if (StateZeroSize && !StateNonZeroSize) {
2071 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, DstVal);
2073 if (appendK == ConcatFnKind::none) {
2076 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, strLength);
2080 state, BO_Add, strLength, dstStrLength, sizeTy);
2082 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, retSize);
2085 C.addTransition(StateZeroSize);
2093 maxLastElementIndex =
2094 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2095 boundWarning =
"Size argument is greater than the length of the "
2096 "destination buffer";
2103 amountCopied = strLength;
2111 SVal finalStrLength = UnknownVal();
2112 SVal strlRetVal = UnknownVal();
2114 if (appendK == ConcatFnKind::none && !returnPtr) {
2116 strlRetVal = strLength;
2122 if (appendK != ConcatFnKind::none) {
2125 if (dstStrLength.isUndef())
2128 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2129 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2130 *dstStrLengthNL, sizeTy);
2133 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2136 if (amountCopiedNL && dstStrLengthNL) {
2138 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2142 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2143 *dstStrLengthNL, sizeTy);
2152 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2153 assert(!finalStrLength.
isUndef());
2155 if (std::optional<NonLoc> finalStrLengthNL =
2156 finalStrLength.
getAs<NonLoc>()) {
2157 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2161 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2162 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2168 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2171 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2176 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2186 finalStrLength = amountCopied;
2194 Result = (ReturnEnd ? UnknownVal() : DstVal);
2196 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2207 if (std::optional<loc::MemRegionVal> dstRegVal =
2208 DstVal.
getAs<loc::MemRegionVal>()) {
2209 QualType ptrTy = Dst.Expression->getType();
2213 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2214 SVal maxLastElement =
2215 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2218 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2222 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2228 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2229 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2230 *knownStrLength, ptrTy);
2233 if (!boundWarning) {
2235 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2239 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2245 if (returnPtr && ReturnEnd)
2258 bool CouldAccessOutOfBound =
true;
2259 if (IsBounded && amountCopied.
isUnknown()) {
2260 auto CouldAccessOutOfBoundForSVal =
2261 [&](std::optional<NonLoc> Val) ->
bool {
2264 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2265 Dst.Expression->getType(), *Val,
2266 C.getASTContext().getSizeType());
2269 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2271 if (CouldAccessOutOfBound) {
2273 const Expr *LenExpr =
Call.getArgExpr(2);
2274 SVal LenVal = state->getSVal(LenExpr, SF);
2282 CouldAccessOutOfBound =
2283 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2294 if (CouldAccessOutOfBound)
2295 state = invalidateDestinationBufferBySize(
2296 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2297 amountCopied,
C.getASTContext().getSizeType());
2299 state = invalidateDestinationBufferNeverOverflows(
2300 C, state,
Call.getCFGElementRef(), *dstRegVal);
2304 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2307 if (IsBounded && (appendK == ConcatFnKind::none)) {
2312 if (amountCopied != strLength)
2313 finalStrLength = UnknownVal();
2315 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2323 if (ReturnEnd &&
Result.isUnknown()) {
2328 state = state->BindExpr(
Call.getOriginExpr(), SF,
Result);
2329 C.addTransition(state);
2332void CStringChecker::evalStrxfrm(CheckerContext &
C,
2333 const CallEvent &
Call)
const {
2335 CurrentFunctionDescription =
"locale transformation function";
2338 const StackFrame *SF =
C.getStackFrame();
2339 SValBuilder &SVB =
C.getSValBuilder();
2342 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2343 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2344 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2347 SVal SrcVal = State->getSVal(Source.Expression, SF);
2348 State = checkNonNull(
C, State, Source, SrcVal);
2353 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2361 auto BindReturnAndTransition = [&RetVal, &
Call, SF,
2364 State = State->BindExpr(
Call.getOriginExpr(), SF, RetVal);
2365 C.addTransition(State);
2370 SVal SizeVal = State->getSVal(
Size.Expression, SF);
2371 QualType SizeTy =
Size.Expression->getType();
2373 auto [StateZeroSize, StateSizeNonZero] =
2374 assumeZero(
C, State, SizeVal, SizeTy);
2377 if (!StateZeroSize && !StateSizeNonZero)
2378 return BindReturnAndTransition(State);
2381 if (StateZeroSize && !StateSizeNonZero)
2382 return BindReturnAndTransition(StateZeroSize);
2385 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, SF);
2386 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2387 if (!StateSizeNonZero)
2391 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2392 AccessKind::write, CK_Regular);
2393 if (!StateSizeNonZero)
2398 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2400 .
getAs<DefinedOrUnknownSVal>();
2401 if (!ComparisonVal) {
2403 StateSizeNonZero = invalidateDestinationBufferBySize(
2404 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2405 SizeVal,
Size.Expression->getType());
2406 return BindReturnAndTransition(StateSizeNonZero);
2409 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2413 StateSuccess = invalidateDestinationBufferBySize(
2414 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2415 SizeVal,
Size.Expression->getType());
2416 BindReturnAndTransition(StateSuccess);
2422 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2423 StateFailure = StateFailure->killBinding(*DestLoc);
2425 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, SF);
2428 BindReturnAndTransition(StateFailure);
2432void CStringChecker::evalStrcmp(CheckerContext &
C,
2433 const CallEvent &
Call)
const {
2435 evalStrcmpCommon(
C,
Call,
false,
false);
2438void CStringChecker::evalStrncmp(CheckerContext &
C,
2439 const CallEvent &
Call)
const {
2441 evalStrcmpCommon(
C,
Call,
true,
false);
2444void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2445 const CallEvent &
Call)
const {
2447 evalStrcmpCommon(
C,
Call,
false,
true);
2450void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2451 const CallEvent &
Call)
const {
2453 evalStrcmpCommon(
C,
Call,
true,
true);
2456void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2457 bool IsBounded,
bool IgnoreCase)
const {
2458 CurrentFunctionDescription =
"string comparison function";
2460 const StackFrame *SF =
C.getStackFrame();
2463 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2464 SVal LeftVal = state->getSVal(
Left.Expression, SF);
2465 state = checkNonNull(
C, state, Left, LeftVal);
2470 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2471 SVal RightVal = state->getSVal(
Right.Expression, SF);
2472 state = checkNonNull(
C, state, Right, RightVal);
2477 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2482 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2489 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2490 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2493 SValBuilder &svalBuilder =
C.getSValBuilder();
2494 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2496 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2502 StSameBuf->BindExpr(
Call.getOriginExpr(), SF,
2503 svalBuilder.makeZeroVal(
Call.getResultType()));
2504 C.addTransition(StSameBuf);
2511 assert(StNotSameBuf);
2512 state = StNotSameBuf;
2518 const StringLiteral *LeftStrLiteral =
2519 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2520 const StringLiteral *RightStrLiteral =
2521 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2522 bool canComputeResult =
false;
2523 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2525 if (LeftStrLiteral && RightStrLiteral) {
2526 StringRef LeftStrRef = LeftStrLiteral->
getString();
2527 StringRef RightStrRef = RightStrLiteral->
getString();
2531 const Expr *lenExpr =
Call.getArgExpr(2);
2532 SVal lenVal = state->getSVal(lenExpr, SF);
2535 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2537 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2538 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2539 canComputeResult =
true;
2543 canComputeResult =
true;
2546 if (canComputeResult) {
2548 size_t s1Term = LeftStrRef.find(
'\0');
2549 if (s1Term != StringRef::npos)
2550 LeftStrRef = LeftStrRef.substr(0, s1Term);
2552 size_t s2Term = RightStrRef.find(
'\0');
2553 if (s2Term != StringRef::npos)
2554 RightStrRef = RightStrRef.substr(0, s2Term);
2557 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2558 : LeftStrRef.compare(RightStrRef);
2562 if (compareRes == 0) {
2563 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2566 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2570 SVal compareWithZero =
2571 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2572 svalBuilder.getConditionType());
2573 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2574 state = state->assume(compareWithZeroVal,
true);
2579 state = state->BindExpr(
Call.getOriginExpr(), SF, resultVal);
2582 C.addTransition(state);
2585void CStringChecker::evalStrsep(CheckerContext &
C,
2586 const CallEvent &
Call)
const {
2589 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2591 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2592 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2596 CurrentFunctionDescription =
"strsep()";
2598 const StackFrame *SF =
C.getStackFrame();
2602 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, SF);
2603 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2608 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2609 SVal DelimStrVal = State->getSVal(DelimStr.Expression, SF);
2610 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2614 SValBuilder &SVB =
C.getSValBuilder();
2616 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2618 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2623 State = invalidateDestinationBufferNeverOverflows(
2628 State = State->bindLoc(*SearchStrLoc,
2638 State = State->BindExpr(
Call.getOriginExpr(), SF,
Result);
2639 C.addTransition(State);
2642void CStringChecker::evalStrchrCommon(CheckerContext &
C,
const CallEvent &
Call,
2644 bool CanReturnNull)
const {
2645 CurrentFunctionDescription = FnName;
2646 const Expr *CE =
Call.getOriginExpr();
2654 const StackFrame *SF =
C.getStackFrame();
2655 SValBuilder &SVB =
C.getSValBuilder();
2656 ASTContext &Ctx =
C.getASTContext();
2659 SourceArgExpr Src = {{
Call.getArgExpr(0), 0}};
2660 SVal SrcVal = State->getSVal(Src.Expression, SF);
2661 State = checkNonNull(
C, State, Src, SrcVal);
2666 if (CanReturnNull) {
2669 C.addTransition(NullState);
2673 std::optional<Loc> SrcLoc = SrcVal.
getAs<Loc>();
2676 State = State->BindExpr(CE, SF,
Result);
2677 C.addTransition(State);
2682 auto RemainingExtentBytes =
2687 State = State->assumeInBound(SymOffset, RemainingExtentBytes,
true);
2690 Src.Expression->getType());
2691 State = State->BindExpr(CE, SF,
Result);
2692 C.addTransition(State);
2696void CStringChecker::evalStdCopy(CheckerContext &
C,
2697 const CallEvent &
Call)
const {
2698 evalStdCopyCommon(
C,
Call);
2701void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2702 const CallEvent &
Call)
const {
2703 evalStdCopyCommon(
C,
Call);
2706void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2707 const CallEvent &
Call)
const {
2708 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2713 const StackFrame *SF =
C.getStackFrame();
2721 const Expr *Dst =
Call.getArgExpr(2);
2722 SVal DstVal = State->getSVal(Dst, SF);
2725 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2726 C, State,
Call.getCFGElementRef(), DstVal);
2728 SValBuilder &SVB =
C.getSValBuilder();
2731 State = State->BindExpr(
Call.getOriginExpr(), SF, ResultVal);
2733 C.addTransition(State);
2736void CStringChecker::evalMemset(CheckerContext &
C,
2737 const CallEvent &
Call)
const {
2739 CurrentFunctionDescription =
"memory set function";
2741 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2742 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2743 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2748 const StackFrame *SF =
C.getStackFrame();
2749 SVal SizeVal =
C.getSVal(
Size.Expression);
2750 QualType SizeTy =
Size.Expression->getType();
2753 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2756 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2760 if (ZeroSize && !NonZeroSize) {
2761 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), SF, BufferPtrVal);
2762 C.addTransition(ZeroSize);
2768 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2772 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2779 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2780 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2783 State = State->BindExpr(
Call.getOriginExpr(), SF, BufferPtrVal);
2784 C.addTransition(State);
2787void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2788 CurrentFunctionDescription =
"memory clearance function";
2790 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2791 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2792 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2797 SVal SizeVal =
C.getSVal(
Size.Expression);
2798 QualType SizeTy =
Size.Expression->getType();
2801 std::tie(StateZeroSize, StateNonZeroSize) =
2802 assumeZero(
C, State, SizeVal, SizeTy);
2806 if (StateZeroSize && !StateNonZeroSize) {
2807 C.addTransition(StateZeroSize);
2812 SVal MemVal =
C.getSVal(Buffer.Expression);
2816 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2820 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2824 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
2825 Size.Expression,
C, State))
2828 C.addTransition(State);
2831void CStringChecker::evalSprintf(CheckerContext &
C,
2832 const CallEvent &
Call)
const {
2833 CurrentFunctionDescription =
"'sprintf'";
2834 evalSprintfCommon(
C,
Call,
false);
2837void CStringChecker::evalSnprintf(CheckerContext &
C,
2838 const CallEvent &
Call)
const {
2839 CurrentFunctionDescription =
"'snprintf'";
2840 evalSprintfCommon(
C,
Call,
true);
2843void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
2844 bool IsBounded)
const {
2847 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2849 const auto NumParams =
Call.parameters().size();
2850 if (CE->getNumArgs() < NumParams) {
2855 const auto AllArguments =
2856 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2857 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2859 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2861 if (
const QualType
type = ArgExpr->getType();
2862 !
type->isAnyPointerType() ||
2863 !
type->getPointeeType()->isAnyCharacterType())
2865 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
2868 SizeArgExpr SrcExprAsSizeDummy = {
2869 {Source.Expression, Source.ArgumentIndex}};
2870 State = CheckOverlap(
2872 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2878 C.addTransition(State);
2885CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2886 CheckerContext &
C)
const {
2887 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2891 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
2896 return &CStringChecker::evalStdCopy;
2898 return &CStringChecker::evalStdCopyBackward;
2904 for (
auto I : CE->arguments()) {
2905 QualType
T = I->getType();
2910 const FnCheck *Callback = Callbacks.lookup(
Call);
2917bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
2918 FnCheck Callback = identifyCall(
Call,
C);
2926 Callback(
this,
C,
Call);
2934 return C.isDifferent();
2937void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
2941 for (
const auto *I : DS->
decls()) {
2942 const VarDecl *D = dyn_cast<VarDecl>(I);
2956 Loc VarLoc = state->getLValue(D,
C.getStackFrame());
2961 SVal StrVal =
C.getSVal(
Init);
2962 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2963 DefinedOrUnknownSVal strLength =
2964 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
2966 state = state->set<CStringLength>(MR, strLength);
2969 C.addTransition(state);
2974 ArrayRef<const MemRegion *> ExplicitRegions,
2975 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
2976 const CallEvent *
Call)
const {
2977 CStringLengthTy Entries = state->get<CStringLength>();
2978 if (Entries.isEmpty())
2981 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2982 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2985 for (
const MemRegion *MR : Regions) {
2986 Invalidated.insert(MR);
2988 SuperRegions.insert(MR);
2989 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2990 MR = SR->getSuperRegion();
2991 SuperRegions.insert(MR);
2995 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2998 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
3000 if (SuperRegions.count(MR)) {
3001 Entries = F.remove(Entries, MR);
3006 const MemRegion *Super = MR;
3007 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
3008 Super = SR->getSuperRegion();
3009 if (Invalidated.count(Super)) {
3010 Entries = F.remove(Entries, MR);
3016 return state->set<CStringLength>(Entries);
3020 SymbolReaper &SR)
const {
3022 CStringLengthTy Entries = state->get<CStringLength>();
3024 for (SVal Len : llvm::make_second_range(Entries)) {
3030void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
3031 CheckerContext &
C)
const {
3033 CStringLengthTy Entries = state->get<CStringLength>();
3034 if (Entries.isEmpty())
3037 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
3038 for (
auto [Reg, Len] : Entries) {
3039 if (
SymbolRef Sym = Len.getAsSymbol()) {
3041 Entries = F.remove(Entries, Reg);
3045 state = state->set<CStringLength>(Entries);
3046 C.addTransition(state);
3049void ento::registerCStringModeling(CheckerManager &Mgr) {
3056bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
3060#define REGISTER_CHECKER(NAME) \
3061 void ento::registerCString##NAME(CheckerManager &Mgr) { \
3062 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
3065 bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \
3075#undef REGISTER_CHECKER
static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx)
#define REGISTER_CHECKER(name)
Result
Implement __builtin_bit_cast and related operations.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedCharTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
LangAS getAddressSpace() const
Return the address space of this type.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
unsigned getLength() const
StringRef getString() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
bool isAnyPointerType() const
const Expr * getInit() const
APSIntPtr getMaxValue(const llvm::APSInt &v)
std::optional< APSIntPtr > evalAPSInt(UnaryOperator::Opcode Op, const llvm::APSInt &V1)
bool matches(const CallEvent &Call) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
Checker families (where a single backend class implements multiple related frontends) should derive f...
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
ElementRegion is used to represent both array elements and casts.
QualType getValueType() const override
MemRegion - The root abstract class for all memory regions.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
SValBuilder & getSValBuilder()
@ 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)
bool hasSymbolicOffset() const
const MemRegion * getRegion() const
It might return null.
int64_t getOffset() const
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...
ProgramStateManager & getStateManager()
virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, Loc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two memory location operands.
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
QualType getArrayIndexType() const
loc::MemRegionVal makeLoc(SymbolRef sym)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy)
Cast a given SVal to another SVal using given QualType's.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
loc::ConcreteInt makeNullWithType(QualType type)
Create NULL pointer, with proper pointer bit-width for given address space.
NonLoc makeZeroArrayIndex()
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
DefinedSVal getMetadataSymbolVal(const void *symbolTag, const MemRegion *region, const Expr *expr, QualType type, const StackFrame *SF, unsigned count)
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, ConstCFGElementRef elem, const StackFrame *SF, unsigned count)
Create a new symbol with a unique 'name'.
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.
LLVM_ATTRIBUTE_RETURNS_NONNULL const StringLiteral * getStringLiteral() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
llvm::iterator_range< symbol_iterator > symbols() const
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
llvm::DenseSet< SymbolRef > InvalidatedSymbols
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
SVal getDynamicExtentWithOffset(ProgramStateRef State, SVal BufV)
Get the dynamic extent for a symbolic value that represents a buffer.
const SymExpr * SymbolRef
DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB)
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
CFGBlock::ConstCFGElementRef ConstCFGElementRef
const FunctionProtoType * T
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
U cast(CodeGen::Address addr)
int const char * function