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 };
74constexpr CharKind CK_Regular = CharKind::Regular;
75constexpr CharKind CK_Wide = CharKind::Wide;
84 check::LiveSymbols, check::DeadSymbols,
85 check::RegionChanges> {
86 mutable StringRef CurrentFunctionDescription;
89 CheckerFrontendWithBugType NullArg{
"Null pointer argument"};
90 CheckerFrontendWithBugType OutOfBounds{
"Out-of-bound array access"};
91 CheckerFrontendWithBugType BufferOverlap{
"Overlapping buffers",
92 "Improper arguments"};
93 CheckerFrontendWithBugType NotNullTerm{
"Not null-terminated string"};
94 CheckerFrontendWithBugType UninitializedRead{
95 "Accessing uninitialized/garbage values"};
97 StringRef getDebugTag()
const override {
return "MallocChecker"; }
99 static void *getTag() {
static int tag;
return &tag; }
101 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
102 void checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const;
104 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &
C)
const;
108 ArrayRef<const MemRegion *> ExplicitRegions,
109 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
110 const CallEvent *
Call)
const;
112 using FnCheck =
std::function<void(
const CStringChecker *, CheckerContext &,
115 CallDescriptionMap<FnCheck> Callbacks = {
116 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
117 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
118 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
119 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
120 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
121 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
122 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
123 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
124 {{CDM::CLibrary, {
"memcmp"}, 3},
125 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
126 {{CDM::CLibrary, {
"wmemcmp"}, 3},
127 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
128 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
129 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
130 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
131 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
132 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
133 &CStringChecker::evalMemset},
134 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
136 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
137 &CStringChecker::evalStrcpy},
138 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
139 &CStringChecker::evalStrncpy},
140 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
141 &CStringChecker::evalStpcpy},
142 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
143 &CStringChecker::evalStrlcpy},
144 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
145 &CStringChecker::evalStrcat},
146 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
147 &CStringChecker::evalStrncat},
148 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
149 &CStringChecker::evalStrlcat},
150 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
151 &CStringChecker::evalstrLength},
152 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
153 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
154 &CStringChecker::evalstrnLength},
155 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
156 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
157 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
158 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
159 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
160 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
161 {{CDM::CLibrary, {
"strxfrm"}, 3}, &CStringChecker::evalStrxfrm},
162 {{CDM::CLibraryMaybeHardened, {
"strchr"}, 2},
163 &CStringChecker::evalStrchr},
164 {{CDM::CLibraryMaybeHardened, {
"strrchr"}, 2},
165 &CStringChecker::evalStrrchr},
166 {{CDM::CLibraryMaybeHardened, {
"memchr"}, 3},
167 &CStringChecker::evalMemchr},
168 {{CDM::CLibrary, {
"strstr"}, 2}, &CStringChecker::evalStrstr},
169 {{CDM::CLibrary, {
"strpbrk"}, 2}, &CStringChecker::evalStrpbrk},
170 {{CDM::CLibrary, {
"strchrnul"}, 2}, &CStringChecker::evalStrchrnul},
171 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
172 {{CDM::CLibrary, {
"bcmp"}, 3},
173 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
174 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
175 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
176 &CStringChecker::evalBzero},
184 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
185 &CStringChecker::evalSprintf},
186 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
187 &CStringChecker::evalSnprintf},
191 CallDescription StdCopy{CDM::SimpleFunc, {
"std",
"copy"}, 3},
192 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
194 FnCheck identifyCall(
const CallEvent &
Call, CheckerContext &
C)
const;
195 void evalMemcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
196 void evalMempcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
197 void evalMemmove(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
198 void evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const;
199 void evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
201 DestinationArgExpr Dest, SourceArgExpr Source,
202 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
204 void evalMemcmp(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
206 void evalstrLength(CheckerContext &
C,
const CallEvent &
Call)
const;
207 void evalstrnLength(CheckerContext &
C,
const CallEvent &
Call)
const;
208 void evalstrLengthCommon(CheckerContext &
C,
const CallEvent &
Call,
209 bool IsStrnlen =
false)
const;
211 void evalStrcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
212 void evalStrncpy(CheckerContext &
C,
const CallEvent &
Call)
const;
213 void evalStpcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
214 void evalStrlcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
215 void evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
216 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
217 bool returnPtr =
true)
const;
219 void evalStrxfrm(CheckerContext &
C,
const CallEvent &
Call)
const;
221 void evalStrcat(CheckerContext &
C,
const CallEvent &
Call)
const;
222 void evalStrncat(CheckerContext &
C,
const CallEvent &
Call)
const;
223 void evalStrlcat(CheckerContext &
C,
const CallEvent &
Call)
const;
225 void evalStrcmp(CheckerContext &
C,
const CallEvent &
Call)
const;
226 void evalStrncmp(CheckerContext &
C,
const CallEvent &
Call)
const;
227 void evalStrcasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
228 void evalStrncasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
229 void evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
230 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
232 void evalStrsep(CheckerContext &
C,
const CallEvent &
Call)
const;
234 void evalStrchr(CheckerContext &
C,
const CallEvent &
Call)
const;
235 void evalStrrchr(CheckerContext &
C,
const CallEvent &
Call)
const;
236 void evalMemchr(CheckerContext &
C,
const CallEvent &
Call)
const;
237 void evalStrstr(CheckerContext &
C,
const CallEvent &
Call)
const;
238 void evalStrpbrk(CheckerContext &
C,
const CallEvent &
Call)
const;
239 void evalStrchrnul(CheckerContext &
C,
const CallEvent &
Call)
const;
243 void evalStrchrCommon(CheckerContext &
C,
const CallEvent &
Call,
245 std::optional<size_t> ConstOffset)
const;
247 void evalStdCopy(CheckerContext &
C,
const CallEvent &
Call)
const;
248 void evalStdCopyBackward(CheckerContext &
C,
const CallEvent &
Call)
const;
249 void evalStdCopyCommon(CheckerContext &
C,
const CallEvent &
Call)
const;
250 void evalMemset(CheckerContext &
C,
const CallEvent &
Call)
const;
251 void evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const;
253 void evalSprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
254 void evalSnprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
255 void evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
256 bool IsBounded)
const;
259 std::pair<ProgramStateRef , ProgramStateRef >
260 static assumeZero(CheckerContext &
C,
266 static SVal getCStringLengthForRegion(CheckerContext &
C,
271 static const StringLiteral *getStringLiteralFromRegion(
const MemRegion *MR);
273 static std::optional<StringRef> getStringRefAtRegion(
const MemRegion *R);
275 SVal getCStringLength(CheckerContext &
C,
279 bool hypothetical =
false)
const;
281 const StringLiteral *getCStringLiteral(CheckerContext &
C,
290 SVal BufV, SVal SizeV, QualType SizeTy);
298 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
312 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
314 InvalidationTraitOperations);
316 static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
317 const MemRegion *MR);
320 SVal CharE,
const Expr *Size, CheckerContext &
C,
325 AnyArgExpr Arg, SVal l)
const;
329 AnyArgExpr Buffer, SVal Element, SVal Size)
const;
331 AnyArgExpr Buffer, SVal Element,
333 CharKind CK = CharKind::Regular)
const;
335 AnyArgExpr Buffer, SizeArgExpr Size,
337 CharKind CK = CharKind::Regular)
const;
339 SizeArgExpr Size, AnyArgExpr
First,
341 CharKind CK = CharKind::Regular)
const;
342 void emitOverlapBug(CheckerContext &
C,
345 const Stmt *Second)
const;
347 void emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
const Stmt *S,
348 StringRef WarningMsg)
const;
350 const Stmt *S, StringRef WarningMsg)
const;
352 const Stmt *S, StringRef WarningMsg)
const;
354 const Expr *E,
const MemRegion *R,
355 StringRef Msg)
const;
365 SVal BufVal, QualType BufTy, SVal LengthVal,
377std::pair<ProgramStateRef, ProgramStateRef>
380 std::optional<DefinedSVal> val =
V.getAs<DefinedSVal>();
382 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
384 SValBuilder &svalBuilder =
C.getSValBuilder();
385 DefinedOrUnknownSVal zero = svalBuilder.
makeZeroVal(Ty);
386 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
391 AnyArgExpr Arg, SVal l)
const {
397 std::tie(stateNull, stateNonNull) =
398 assumeZero(
C, State, l, Arg.Expression->
getType());
400 if (stateNull && !stateNonNull) {
403 llvm::raw_svector_ostream
OS(buf);
404 assert(!CurrentFunctionDescription.empty());
405 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
406 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
407 << CurrentFunctionDescription;
409 emitNullArgBug(
C, stateNull, Arg.Expression,
OS.str());
415 assert(stateNonNull);
424 if (CK == CharKind::Regular) {
440 if (Offset.isUnknown())
447 Os << Idx << llvm::getOrdinalSuffix(Idx);
452 AnyArgExpr Buffer, SVal Element,
459 SVal BufVal =
C.getSVal(Buffer.Expression);
460 const auto *ER = dyn_cast_or_null<ElementRegion>(BufVal.
getAsRegion());
464 const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
470 if (!SuperR->getValueType()->isArrayType())
473 SValBuilder &SVB =
C.getSValBuilder();
478 std::optional<Loc> FirstElementVal =
480 if (!FirstElementVal)
485 State->getSVal(*FirstElementVal).isUndef()) {
486 llvm::SmallString<258> Buf;
487 llvm::raw_svector_ostream
OS(Buf);
488 OS <<
"The first element of the ";
490 OS <<
" argument is undefined";
491 emitUninitializedReadBug(
C, State, Buffer.Expression,
492 FirstElementVal->getAsRegion(),
OS.str());
523 std::optional<NonLoc> Offset =
533 SVal LastIdx = SVB.
evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);
535 SVal LastElementVal = State->getLValue(ElemTy, LastIdx, BufVal);
540 State->getSVal(LastElementVal.
castAs<Loc>()).isUndef()) {
541 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
548 llvm::SmallString<258> Buf;
549 llvm::raw_svector_ostream
OS(Buf);
550 OS <<
"The last accessed element (at index ";
551 OS << IdxInt->getExtValue();
554 OS <<
" argument is undefined";
555 emitUninitializedReadBug(
C, State, Buffer.Expression,
567 AnyArgExpr Buffer, SVal Element,
580 const auto *ER = dyn_cast<ElementRegion>(R);
585 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
591 DefinedOrUnknownSVal
Size =
594 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
595 if (StOutBound && !StInBound) {
612 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
613 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
624 AnyArgExpr Buffer, SizeArgExpr Size,
625 AccessKind Access, CharKind CK)
const {
630 SValBuilder &svalBuilder =
C.getSValBuilder();
633 QualType SizeTy =
Size.Expression->getType();
634 QualType PtrTy = getCharPtrType(Ctx, CK);
637 SVal BufVal =
C.getSVal(Buffer.Expression);
638 State = checkNonNull(
C, State, Buffer, BufVal);
646 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
654 SVal LengthVal =
C.getSVal(
Size.Expression);
655 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
661 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
662 if (Offset.isUnknown())
664 NonLoc LastOffset = Offset.
castAs<NonLoc>();
667 if (std::optional<Loc> BufLoc = BufStart.
getAs<Loc>()) {
670 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
671 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
672 if (Access == AccessKind::read)
673 State = checkInit(
C, State, Buffer, BufStart, *Length);
686 SizeArgExpr Size, AnyArgExpr
First,
699 if (!
First.Expression->getType()->isAnyPointerType() ||
704 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
709 const StackFrame *SF =
C.getStackFrame();
710 SVal firstVal = state->getSVal(
First.Expression, SF);
711 SVal secondVal = state->getSVal(Second.Expression, SF);
713 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
717 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
722 SValBuilder &svalBuilder =
C.getSValBuilder();
723 std::tie(stateTrue, stateFalse) =
724 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
726 if (stateTrue && !stateFalse) {
729 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
754 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
755 std::optional<DefinedOrUnknownSVal> reverseTest =
756 reverse.
getAs<DefinedOrUnknownSVal>();
760 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
767 std::swap(firstLoc, secondLoc);
770 std::swap(
First, Second);
775 SVal LengthVal = state->getSVal(
Size.Expression, SF);
776 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
783 QualType CharPtrTy = getCharPtrType(Ctx, CK);
785 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
786 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
791 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
793 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
799 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
800 std::optional<DefinedOrUnknownSVal> OverlapTest =
801 Overlap.
getAs<DefinedOrUnknownSVal>();
805 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
807 if (stateTrue && !stateFalse) {
809 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
829void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
831 const Stmt *Second)
const {
833 "Can't emit from a checker that is not enabled!");
834 ExplodedNode *N =
C.generateErrorNode(state);
839 auto report = std::make_unique<PathSensitiveBugReport>(
840 BufferOverlap,
"Arguments must not be overlapping buffers", N);
841 report->addRange(
First->getSourceRange());
844 C.emitReport(std::move(report));
847void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
848 const Stmt *S, StringRef WarningMsg)
const {
850 "Can't emit from a checker that is not enabled!");
851 if (ExplodedNode *N =
C.generateErrorNode(State)) {
853 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
855 if (
const auto *Ex = dyn_cast<Expr>(S))
857 C.emitReport(std::move(
Report));
861void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
863 const Expr *E,
const MemRegion *R,
864 StringRef Msg)
const {
866 "Can't emit from a checker that is not enabled!");
867 if (ExplodedNode *N =
C.generateErrorNode(State)) {
869 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
870 Report->addNote(
"Other elements might also be undefined",
874 Report->addVisitor<NoStoreFuncVisitor>(
R->castAs<SubRegion>());
875 C.emitReport(std::move(
Report));
879void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
881 StringRef WarningMsg)
const {
883 "Can't emit from a checker that is not enabled!");
884 if (ExplodedNode *N =
C.generateErrorNode(State)) {
889 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
891 C.emitReport(std::move(
Report));
895void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
897 StringRef WarningMsg)
const {
899 "Can't emit from a checker that is not enabled!");
900 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
902 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
905 C.emitReport(std::move(
Report));
912 NonLoc right)
const {
917 SValBuilder &svalBuilder =
C.getSValBuilder();
921 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
922 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
926 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
931 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
936 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
939 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
940 *maxMinusRightNL, cmpTy);
942 auto [StateOverflow, StateOkay] =
943 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
945 if (StateOverflow && !StateOkay) {
951 C.addSink(StateOverflow);
966 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
971 case MemRegion::StringRegionKind:
976 case MemRegion::SymbolicRegionKind:
977 case MemRegion::AllocaRegionKind:
978 case MemRegion::NonParamVarRegionKind:
979 case MemRegion::ParamVarRegionKind:
980 case MemRegion::FieldRegionKind:
981 case MemRegion::ObjCIvarRegionKind:
985 case MemRegion::ElementRegionKind:
999 return state->remove<CStringLength>(MR);
1001 return state->set<CStringLength>(MR, strLength);
1004SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
1007 const MemRegion *MR,
1008 bool hypothetical) {
1009 if (!hypothetical) {
1011 const SVal *Recorded = state->get<CStringLength>(MR);
1017 SValBuilder &svalBuilder =
C.getSValBuilder();
1021 C.getStackFrame(),
C.blockCount());
1023 if (!hypothetical) {
1024 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
1027 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1028 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
1029 std::optional<APSIntPtr> maxLengthInt =
1031 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
1032 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1034 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
1036 state = state->set<CStringLength>(MR, strLength);
1042const StringLiteral *
1043CStringChecker::getStringLiteralFromRegion(
const MemRegion *MR) {
1045 case MemRegion::StringRegionKind:
1047 case MemRegion::NonParamVarRegionKind:
1049 Decl->getType().isConstQualified())
1050 return dyn_cast_or_null<StringLiteral>(
Decl->getInit());
1057std::optional<StringRef>
1058CStringChecker::getStringRefAtRegion(
const MemRegion *R) {
1060 return std::nullopt;
1062 const MemRegion *
Base =
R->StripCasts();
1063 if (
const auto *ER = dyn_cast<ElementRegion>(Base)) {
1064 if (
auto Idx = ER->getIndex().getAs<nonloc::ConcreteInt>()) {
1065 Offset = Idx->getValue().get()->getZExtValue();
1066 Base = ER->getSuperRegion()->StripCasts();
1068 return std::nullopt;
1071 const StringLiteral *Lit = getStringLiteralFromRegion(Base);
1073 return std::nullopt;
1078 return std::nullopt;
1080 if (Offset > S.size())
1081 return std::nullopt;
1082 return S.substr(Offset);
1085SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
1086 const Expr *Ex, SVal Buf,
1087 bool hypothetical)
const {
1093 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
1095 SmallString<120> buf;
1096 llvm::raw_svector_ostream os(buf);
1097 assert(!CurrentFunctionDescription.empty());
1098 os <<
"Argument to " << CurrentFunctionDescription
1099 <<
" is the address of the label '" << Label->getLabel()->getName()
1100 <<
"', which is not a null-terminated string";
1102 emitNotCStringBug(
C, state, Ex, os.str());
1104 return UndefinedVal();
1108 return UnknownVal();
1115 if (
const StringLiteral *StrLit = getStringLiteralFromRegion(MR)) {
1121 SValBuilder &SVB =
C.getSValBuilder();
1126 case MemRegion::StringRegionKind:
1127 case MemRegion::NonParamVarRegionKind:
1128 case MemRegion::SymbolicRegionKind:
1129 case MemRegion::AllocaRegionKind:
1130 case MemRegion::ParamVarRegionKind:
1131 case MemRegion::FieldRegionKind:
1132 case MemRegion::ObjCIvarRegionKind:
1133 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1134 case MemRegion::CompoundLiteralRegionKind:
1136 return UnknownVal();
1137 case MemRegion::ElementRegionKind: {
1142 const SubRegion *SuperReg =
1144 const StringLiteral *StrLit = getStringLiteralFromRegion(SuperReg);
1146 return UnknownVal();
1147 SValBuilder &SVB =
C.getSValBuilder();
1152 if (state->assume(SVB.
evalBinOpNN(state, BO_LE, Idx, LengthVal,
1154 .
castAs<DefinedOrUnknownSVal>(),
1156 return SVB.
evalBinOp(state, BO_Sub, LengthVal, Idx, SizeTy);
1157 return UnknownVal();
1164 SmallString<120> buf;
1165 llvm::raw_svector_ostream os(buf);
1167 assert(!CurrentFunctionDescription.empty());
1168 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1170 if (SummarizeRegion(os,
C.getASTContext(), MR))
1171 os <<
", which is not a null-terminated string";
1173 os <<
"not a null-terminated string";
1175 emitNotCStringBug(
C, state, Ex, os.str());
1177 return UndefinedVal();
1181const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1194 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1202bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1203 SVal BufVal, QualType BufTy,
1204 SVal LengthVal, QualType LengthTy) {
1213 SValBuilder &SB =
C.getSValBuilder();
1214 ASTContext &Ctx =
C.getASTContext();
1218 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1224 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1225 if (Offset.isUnknown())
1227 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1230 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1231 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1235 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1242 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1248 C.getASTContext().CharTy &&
1249 "isFirstBufInBound should only be called with char* ElementRegions");
1256 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1260 return static_cast<bool>(StInBound);
1266 auto InvalidationTraitOperations =
1267 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1268 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1271 if (MemRegion::FieldRegionKind ==
R->getKind() &&
1272 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1280 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1284CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1286 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1287 const MemRegion *
R) {
1291 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1294ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1296 auto InvalidationTraitOperations =
1297 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1298 if (MemRegion::FieldRegionKind ==
R->getKind())
1305 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1312 auto InvalidationTraitOperations =
1313 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1322 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1327 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1329 InvalidationTraitOperations) {
1330 std::optional<Loc> L =
V.getAs<Loc>();
1337 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1338 const MemRegion *
R = MR->getRegion()->
StripCasts();
1342 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1348 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
1349 RegionAndSymbolInvalidationTraits ITraits;
1350 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1352 return State->invalidateRegions(R, Elem,
C.blockCount(), SF,
1353 CausesPointerEscape,
nullptr,
nullptr,
1360 return State->killBinding(*L);
1363bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1364 const MemRegion *MR) {
1366 case MemRegion::FunctionCodeRegionKind: {
1368 os <<
"the address of the function '" << *FD <<
'\'';
1370 os <<
"the address of a function";
1373 case MemRegion::BlockCodeRegionKind:
1376 case MemRegion::BlockDataRegionKind:
1379 case MemRegion::CXXThisRegionKind:
1380 case MemRegion::CXXTempObjectRegionKind:
1381 os <<
"a C++ temp object of type "
1384 case MemRegion::NonParamVarRegionKind:
1387 case MemRegion::ParamVarRegionKind:
1390 case MemRegion::FieldRegionKind:
1393 case MemRegion::ObjCIvarRegionKind:
1394 os <<
"an instance variable of type "
1403 SVal CharVal,
const Expr *Size,
1405 SVal MemVal =
C.getSVal(DstBuffer);
1406 SVal SizeVal =
C.getSVal(Size);
1416 const MemRegion *BR = Offset.
getRegion();
1418 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1422 SValBuilder &svalBuilder =
C.getSValBuilder();
1423 ASTContext &Ctx =
C.getASTContext();
1433 std::tie(StateWholeReg, StateNotWholeReg) =
1434 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1441 std::tie(StateNullChar, StateNonNullChar) =
1444 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1445 !StateNonNullChar) {
1453 State->bindDefaultZero(svalBuilder.
makeLoc(BR),
C.getStackFrame());
1457 State = invalidateDestinationBufferBySize(
1458 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1461 if (StateNullChar && !StateNonNullChar) {
1464 State = setCStringLength(State, MR,
1466 }
else if (!StateNullChar && StateNonNullChar) {
1468 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1469 C.getStackFrame(),
C.blockCount());
1473 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1476 State = setCStringLength(
1477 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1483 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1484 SizeVal,
Size->getType());
1493void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1495 DestinationArgExpr Dest,
1496 SourceArgExpr Source,
bool Restricted,
1497 bool IsMempcpy, CharKind CK)
const {
1498 CurrentFunctionDescription =
"memory copy function";
1501 const StackFrame *SF =
C.getStackFrame();
1502 SVal sizeVal = state->getSVal(
Size.Expression, SF);
1503 QualType sizeTy =
Size.Expression->getType();
1506 std::tie(stateZeroSize, stateNonZeroSize) =
1507 assumeZero(
C, state, sizeVal, sizeTy);
1510 SVal destVal = state->getSVal(Dest.Expression, SF);
1514 if (stateZeroSize && !stateNonZeroSize) {
1515 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), SF, destVal);
1516 C.addTransition(stateZeroSize);
1521 if (stateNonZeroSize) {
1525 state = stateNonZeroSize;
1529 state = checkNonNull(
C, state, Dest, destVal);
1534 SVal srcVal = state->getSVal(Source.Expression, SF);
1538 state = checkNonNull(
C, state, Source, srcVal);
1543 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1544 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1547 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1556 SValBuilder &SvalBuilder =
C.getSValBuilder();
1558 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1559 SVal DestRegCharVal =
1560 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1561 SVal lastElement =
C.getSValBuilder().evalBinOp(
1562 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1566 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1569 state = state->BindExpr(
Call.getOriginExpr(), SF, lastElement);
1573 state = state->BindExpr(
Call.getOriginExpr(), SF, destVal);
1582 state = invalidateDestinationBufferBySize(
1583 C, state, Dest.Expression,
Call.getCFGElementRef(),
1584 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1588 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1589 C.getSVal(Source.Expression));
1591 C.addTransition(state);
1595void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1596 CharKind CK)
const {
1599 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1600 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1601 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1605 constexpr bool IsRestricted =
true;
1606 constexpr bool IsMempcpy =
false;
1607 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1610void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1611 CharKind CK)
const {
1614 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1615 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1616 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1618 constexpr bool IsRestricted =
true;
1619 constexpr bool IsMempcpy =
true;
1620 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1624void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1625 CharKind CK)
const {
1628 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1629 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1630 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1632 constexpr bool IsRestricted =
false;
1633 constexpr bool IsMempcpy =
false;
1634 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1638void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1640 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1641 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1642 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1644 constexpr bool IsRestricted =
false;
1645 constexpr bool IsMempcpy =
false;
1646 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1647 IsMempcpy, CharKind::Regular);
1650void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1651 CharKind CK)
const {
1653 CurrentFunctionDescription =
"memory comparison function";
1655 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1656 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1657 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1660 SValBuilder &Builder =
C.getSValBuilder();
1661 const StackFrame *SF =
C.getStackFrame();
1664 SVal sizeVal = State->getSVal(
Size.Expression, SF);
1665 QualType sizeTy =
Size.Expression->getType();
1668 std::tie(stateZeroSize, stateNonZeroSize) =
1669 assumeZero(
C, State, sizeVal, sizeTy);
1673 if (stateZeroSize) {
1674 State = stateZeroSize;
1675 State = State->BindExpr(
Call.getOriginExpr(), SF,
1676 Builder.makeZeroVal(
Call.getResultType()));
1677 C.addTransition(State);
1681 if (stateNonZeroSize) {
1682 State = stateNonZeroSize;
1686 DefinedOrUnknownSVal LV =
1687 State->getSVal(
Left.Expression, SF).castAs<DefinedOrUnknownSVal>();
1688 DefinedOrUnknownSVal RV =
1689 State->getSVal(
Right.Expression, SF).castAs<DefinedOrUnknownSVal>();
1693 std::tie(SameBuffer, NotSameBuffer) =
1694 State->assume(Builder.evalEQ(State, LV, RV));
1698 if (SameBuffer && !NotSameBuffer) {
1700 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1702 State = SameBuffer->BindExpr(
Call.getOriginExpr(), SF,
1703 Builder.makeZeroVal(
Call.getResultType()));
1704 C.addTransition(State);
1711 assert(NotSameBuffer);
1712 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1713 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1716 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1717 State = State->BindExpr(
Call.getOriginExpr(), SF, CmpV);
1718 C.addTransition(State);
1723void CStringChecker::evalstrLength(CheckerContext &
C,
1724 const CallEvent &
Call)
const {
1726 evalstrLengthCommon(
C,
Call,
false);
1729void CStringChecker::evalstrnLength(CheckerContext &
C,
1730 const CallEvent &
Call)
const {
1732 evalstrLengthCommon(
C,
Call,
true);
1735void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1736 const CallEvent &
Call,
1737 bool IsStrnlen)
const {
1738 CurrentFunctionDescription =
"string length function";
1740 const StackFrame *SF =
C.getStackFrame();
1743 const Expr *maxlenExpr =
Call.getArgExpr(1);
1744 SVal maxlenVal = state->getSVal(maxlenExpr, SF);
1747 std::tie(stateZeroSize, stateNonZeroSize) =
1748 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1752 if (stateZeroSize) {
1753 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1754 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), SF, zero);
1755 C.addTransition(stateZeroSize);
1759 if (!stateNonZeroSize)
1763 state = stateNonZeroSize;
1767 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1768 SVal ArgVal = state->getSVal(Arg.Expression, SF);
1769 state = checkNonNull(
C, state, Arg, ArgVal);
1774 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1781 DefinedOrUnknownSVal result = UnknownVal();
1786 QualType cmpTy =
C.getSValBuilder().getConditionType();
1790 const Expr *maxlenExpr =
Call.getArgExpr(1);
1791 SVal maxlenVal = state->getSVal(maxlenExpr, SF);
1793 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1794 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1796 if (strLengthNL && maxlenValNL) {
1800 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1802 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1803 .castAs<DefinedOrUnknownSVal>());
1805 if (stateStringTooLong && !stateStringNotTooLong) {
1807 result = *maxlenValNL;
1808 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1810 result = *strLengthNL;
1819 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1820 NonLoc resultNL = result.
castAs<NonLoc>();
1823 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1824 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1825 .castAs<DefinedOrUnknownSVal>(),
true);
1829 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1830 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1831 .castAs<DefinedOrUnknownSVal>(),
true);
1837 result = strLength.
castAs<DefinedOrUnknownSVal>();
1842 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1847 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1848 state = state->BindExpr(
Call.getOriginExpr(), SF, result);
1849 C.addTransition(state);
1852void CStringChecker::evalStrcpy(CheckerContext &
C,
1853 const CallEvent &
Call)
const {
1855 evalStrcpyCommon(
C,
Call,
1858 ConcatFnKind::none);
1861void CStringChecker::evalStrncpy(CheckerContext &
C,
1862 const CallEvent &
Call)
const {
1864 evalStrcpyCommon(
C,
Call,
1867 ConcatFnKind::none);
1870void CStringChecker::evalStpcpy(CheckerContext &
C,
1871 const CallEvent &
Call)
const {
1873 evalStrcpyCommon(
C,
Call,
1876 ConcatFnKind::none);
1879void CStringChecker::evalStrlcpy(CheckerContext &
C,
1880 const CallEvent &
Call)
const {
1882 evalStrcpyCommon(
C,
Call,
1889void CStringChecker::evalStrcat(CheckerContext &
C,
1890 const CallEvent &
Call)
const {
1892 evalStrcpyCommon(
C,
Call,
1895 ConcatFnKind::strcat);
1898void CStringChecker::evalStrncat(CheckerContext &
C,
1899 const CallEvent &
Call)
const {
1901 evalStrcpyCommon(
C,
Call,
1904 ConcatFnKind::strcat);
1907void CStringChecker::evalStrlcat(CheckerContext &
C,
1908 const CallEvent &
Call)
const {
1912 evalStrcpyCommon(
C,
Call,
1915 ConcatFnKind::strlcat,
1919void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1920 bool ReturnEnd,
bool IsBounded,
1921 ConcatFnKind appendK,
1922 bool returnPtr)
const {
1923 if (appendK == ConcatFnKind::none)
1924 CurrentFunctionDescription =
"string copy function";
1926 CurrentFunctionDescription =
"string concatenation function";
1929 const StackFrame *SF =
C.getStackFrame();
1932 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1933 SVal DstVal = state->getSVal(Dst.Expression, SF);
1934 state = checkNonNull(
C, state, Dst, DstVal);
1939 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1940 SVal srcVal = state->getSVal(srcExpr.Expression, SF);
1941 state = checkNonNull(
C, state, srcExpr, srcVal);
1946 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1947 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1950 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1951 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1957 SValBuilder &svalBuilder =
C.getSValBuilder();
1964 SVal amountCopied = UnknownVal();
1965 SVal maxLastElementIndex = UnknownVal();
1966 const char *boundWarning =
nullptr;
1970 SizeArgExpr SrcExprAsSizeDummy = {
1971 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1972 state = CheckOverlap(
1974 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1983 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1984 SVal lenVal = state->getSVal(lenExpr.Expression, SF);
1988 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1990 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1994 if (strLengthNL && lenValNL) {
1996 case ConcatFnKind::none:
1997 case ConcatFnKind::strcat: {
2002 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
2004 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
2005 .castAs<DefinedOrUnknownSVal>());
2007 if (stateSourceTooLong && !stateSourceNotTooLong) {
2010 state = stateSourceTooLong;
2011 amountCopied = lenVal;
2013 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
2015 state = stateSourceNotTooLong;
2016 amountCopied = strLength;
2020 case ConcatFnKind::strlcat:
2021 if (!dstStrLengthNL)
2025 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
2026 *dstStrLengthNL, sizeTy);
2030 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
2032 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
2039 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
2042 std::tie(TrueState, FalseState) =
2043 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
2046 if (TrueState && !FalseState) {
2047 amountCopied = strLength;
2051 if (!TrueState && FalseState) {
2052 amountCopied = freeSpace;
2055 if (TrueState && FalseState)
2056 amountCopied = UnknownVal();
2063 case ConcatFnKind::strcat:
2069 if (dstStrLength.isUndef())
2072 if (dstStrLengthNL) {
2074 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2076 boundWarning =
"Size argument is greater than the free space in the "
2077 "destination buffer";
2080 case ConcatFnKind::none:
2081 case ConcatFnKind::strlcat:
2091 std::tie(StateZeroSize, StateNonZeroSize) =
2092 assumeZero(
C, state, *lenValNL, sizeTy);
2095 if (StateZeroSize && !StateNonZeroSize) {
2098 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, DstVal);
2100 if (appendK == ConcatFnKind::none) {
2103 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, strLength);
2107 state, BO_Add, strLength, dstStrLength, sizeTy);
2109 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, retSize);
2112 C.addTransition(StateZeroSize);
2120 maxLastElementIndex =
2121 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2122 boundWarning =
"Size argument is greater than the length of the "
2123 "destination buffer";
2130 amountCopied = strLength;
2138 SVal finalStrLength = UnknownVal();
2139 SVal strlRetVal = UnknownVal();
2141 if (appendK == ConcatFnKind::none && !returnPtr) {
2143 strlRetVal = strLength;
2149 if (appendK != ConcatFnKind::none) {
2152 if (dstStrLength.isUndef())
2155 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2156 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2157 *dstStrLengthNL, sizeTy);
2160 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2163 if (amountCopiedNL && dstStrLengthNL) {
2165 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2169 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2170 *dstStrLengthNL, sizeTy);
2179 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2180 assert(!finalStrLength.
isUndef());
2182 if (std::optional<NonLoc> finalStrLengthNL =
2183 finalStrLength.
getAs<NonLoc>()) {
2184 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2188 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2189 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2195 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2198 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2203 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2213 finalStrLength = amountCopied;
2221 Result = (ReturnEnd ? UnknownVal() : DstVal);
2223 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2234 if (std::optional<loc::MemRegionVal> dstRegVal =
2235 DstVal.
getAs<loc::MemRegionVal>()) {
2236 QualType ptrTy = Dst.Expression->getType();
2240 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2241 SVal maxLastElement =
2242 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2245 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2249 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2255 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2256 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2257 *knownStrLength, ptrTy);
2260 if (!boundWarning) {
2262 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2266 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2272 if (returnPtr && ReturnEnd)
2285 bool CouldAccessOutOfBound =
true;
2286 if (IsBounded && amountCopied.
isUnknown()) {
2287 auto CouldAccessOutOfBoundForSVal =
2288 [&](std::optional<NonLoc> Val) ->
bool {
2291 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2292 Dst.Expression->getType(), *Val,
2293 C.getASTContext().getSizeType());
2296 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2298 if (CouldAccessOutOfBound) {
2300 const Expr *LenExpr =
Call.getArgExpr(2);
2301 SVal LenVal = state->getSVal(LenExpr, SF);
2309 CouldAccessOutOfBound =
2310 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2321 if (CouldAccessOutOfBound)
2322 state = invalidateDestinationBufferBySize(
2323 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2324 amountCopied,
C.getASTContext().getSizeType());
2326 state = invalidateDestinationBufferNeverOverflows(
2327 C, state,
Call.getCFGElementRef(), *dstRegVal);
2331 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2334 if (IsBounded && (appendK == ConcatFnKind::none)) {
2339 if (amountCopied != strLength)
2340 finalStrLength = UnknownVal();
2342 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2350 if (ReturnEnd &&
Result.isUnknown()) {
2355 state = state->BindExpr(
Call.getOriginExpr(), SF,
Result);
2356 C.addTransition(state);
2359void CStringChecker::evalStrxfrm(CheckerContext &
C,
2360 const CallEvent &
Call)
const {
2362 CurrentFunctionDescription =
"locale transformation function";
2365 const StackFrame *SF =
C.getStackFrame();
2366 SValBuilder &SVB =
C.getSValBuilder();
2369 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2370 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2371 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2374 SVal SrcVal = State->getSVal(Source.Expression, SF);
2375 State = checkNonNull(
C, State, Source, SrcVal);
2380 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2388 auto BindReturnAndTransition = [&RetVal, &
Call, SF,
2391 State = State->BindExpr(
Call.getOriginExpr(), SF, RetVal);
2392 C.addTransition(State);
2397 SVal SizeVal = State->getSVal(
Size.Expression, SF);
2398 QualType SizeTy =
Size.Expression->getType();
2400 auto [StateZeroSize, StateSizeNonZero] =
2401 assumeZero(
C, State, SizeVal, SizeTy);
2404 if (!StateZeroSize && !StateSizeNonZero)
2405 return BindReturnAndTransition(State);
2408 if (StateZeroSize && !StateSizeNonZero)
2409 return BindReturnAndTransition(StateZeroSize);
2412 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, SF);
2413 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2414 if (!StateSizeNonZero)
2418 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2419 AccessKind::write, CK_Regular);
2420 if (!StateSizeNonZero)
2425 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2427 .
getAs<DefinedOrUnknownSVal>();
2428 if (!ComparisonVal) {
2430 StateSizeNonZero = invalidateDestinationBufferBySize(
2431 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2432 SizeVal,
Size.Expression->getType());
2433 return BindReturnAndTransition(StateSizeNonZero);
2436 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2440 StateSuccess = invalidateDestinationBufferBySize(
2441 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2442 SizeVal,
Size.Expression->getType());
2443 BindReturnAndTransition(StateSuccess);
2449 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2450 StateFailure = StateFailure->killBinding(*DestLoc);
2452 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, SF);
2455 BindReturnAndTransition(StateFailure);
2459void CStringChecker::evalStrcmp(CheckerContext &
C,
2460 const CallEvent &
Call)
const {
2462 evalStrcmpCommon(
C,
Call,
false,
false);
2465void CStringChecker::evalStrncmp(CheckerContext &
C,
2466 const CallEvent &
Call)
const {
2468 evalStrcmpCommon(
C,
Call,
true,
false);
2471void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2472 const CallEvent &
Call)
const {
2474 evalStrcmpCommon(
C,
Call,
false,
true);
2477void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2478 const CallEvent &
Call)
const {
2480 evalStrcmpCommon(
C,
Call,
true,
true);
2483void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2484 bool IsBounded,
bool IgnoreCase)
const {
2485 CurrentFunctionDescription =
"string comparison function";
2487 const StackFrame *SF =
C.getStackFrame();
2490 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2491 SVal LeftVal = state->getSVal(
Left.Expression, SF);
2492 state = checkNonNull(
C, state, Left, LeftVal);
2497 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2498 SVal RightVal = state->getSVal(
Right.Expression, SF);
2499 state = checkNonNull(
C, state, Right, RightVal);
2504 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2509 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2516 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2517 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2520 SValBuilder &svalBuilder =
C.getSValBuilder();
2521 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2523 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2529 StSameBuf->BindExpr(
Call.getOriginExpr(), SF,
2530 svalBuilder.makeZeroVal(
Call.getResultType()));
2531 C.addTransition(StSameBuf);
2538 assert(StNotSameBuf);
2539 state = StNotSameBuf;
2545 const StringLiteral *LeftStrLiteral =
2546 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2547 const StringLiteral *RightStrLiteral =
2548 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2549 bool canComputeResult =
false;
2550 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2552 if (LeftStrLiteral && RightStrLiteral) {
2553 StringRef LeftStrRef = LeftStrLiteral->
getString();
2554 StringRef RightStrRef = RightStrLiteral->
getString();
2558 const Expr *lenExpr =
Call.getArgExpr(2);
2559 SVal lenVal = state->getSVal(lenExpr, SF);
2562 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2564 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2565 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2566 canComputeResult =
true;
2570 canComputeResult =
true;
2573 if (canComputeResult) {
2575 size_t s1Term = LeftStrRef.find(
'\0');
2576 if (s1Term != StringRef::npos)
2577 LeftStrRef = LeftStrRef.substr(0, s1Term);
2579 size_t s2Term = RightStrRef.find(
'\0');
2580 if (s2Term != StringRef::npos)
2581 RightStrRef = RightStrRef.substr(0, s2Term);
2584 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2585 : LeftStrRef.compare(RightStrRef);
2589 if (compareRes == 0) {
2590 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2593 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2597 SVal compareWithZero =
2598 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2599 svalBuilder.getConditionType());
2600 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2601 state = state->assume(compareWithZeroVal,
true);
2606 state = state->BindExpr(
Call.getOriginExpr(), SF, resultVal);
2609 C.addTransition(state);
2612void CStringChecker::evalStrsep(CheckerContext &
C,
2613 const CallEvent &
Call)
const {
2616 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2618 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2619 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2623 CurrentFunctionDescription =
"strsep()";
2625 const StackFrame *SF =
C.getStackFrame();
2629 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, SF);
2630 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2635 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2636 SVal DelimStrVal = State->getSVal(DelimStr.Expression, SF);
2637 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2641 SValBuilder &SVB =
C.getSValBuilder();
2643 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2645 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2650 State = invalidateDestinationBufferNeverOverflows(
2655 State = State->bindLoc(*SearchStrLoc,
2665 State = State->BindExpr(
Call.getOriginExpr(), SF,
Result);
2666 C.addTransition(State);
2675 SVal SrcVal = State->getSVal(
Call.getArgExpr(0), SF);
2676 return CStringChecker::getStringRefAtRegion(SrcVal.
getAsRegion());
2681 size_t NulPos = Haystack.find(
'\0');
2682 return (NulPos != StringRef::npos) ? Haystack.substr(0, NulPos) : Haystack;
2689 SVal Arg1Val =
C.getState()->getSVal(
Call.getArgExpr(1),
C.getStackFrame());
2690 const llvm::APSInt *CharInt = SVB.
getKnownValue(
C.getState(), Arg1Val);
2692 return std::nullopt;
2693 return static_cast<char>(CharInt->getExtValue());
2700static std::optional<size_t>
2704 return std::nullopt;
2705 return Search(
C,
Call, *Haystack);
2712 StringRef Haystack,
bool Reverse,
2716 return std::nullopt;
2717 StringRef CStr =
getCStr(Haystack);
2720 size_t Pos = Reverse ? CStr.rfind(*Ch) : CStr.find(*Ch);
2721 if (Pos == StringRef::npos && NulOnMiss)
2726void CStringChecker::evalStrchr(CheckerContext &
C,
2727 const CallEvent &
Call)
const {
2728 CurrentFunctionDescription =
"strchr()";
2736void CStringChecker::evalStrrchr(CheckerContext &
C,
2737 const CallEvent &
Call)
const {
2738 CurrentFunctionDescription =
"strrchr()";
2746void CStringChecker::evalStrchrnul(CheckerContext &
C,
2747 const CallEvent &
Call)
const {
2748 CurrentFunctionDescription =
"strchrnul()";
2756void CStringChecker::evalMemchr(CheckerContext &
C,
2757 const CallEvent &
Call)
const {
2758 CurrentFunctionDescription =
"memchr()";
2759 auto Search = [](CheckerContext &
C,
const CallEvent &
Call,
2760 StringRef Haystack) -> std::optional<size_t> {
2762 if (!Ch ||
Call.getNumArgs() < 3)
2763 return std::nullopt;
2764 SValBuilder &SVB =
C.getSValBuilder();
2767 C.getState()->getSVal(
Call.getArgExpr(2),
C.getStackFrame()));
2769 return std::nullopt;
2772 SmallString<64> Buf(Haystack);
2773 Buf.push_back(
'\0');
2774 StringRef Region = StringRef(Buf.data(), Buf.size());
2775 if (N > Region.size())
2776 return std::nullopt;
2777 return Region.substr(0, N).find(*Ch);
2779 evalStrchrCommon(
C,
Call,
true,
2783void CStringChecker::evalStrstr(CheckerContext &
C,
2784 const CallEvent &
Call)
const {
2785 CurrentFunctionDescription =
"strstr()";
2786 auto Search = [](CheckerContext &
C,
const CallEvent &
Call,
2787 StringRef Haystack) -> std::optional<size_t> {
2788 SVal Arg1Val =
C.getState()->getSVal(
Call.getArgExpr(1),
C.getStackFrame());
2789 auto Needle = CStringChecker::getStringRefAtRegion(Arg1Val.
getAsRegion());
2791 return std::nullopt;
2792 StringRef CStr =
getCStr(Haystack);
2793 StringRef CNeedle =
getCStr(*Needle);
2794 return CNeedle.empty() ?
size_t{0} : CStr.find(CNeedle);
2796 evalStrchrCommon(
C,
Call,
true,
2800void CStringChecker::evalStrpbrk(CheckerContext &
C,
2801 const CallEvent &
Call)
const {
2802 CurrentFunctionDescription =
"strpbrk()";
2803 auto Search = [](CheckerContext &
C,
const CallEvent &
Call,
2804 StringRef Haystack) -> std::optional<size_t> {
2805 SVal Arg1Val =
C.getState()->getSVal(
Call.getArgExpr(1),
C.getStackFrame());
2806 auto Accept = CStringChecker::getStringRefAtRegion(Arg1Val.
getAsRegion());
2808 return std::nullopt;
2811 evalStrchrCommon(
C,
Call,
true,
2815void CStringChecker::evalStrchrCommon(CheckerContext &
C,
const CallEvent &
Call,
2817 std::optional<size_t> ConstOffset)
const {
2818 const Expr *CE =
Call.getOriginExpr();
2825 const StackFrame *SF =
C.getStackFrame();
2826 SValBuilder &SVB =
C.getSValBuilder();
2827 ASTContext &Ctx =
C.getASTContext();
2829 SourceArgExpr Src = {{
Call.getArgExpr(0), 0}};
2830 SVal SrcVal = State->getSVal(Src.Expression, SF);
2831 State = checkNonNull(
C, State, Src, SrcVal);
2835 bool MustMatch = ConstOffset && *ConstOffset != StringRef::npos;
2836 bool MustNotMatch = ConstOffset && *ConstOffset == StringRef::npos;
2839 if (CanReturnNull && !MustMatch) {
2842 C.addTransition(NullState);
2849 std::optional<Loc> SrcLoc = SrcVal.
getAs<Loc>();
2852 State = State->BindExpr(CE, SF,
Result);
2853 C.addTransition(State);
2859 NonLoc ConcreteOffset =
2862 Src.Expression->getType());
2863 State = State->BindExpr(CE, SF,
Result);
2864 C.addTransition(State);
2869 auto RemainingExtentBytes =
2874 State = State->assumeInBound(SymOffset, RemainingExtentBytes,
true);
2879 Src.Expression->getType());
2880 State = State->BindExpr(CE, SF,
Result);
2881 C.addTransition(State);
2885void CStringChecker::evalStdCopy(CheckerContext &
C,
2886 const CallEvent &
Call)
const {
2887 evalStdCopyCommon(
C,
Call);
2890void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2891 const CallEvent &
Call)
const {
2892 evalStdCopyCommon(
C,
Call);
2895void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2896 const CallEvent &
Call)
const {
2897 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2902 const StackFrame *SF =
C.getStackFrame();
2910 const Expr *Dst =
Call.getArgExpr(2);
2911 SVal DstVal = State->getSVal(Dst, SF);
2914 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2915 C, State,
Call.getCFGElementRef(), DstVal);
2917 SValBuilder &SVB =
C.getSValBuilder();
2920 State = State->BindExpr(
Call.getOriginExpr(), SF, ResultVal);
2922 C.addTransition(State);
2925void CStringChecker::evalMemset(CheckerContext &
C,
2926 const CallEvent &
Call)
const {
2928 CurrentFunctionDescription =
"memory set function";
2930 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2931 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2932 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2937 const StackFrame *SF =
C.getStackFrame();
2938 SVal SizeVal =
C.getSVal(
Size.Expression);
2939 QualType SizeTy =
Size.Expression->getType();
2942 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2945 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2949 if (ZeroSize && !NonZeroSize) {
2950 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), SF, BufferPtrVal);
2951 C.addTransition(ZeroSize);
2957 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2961 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2968 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2969 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2972 State = State->BindExpr(
Call.getOriginExpr(), SF, BufferPtrVal);
2973 C.addTransition(State);
2976void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2977 CurrentFunctionDescription =
"memory clearance function";
2979 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2980 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2981 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2986 SVal SizeVal =
C.getSVal(
Size.Expression);
2987 QualType SizeTy =
Size.Expression->getType();
2990 std::tie(StateZeroSize, StateNonZeroSize) =
2991 assumeZero(
C, State, SizeVal, SizeTy);
2995 if (StateZeroSize && !StateNonZeroSize) {
2996 C.addTransition(StateZeroSize);
3001 SVal MemVal =
C.getSVal(Buffer.Expression);
3005 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
3009 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
3013 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
3014 Size.Expression,
C, State))
3017 C.addTransition(State);
3020void CStringChecker::evalSprintf(CheckerContext &
C,
3021 const CallEvent &
Call)
const {
3022 CurrentFunctionDescription =
"'sprintf'";
3023 evalSprintfCommon(
C,
Call,
false);
3026void CStringChecker::evalSnprintf(CheckerContext &
C,
3027 const CallEvent &
Call)
const {
3028 CurrentFunctionDescription =
"'snprintf'";
3029 evalSprintfCommon(
C,
Call,
true);
3032void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
3033 bool IsBounded)
const {
3036 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
3038 const auto NumParams =
Call.parameters().size();
3039 if (CE->getNumArgs() < NumParams) {
3044 const auto AllArguments =
3045 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
3046 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
3048 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
3050 if (
const QualType
type = ArgExpr->getType();
3051 !
type->isAnyPointerType() ||
3052 !
type->getPointeeType()->isAnyCharacterType())
3054 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
3057 SizeArgExpr SrcExprAsSizeDummy = {
3058 {Source.Expression, Source.ArgumentIndex}};
3059 State = CheckOverlap(
3061 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
3067 C.addTransition(State);
3074CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
3075 CheckerContext &
C)
const {
3076 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
3080 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
3085 return &CStringChecker::evalStdCopy;
3087 return &CStringChecker::evalStdCopyBackward;
3093 for (
auto I : CE->arguments()) {
3094 QualType
T = I->getType();
3106bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
3123 return C.isDifferent();
3126void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
3130 for (
const auto *I : DS->
decls()) {
3131 const VarDecl *D = dyn_cast<VarDecl>(I);
3145 Loc VarLoc = state->getLValue(D,
C.getStackFrame());
3150 SVal StrVal =
C.getSVal(
Init);
3151 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
3152 DefinedOrUnknownSVal strLength =
3153 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
3155 state = state->set<CStringLength>(MR, strLength);
3158 C.addTransition(state);
3163 ArrayRef<const MemRegion *> ExplicitRegions,
3164 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
3165 const CallEvent *
Call)
const {
3166 CStringLengthTy Entries = state->get<CStringLength>();
3167 if (Entries.isEmpty())
3170 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
3171 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
3174 for (
const MemRegion *MR : Regions) {
3175 Invalidated.insert(MR);
3177 SuperRegions.insert(MR);
3178 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
3179 MR = SR->getSuperRegion();
3180 SuperRegions.insert(MR);
3184 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
3187 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
3189 if (SuperRegions.count(MR)) {
3190 Entries = F.remove(Entries, MR);
3195 const MemRegion *Super = MR;
3196 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
3197 Super = SR->getSuperRegion();
3198 if (Invalidated.count(Super)) {
3199 Entries = F.remove(Entries, MR);
3205 return state->set<CStringLength>(Entries);
3209 SymbolReaper &SR)
const {
3211 CStringLengthTy Entries = state->get<CStringLength>();
3213 for (SVal Len : llvm::make_second_range(Entries)) {
3219void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
3220 CheckerContext &
C)
const {
3222 CStringLengthTy Entries = state->get<CStringLength>();
3223 if (Entries.isEmpty())
3226 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
3227 for (
auto [Reg, Len] : Entries) {
3228 if (
SymbolRef Sym = Len.getAsSymbol()) {
3230 Entries = F.remove(Entries, Reg);
3234 state = state->set<CStringLength>(Entries);
3235 C.addTransition(state);
3238void ento::registerCStringModeling(CheckerManager &Mgr) {
3245bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
3249#define REGISTER_CHECKER(NAME) \
3250 void ento::registerCString##NAME(CheckerManager &Mgr) { \
3251 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
3254 bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \
3264#undef REGISTER_CHECKER
static std::optional< size_t > searchChar(CheckerContext &C, const CallEvent &Call, StringRef Haystack, bool Reverse, bool NulOnMiss)
Search for a character in the null-terminated C string view.
static std::optional< size_t > computeStringOffset(CheckerContext &C, const CallEvent &Call, SearchFn Search)
static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)
static std::optional< char > getSearchChar(CheckerContext &C, const CallEvent &Call)
Try to extract the constant character from the second argument.
static StringRef getCStr(StringRef Haystack)
Get the null-terminated C string view of the haystack.
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx)
static std::optional< StringRef > getHaystack(CheckerContext &C, const CallEvent &Call)
Compute the constant search offset for strchr/strrchr/strchrnul.
std::function< std::optional< size_t >( CheckerContext &, const CallEvent &, StringRef)> SearchFn
Resolve the haystack and delegate to a function-specific search lambda.
#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.
It represents a stack frame of the call stack.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
unsigned getLength() const
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
StringRef getString() const
unsigned getCharByteWidth() 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.
Represents an abstract call to a function or method along a particular path.
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.
virtual const llvm::APSInt * getKnownValue(ProgramStateRef state, SVal val)=0
Evaluates a given SVal.
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.
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.
Top level wrappers for InstallAPI frontend operations.
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