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 &CStringChecker::evalStrchr},
168 {{CDM::CLibraryMaybeHardened, {
"strrchr"}, 2},
169 &CStringChecker::evalStrrchr},
170 {{CDM::CLibraryMaybeHardened, {
"memchr"}, 3},
171 &CStringChecker::evalMemchr},
172 {{CDM::CLibrary, {
"strstr"}, 2}, &CStringChecker::evalStrstr},
173 {{CDM::CLibrary, {
"strpbrk"}, 2}, &CStringChecker::evalStrpbrk},
174 {{CDM::CLibrary, {
"strchrnul"}, 2}, &CStringChecker::evalStrchrnul},
175 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
176 {{CDM::CLibrary, {
"bcmp"}, 3},
177 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
178 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
179 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
180 &CStringChecker::evalBzero},
188 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
189 &CStringChecker::evalSprintf},
190 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
191 &CStringChecker::evalSnprintf},
195 CallDescription StdCopy{CDM::SimpleFunc, {
"std",
"copy"}, 3},
196 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
198 FnCheck identifyCall(
const CallEvent &
Call, CheckerContext &
C)
const;
199 void evalMemcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
200 void evalMempcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
201 void evalMemmove(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
202 void evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const;
203 void evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
205 DestinationArgExpr Dest, SourceArgExpr Source,
206 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
208 void evalMemcmp(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
210 void evalstrLength(CheckerContext &
C,
const CallEvent &
Call)
const;
211 void evalstrnLength(CheckerContext &
C,
const CallEvent &
Call)
const;
212 void evalstrLengthCommon(CheckerContext &
C,
const CallEvent &
Call,
213 bool IsStrnlen =
false)
const;
215 void evalStrcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
216 void evalStrncpy(CheckerContext &
C,
const CallEvent &
Call)
const;
217 void evalStpcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
218 void evalStrlcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
219 void evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
220 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
221 bool returnPtr =
true)
const;
223 void evalStrxfrm(CheckerContext &
C,
const CallEvent &
Call)
const;
225 void evalStrcat(CheckerContext &
C,
const CallEvent &
Call)
const;
226 void evalStrncat(CheckerContext &
C,
const CallEvent &
Call)
const;
227 void evalStrlcat(CheckerContext &
C,
const CallEvent &
Call)
const;
229 void evalStrcmp(CheckerContext &
C,
const CallEvent &
Call)
const;
230 void evalStrncmp(CheckerContext &
C,
const CallEvent &
Call)
const;
231 void evalStrcasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
232 void evalStrncasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
233 void evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
234 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
236 void evalStrsep(CheckerContext &
C,
const CallEvent &
Call)
const;
238 void evalStrchr(CheckerContext &
C,
const CallEvent &
Call)
const;
239 void evalStrrchr(CheckerContext &
C,
const CallEvent &
Call)
const;
240 void evalMemchr(CheckerContext &
C,
const CallEvent &
Call)
const;
241 void evalStrstr(CheckerContext &
C,
const CallEvent &
Call)
const;
242 void evalStrpbrk(CheckerContext &
C,
const CallEvent &
Call)
const;
243 void evalStrchrnul(CheckerContext &
C,
const CallEvent &
Call)
const;
247 void evalStrchrCommon(CheckerContext &
C,
const CallEvent &
Call,
249 std::optional<size_t> ConstOffset)
const;
251 void evalStdCopy(CheckerContext &
C,
const CallEvent &
Call)
const;
252 void evalStdCopyBackward(CheckerContext &
C,
const CallEvent &
Call)
const;
253 void evalStdCopyCommon(CheckerContext &
C,
const CallEvent &
Call)
const;
254 void evalMemset(CheckerContext &
C,
const CallEvent &
Call)
const;
255 void evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const;
257 void evalSprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
258 void evalSnprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
259 void evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
260 bool IsBounded)
const;
263 std::pair<ProgramStateRef , ProgramStateRef >
264 static assumeZero(CheckerContext &
C,
270 static SVal getCStringLengthForRegion(CheckerContext &
C,
275 static const StringLiteral *getStringLiteralFromRegion(
const MemRegion *MR);
277 static std::optional<StringRef> getStringRefAtRegion(
const MemRegion *R);
279 SVal getCStringLength(CheckerContext &
C,
283 bool hypothetical =
false)
const;
285 const StringLiteral *getCStringLiteral(CheckerContext &
C,
294 SVal BufV, SVal SizeV, QualType SizeTy);
302 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
316 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
318 InvalidationTraitOperations);
320 static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
321 const MemRegion *MR);
324 SVal CharE,
const Expr *Size, CheckerContext &
C,
329 AnyArgExpr Arg, SVal l)
const;
333 AnyArgExpr Buffer, SVal Element, SVal Size)
const;
335 AnyArgExpr Buffer, SVal Element,
337 CharKind CK = CharKind::Regular)
const;
339 AnyArgExpr Buffer, SizeArgExpr Size,
341 CharKind CK = CharKind::Regular)
const;
343 SizeArgExpr Size, AnyArgExpr
First,
345 CharKind CK = CharKind::Regular)
const;
346 void emitOverlapBug(CheckerContext &
C,
349 const Stmt *Second)
const;
351 void emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
const Stmt *S,
352 StringRef WarningMsg)
const;
354 const Stmt *S, StringRef WarningMsg)
const;
356 const Stmt *S, StringRef WarningMsg)
const;
358 const Expr *E,
const MemRegion *R,
359 StringRef Msg)
const;
369 SVal BufVal, QualType BufTy, SVal LengthVal,
381std::pair<ProgramStateRef, ProgramStateRef>
384 std::optional<DefinedSVal> val =
V.getAs<DefinedSVal>();
386 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
388 SValBuilder &svalBuilder =
C.getSValBuilder();
389 DefinedOrUnknownSVal zero = svalBuilder.
makeZeroVal(Ty);
390 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
395 AnyArgExpr Arg, SVal l)
const {
401 std::tie(stateNull, stateNonNull) =
402 assumeZero(
C, State, l, Arg.Expression->
getType());
404 if (stateNull && !stateNonNull) {
407 llvm::raw_svector_ostream
OS(buf);
408 assert(!CurrentFunctionDescription.empty());
409 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
410 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
411 << CurrentFunctionDescription;
413 emitNullArgBug(
C, stateNull, Arg.Expression,
OS.str());
419 assert(stateNonNull);
428 if (CK == CharKind::Regular) {
444 if (Offset.isUnknown())
451 Os << Idx << llvm::getOrdinalSuffix(Idx);
456 AnyArgExpr Buffer, SVal Element,
463 SVal BufVal =
C.getSVal(Buffer.Expression);
464 const auto *ER = dyn_cast_or_null<ElementRegion>(BufVal.
getAsRegion());
468 const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
474 if (!SuperR->getValueType()->isArrayType())
477 SValBuilder &SVB =
C.getSValBuilder();
482 std::optional<Loc> FirstElementVal =
484 if (!FirstElementVal)
489 State->getSVal(*FirstElementVal).isUndef()) {
490 llvm::SmallString<258> Buf;
491 llvm::raw_svector_ostream
OS(Buf);
492 OS <<
"The first element of the ";
494 OS <<
" argument is undefined";
495 emitUninitializedReadBug(
C, State, Buffer.Expression,
496 FirstElementVal->getAsRegion(),
OS.str());
527 std::optional<NonLoc> Offset =
537 SVal LastIdx = SVB.
evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);
539 SVal LastElementVal = State->getLValue(ElemTy, LastIdx, BufVal);
544 State->getSVal(LastElementVal.
castAs<Loc>()).isUndef()) {
545 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
552 llvm::SmallString<258> Buf;
553 llvm::raw_svector_ostream
OS(Buf);
554 OS <<
"The last accessed element (at index ";
555 OS << IdxInt->getExtValue();
558 OS <<
" argument is undefined";
559 emitUninitializedReadBug(
C, State, Buffer.Expression,
571 AnyArgExpr Buffer, SVal Element,
584 const auto *ER = dyn_cast<ElementRegion>(R);
589 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
595 DefinedOrUnknownSVal
Size =
598 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
599 if (StOutBound && !StInBound) {
616 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
617 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
628 AnyArgExpr Buffer, SizeArgExpr Size,
629 AccessKind Access, CharKind CK)
const {
634 SValBuilder &svalBuilder =
C.getSValBuilder();
637 QualType SizeTy =
Size.Expression->getType();
638 QualType PtrTy = getCharPtrType(Ctx, CK);
641 SVal BufVal =
C.getSVal(Buffer.Expression);
642 State = checkNonNull(
C, State, Buffer, BufVal);
650 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
658 SVal LengthVal =
C.getSVal(
Size.Expression);
659 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
665 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
666 if (Offset.isUnknown())
668 NonLoc LastOffset = Offset.
castAs<NonLoc>();
671 if (std::optional<Loc> BufLoc = BufStart.
getAs<Loc>()) {
674 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
675 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
676 if (Access == AccessKind::read)
677 State = checkInit(
C, State, Buffer, BufStart, *Length);
690 SizeArgExpr Size, AnyArgExpr
First,
703 if (!
First.Expression->getType()->isAnyPointerType() ||
708 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
713 const StackFrame *SF =
C.getStackFrame();
714 SVal firstVal = state->getSVal(
First.Expression, SF);
715 SVal secondVal = state->getSVal(Second.Expression, SF);
717 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
721 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
726 SValBuilder &svalBuilder =
C.getSValBuilder();
727 std::tie(stateTrue, stateFalse) =
728 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
730 if (stateTrue && !stateFalse) {
733 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
758 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
759 std::optional<DefinedOrUnknownSVal> reverseTest =
760 reverse.
getAs<DefinedOrUnknownSVal>();
764 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
771 std::swap(firstLoc, secondLoc);
774 std::swap(
First, Second);
779 SVal LengthVal = state->getSVal(
Size.Expression, SF);
780 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
787 QualType CharPtrTy = getCharPtrType(Ctx, CK);
789 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
790 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
795 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
797 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
803 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
804 std::optional<DefinedOrUnknownSVal> OverlapTest =
805 Overlap.
getAs<DefinedOrUnknownSVal>();
809 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
811 if (stateTrue && !stateFalse) {
813 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
833void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
835 const Stmt *Second)
const {
837 "Can't emit from a checker that is not enabled!");
838 ExplodedNode *N =
C.generateErrorNode(state);
843 auto report = std::make_unique<PathSensitiveBugReport>(
844 BufferOverlap,
"Arguments must not be overlapping buffers", N);
845 report->addRange(
First->getSourceRange());
848 C.emitReport(std::move(report));
851void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
852 const Stmt *S, StringRef WarningMsg)
const {
854 "Can't emit from a checker that is not enabled!");
855 if (ExplodedNode *N =
C.generateErrorNode(State)) {
857 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
859 if (
const auto *Ex = dyn_cast<Expr>(S))
861 C.emitReport(std::move(
Report));
865void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
867 const Expr *E,
const MemRegion *R,
868 StringRef Msg)
const {
870 "Can't emit from a checker that is not enabled!");
871 if (ExplodedNode *N =
C.generateErrorNode(State)) {
873 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
874 Report->addNote(
"Other elements might also be undefined",
878 Report->addVisitor<NoStoreFuncVisitor>(
R->castAs<SubRegion>());
879 C.emitReport(std::move(
Report));
883void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
885 StringRef WarningMsg)
const {
887 "Can't emit from a checker that is not enabled!");
888 if (ExplodedNode *N =
C.generateErrorNode(State)) {
893 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
895 C.emitReport(std::move(
Report));
899void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
901 StringRef WarningMsg)
const {
903 "Can't emit from a checker that is not enabled!");
904 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
906 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
909 C.emitReport(std::move(
Report));
916 NonLoc right)
const {
921 SValBuilder &svalBuilder =
C.getSValBuilder();
925 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
926 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
930 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
935 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
940 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
943 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
944 *maxMinusRightNL, cmpTy);
946 auto [StateOverflow, StateOkay] =
947 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
949 if (StateOverflow && !StateOkay) {
955 C.addSink(StateOverflow);
970 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
975 case MemRegion::StringRegionKind:
980 case MemRegion::SymbolicRegionKind:
981 case MemRegion::AllocaRegionKind:
982 case MemRegion::NonParamVarRegionKind:
983 case MemRegion::ParamVarRegionKind:
984 case MemRegion::FieldRegionKind:
985 case MemRegion::ObjCIvarRegionKind:
989 case MemRegion::ElementRegionKind:
1003 return state->remove<CStringLength>(MR);
1005 return state->set<CStringLength>(MR, strLength);
1008SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
1011 const MemRegion *MR,
1012 bool hypothetical) {
1013 if (!hypothetical) {
1015 const SVal *Recorded = state->get<CStringLength>(MR);
1021 SValBuilder &svalBuilder =
C.getSValBuilder();
1025 C.getStackFrame(),
C.blockCount());
1027 if (!hypothetical) {
1028 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
1031 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1032 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
1033 std::optional<APSIntPtr> maxLengthInt =
1035 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
1036 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1038 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
1040 state = state->set<CStringLength>(MR, strLength);
1046const StringLiteral *
1047CStringChecker::getStringLiteralFromRegion(
const MemRegion *MR) {
1049 case MemRegion::StringRegionKind:
1051 case MemRegion::NonParamVarRegionKind:
1053 Decl->getType().isConstQualified())
1054 return dyn_cast_or_null<StringLiteral>(
Decl->getInit());
1061std::optional<StringRef>
1062CStringChecker::getStringRefAtRegion(
const MemRegion *R) {
1064 return std::nullopt;
1066 const MemRegion *
Base =
R->StripCasts();
1067 if (
const auto *ER = dyn_cast<ElementRegion>(Base)) {
1068 if (
auto Idx = ER->getIndex().getAs<nonloc::ConcreteInt>()) {
1069 Offset = Idx->getValue().get()->getZExtValue();
1070 Base = ER->getSuperRegion()->StripCasts();
1072 return std::nullopt;
1075 const StringLiteral *Lit = getStringLiteralFromRegion(Base);
1077 return std::nullopt;
1082 return std::nullopt;
1084 if (Offset > S.size())
1085 return std::nullopt;
1086 return S.substr(Offset);
1089SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
1090 const Expr *Ex, SVal Buf,
1091 bool hypothetical)
const {
1097 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
1099 SmallString<120> buf;
1100 llvm::raw_svector_ostream os(buf);
1101 assert(!CurrentFunctionDescription.empty());
1102 os <<
"Argument to " << CurrentFunctionDescription
1103 <<
" is the address of the label '" << Label->getLabel()->getName()
1104 <<
"', which is not a null-terminated string";
1106 emitNotCStringBug(
C, state, Ex, os.str());
1108 return UndefinedVal();
1112 return UnknownVal();
1119 if (
const StringLiteral *StrLit = getStringLiteralFromRegion(MR)) {
1125 SValBuilder &SVB =
C.getSValBuilder();
1130 case MemRegion::StringRegionKind:
1131 case MemRegion::NonParamVarRegionKind:
1132 case MemRegion::SymbolicRegionKind:
1133 case MemRegion::AllocaRegionKind:
1134 case MemRegion::ParamVarRegionKind:
1135 case MemRegion::FieldRegionKind:
1136 case MemRegion::ObjCIvarRegionKind:
1137 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1138 case MemRegion::CompoundLiteralRegionKind:
1140 return UnknownVal();
1141 case MemRegion::ElementRegionKind: {
1146 const SubRegion *SuperReg =
1148 const StringLiteral *StrLit = getStringLiteralFromRegion(SuperReg);
1150 return UnknownVal();
1151 SValBuilder &SVB =
C.getSValBuilder();
1156 if (state->assume(SVB.
evalBinOpNN(state, BO_LE, Idx, LengthVal,
1158 .
castAs<DefinedOrUnknownSVal>(),
1160 return SVB.
evalBinOp(state, BO_Sub, LengthVal, Idx, SizeTy);
1161 return UnknownVal();
1168 SmallString<120> buf;
1169 llvm::raw_svector_ostream os(buf);
1171 assert(!CurrentFunctionDescription.empty());
1172 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1174 if (SummarizeRegion(os,
C.getASTContext(), MR))
1175 os <<
", which is not a null-terminated string";
1177 os <<
"not a null-terminated string";
1179 emitNotCStringBug(
C, state, Ex, os.str());
1181 return UndefinedVal();
1185const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1198 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1206bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1207 SVal BufVal, QualType BufTy,
1208 SVal LengthVal, QualType LengthTy) {
1217 SValBuilder &SB =
C.getSValBuilder();
1218 ASTContext &Ctx =
C.getASTContext();
1222 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1228 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1229 if (Offset.isUnknown())
1231 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1234 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1235 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1239 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1246 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1252 C.getASTContext().CharTy &&
1253 "isFirstBufInBound should only be called with char* ElementRegions");
1260 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1264 return static_cast<bool>(StInBound);
1270 auto InvalidationTraitOperations =
1271 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1272 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1275 if (MemRegion::FieldRegionKind ==
R->getKind() &&
1276 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1284 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1288CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1290 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1291 const MemRegion *
R) {
1295 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1298ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1300 auto InvalidationTraitOperations =
1301 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1302 if (MemRegion::FieldRegionKind ==
R->getKind())
1309 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1316 auto InvalidationTraitOperations =
1317 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1326 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1331 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1333 InvalidationTraitOperations) {
1334 std::optional<Loc> L =
V.getAs<Loc>();
1341 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1342 const MemRegion *
R = MR->getRegion()->
StripCasts();
1346 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1352 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
1353 RegionAndSymbolInvalidationTraits ITraits;
1354 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1356 return State->invalidateRegions(R, Elem,
C.blockCount(), SF,
1357 CausesPointerEscape,
nullptr,
nullptr,
1364 return State->killBinding(*L);
1367bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1368 const MemRegion *MR) {
1370 case MemRegion::FunctionCodeRegionKind: {
1372 os <<
"the address of the function '" << *FD <<
'\'';
1374 os <<
"the address of a function";
1377 case MemRegion::BlockCodeRegionKind:
1380 case MemRegion::BlockDataRegionKind:
1383 case MemRegion::CXXThisRegionKind:
1384 case MemRegion::CXXTempObjectRegionKind:
1385 os <<
"a C++ temp object of type "
1388 case MemRegion::NonParamVarRegionKind:
1391 case MemRegion::ParamVarRegionKind:
1394 case MemRegion::FieldRegionKind:
1397 case MemRegion::ObjCIvarRegionKind:
1398 os <<
"an instance variable of type "
1407 SVal CharVal,
const Expr *Size,
1409 SVal MemVal =
C.getSVal(DstBuffer);
1410 SVal SizeVal =
C.getSVal(Size);
1420 const MemRegion *BR = Offset.
getRegion();
1422 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1426 SValBuilder &svalBuilder =
C.getSValBuilder();
1427 ASTContext &Ctx =
C.getASTContext();
1437 std::tie(StateWholeReg, StateNotWholeReg) =
1438 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1445 std::tie(StateNullChar, StateNonNullChar) =
1448 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1449 !StateNonNullChar) {
1457 State->bindDefaultZero(svalBuilder.
makeLoc(BR),
C.getStackFrame());
1461 State = invalidateDestinationBufferBySize(
1462 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1465 if (StateNullChar && !StateNonNullChar) {
1468 State = setCStringLength(State, MR,
1470 }
else if (!StateNullChar && StateNonNullChar) {
1472 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1473 C.getStackFrame(),
C.blockCount());
1477 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1480 State = setCStringLength(
1481 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1487 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1488 SizeVal,
Size->getType());
1497void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1499 DestinationArgExpr Dest,
1500 SourceArgExpr Source,
bool Restricted,
1501 bool IsMempcpy, CharKind CK)
const {
1502 CurrentFunctionDescription =
"memory copy function";
1505 const StackFrame *SF =
C.getStackFrame();
1506 SVal sizeVal = state->getSVal(
Size.Expression, SF);
1507 QualType sizeTy =
Size.Expression->getType();
1510 std::tie(stateZeroSize, stateNonZeroSize) =
1511 assumeZero(
C, state, sizeVal, sizeTy);
1514 SVal destVal = state->getSVal(Dest.Expression, SF);
1518 if (stateZeroSize && !stateNonZeroSize) {
1519 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), SF, destVal);
1520 C.addTransition(stateZeroSize);
1525 if (stateNonZeroSize) {
1529 state = stateNonZeroSize;
1533 state = checkNonNull(
C, state, Dest, destVal);
1538 SVal srcVal = state->getSVal(Source.Expression, SF);
1542 state = checkNonNull(
C, state, Source, srcVal);
1547 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1548 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1551 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1560 SValBuilder &SvalBuilder =
C.getSValBuilder();
1562 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1563 SVal DestRegCharVal =
1564 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1565 SVal lastElement =
C.getSValBuilder().evalBinOp(
1566 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1570 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1573 state = state->BindExpr(
Call.getOriginExpr(), SF, lastElement);
1577 state = state->BindExpr(
Call.getOriginExpr(), SF, destVal);
1586 state = invalidateDestinationBufferBySize(
1587 C, state, Dest.Expression,
Call.getCFGElementRef(),
1588 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1592 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1593 C.getSVal(Source.Expression));
1595 C.addTransition(state);
1599void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1600 CharKind CK)
const {
1603 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1604 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1605 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1609 constexpr bool IsRestricted =
true;
1610 constexpr bool IsMempcpy =
false;
1611 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1614void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1615 CharKind CK)
const {
1618 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1619 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1620 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1622 constexpr bool IsRestricted =
true;
1623 constexpr bool IsMempcpy =
true;
1624 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1628void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1629 CharKind CK)
const {
1632 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1633 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1634 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1636 constexpr bool IsRestricted =
false;
1637 constexpr bool IsMempcpy =
false;
1638 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1642void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1644 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1645 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1646 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1648 constexpr bool IsRestricted =
false;
1649 constexpr bool IsMempcpy =
false;
1650 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1651 IsMempcpy, CharKind::Regular);
1654void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1655 CharKind CK)
const {
1657 CurrentFunctionDescription =
"memory comparison function";
1659 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1660 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1661 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1664 SValBuilder &Builder =
C.getSValBuilder();
1665 const StackFrame *SF =
C.getStackFrame();
1668 SVal sizeVal = State->getSVal(
Size.Expression, SF);
1669 QualType sizeTy =
Size.Expression->getType();
1672 std::tie(stateZeroSize, stateNonZeroSize) =
1673 assumeZero(
C, State, sizeVal, sizeTy);
1677 if (stateZeroSize) {
1678 State = stateZeroSize;
1679 State = State->BindExpr(
Call.getOriginExpr(), SF,
1680 Builder.makeZeroVal(
Call.getResultType()));
1681 C.addTransition(State);
1685 if (stateNonZeroSize) {
1686 State = stateNonZeroSize;
1690 DefinedOrUnknownSVal LV =
1691 State->getSVal(
Left.Expression, SF).castAs<DefinedOrUnknownSVal>();
1692 DefinedOrUnknownSVal RV =
1693 State->getSVal(
Right.Expression, SF).castAs<DefinedOrUnknownSVal>();
1697 std::tie(SameBuffer, NotSameBuffer) =
1698 State->assume(Builder.evalEQ(State, LV, RV));
1702 if (SameBuffer && !NotSameBuffer) {
1704 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1706 State = SameBuffer->BindExpr(
Call.getOriginExpr(), SF,
1707 Builder.makeZeroVal(
Call.getResultType()));
1708 C.addTransition(State);
1715 assert(NotSameBuffer);
1716 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1717 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1720 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1721 State = State->BindExpr(
Call.getOriginExpr(), SF, CmpV);
1722 C.addTransition(State);
1727void CStringChecker::evalstrLength(CheckerContext &
C,
1728 const CallEvent &
Call)
const {
1730 evalstrLengthCommon(
C,
Call,
false);
1733void CStringChecker::evalstrnLength(CheckerContext &
C,
1734 const CallEvent &
Call)
const {
1736 evalstrLengthCommon(
C,
Call,
true);
1739void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1740 const CallEvent &
Call,
1741 bool IsStrnlen)
const {
1742 CurrentFunctionDescription =
"string length function";
1744 const StackFrame *SF =
C.getStackFrame();
1747 const Expr *maxlenExpr =
Call.getArgExpr(1);
1748 SVal maxlenVal = state->getSVal(maxlenExpr, SF);
1751 std::tie(stateZeroSize, stateNonZeroSize) =
1752 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1756 if (stateZeroSize) {
1757 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1758 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), SF, zero);
1759 C.addTransition(stateZeroSize);
1763 if (!stateNonZeroSize)
1767 state = stateNonZeroSize;
1771 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1772 SVal ArgVal = state->getSVal(Arg.Expression, SF);
1773 state = checkNonNull(
C, state, Arg, ArgVal);
1778 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1785 DefinedOrUnknownSVal result = UnknownVal();
1790 QualType cmpTy =
C.getSValBuilder().getConditionType();
1794 const Expr *maxlenExpr =
Call.getArgExpr(1);
1795 SVal maxlenVal = state->getSVal(maxlenExpr, SF);
1797 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1798 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1800 if (strLengthNL && maxlenValNL) {
1804 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1806 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1807 .castAs<DefinedOrUnknownSVal>());
1809 if (stateStringTooLong && !stateStringNotTooLong) {
1811 result = *maxlenValNL;
1812 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1814 result = *strLengthNL;
1823 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1824 NonLoc resultNL = result.
castAs<NonLoc>();
1827 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1828 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1829 .castAs<DefinedOrUnknownSVal>(),
true);
1833 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1834 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1835 .castAs<DefinedOrUnknownSVal>(),
true);
1841 result = strLength.
castAs<DefinedOrUnknownSVal>();
1846 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1851 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1852 state = state->BindExpr(
Call.getOriginExpr(), SF, result);
1853 C.addTransition(state);
1856void CStringChecker::evalStrcpy(CheckerContext &
C,
1857 const CallEvent &
Call)
const {
1859 evalStrcpyCommon(
C,
Call,
1862 ConcatFnKind::none);
1865void CStringChecker::evalStrncpy(CheckerContext &
C,
1866 const CallEvent &
Call)
const {
1868 evalStrcpyCommon(
C,
Call,
1871 ConcatFnKind::none);
1874void CStringChecker::evalStpcpy(CheckerContext &
C,
1875 const CallEvent &
Call)
const {
1877 evalStrcpyCommon(
C,
Call,
1880 ConcatFnKind::none);
1883void CStringChecker::evalStrlcpy(CheckerContext &
C,
1884 const CallEvent &
Call)
const {
1886 evalStrcpyCommon(
C,
Call,
1893void CStringChecker::evalStrcat(CheckerContext &
C,
1894 const CallEvent &
Call)
const {
1896 evalStrcpyCommon(
C,
Call,
1899 ConcatFnKind::strcat);
1902void CStringChecker::evalStrncat(CheckerContext &
C,
1903 const CallEvent &
Call)
const {
1905 evalStrcpyCommon(
C,
Call,
1908 ConcatFnKind::strcat);
1911void CStringChecker::evalStrlcat(CheckerContext &
C,
1912 const CallEvent &
Call)
const {
1916 evalStrcpyCommon(
C,
Call,
1919 ConcatFnKind::strlcat,
1923void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1924 bool ReturnEnd,
bool IsBounded,
1925 ConcatFnKind appendK,
1926 bool returnPtr)
const {
1927 if (appendK == ConcatFnKind::none)
1928 CurrentFunctionDescription =
"string copy function";
1930 CurrentFunctionDescription =
"string concatenation function";
1933 const StackFrame *SF =
C.getStackFrame();
1936 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1937 SVal DstVal = state->getSVal(Dst.Expression, SF);
1938 state = checkNonNull(
C, state, Dst, DstVal);
1943 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1944 SVal srcVal = state->getSVal(srcExpr.Expression, SF);
1945 state = checkNonNull(
C, state, srcExpr, srcVal);
1950 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1951 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1954 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1955 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1961 SValBuilder &svalBuilder =
C.getSValBuilder();
1968 SVal amountCopied = UnknownVal();
1969 SVal maxLastElementIndex = UnknownVal();
1970 const char *boundWarning =
nullptr;
1974 SizeArgExpr SrcExprAsSizeDummy = {
1975 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1976 state = CheckOverlap(
1978 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1987 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1988 SVal lenVal = state->getSVal(lenExpr.Expression, SF);
1992 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1994 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1998 if (strLengthNL && lenValNL) {
2000 case ConcatFnKind::none:
2001 case ConcatFnKind::strcat: {
2006 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
2008 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
2009 .castAs<DefinedOrUnknownSVal>());
2011 if (stateSourceTooLong && !stateSourceNotTooLong) {
2014 state = stateSourceTooLong;
2015 amountCopied = lenVal;
2017 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
2019 state = stateSourceNotTooLong;
2020 amountCopied = strLength;
2024 case ConcatFnKind::strlcat:
2025 if (!dstStrLengthNL)
2029 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
2030 *dstStrLengthNL, sizeTy);
2034 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
2036 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
2043 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
2046 std::tie(TrueState, FalseState) =
2047 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
2050 if (TrueState && !FalseState) {
2051 amountCopied = strLength;
2055 if (!TrueState && FalseState) {
2056 amountCopied = freeSpace;
2059 if (TrueState && FalseState)
2060 amountCopied = UnknownVal();
2067 case ConcatFnKind::strcat:
2073 if (dstStrLength.isUndef())
2076 if (dstStrLengthNL) {
2078 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2080 boundWarning =
"Size argument is greater than the free space in the "
2081 "destination buffer";
2084 case ConcatFnKind::none:
2085 case ConcatFnKind::strlcat:
2095 std::tie(StateZeroSize, StateNonZeroSize) =
2096 assumeZero(
C, state, *lenValNL, sizeTy);
2099 if (StateZeroSize && !StateNonZeroSize) {
2102 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, DstVal);
2104 if (appendK == ConcatFnKind::none) {
2107 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, strLength);
2111 state, BO_Add, strLength, dstStrLength, sizeTy);
2113 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, retSize);
2116 C.addTransition(StateZeroSize);
2124 maxLastElementIndex =
2125 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2126 boundWarning =
"Size argument is greater than the length of the "
2127 "destination buffer";
2134 amountCopied = strLength;
2142 SVal finalStrLength = UnknownVal();
2143 SVal strlRetVal = UnknownVal();
2145 if (appendK == ConcatFnKind::none && !returnPtr) {
2147 strlRetVal = strLength;
2153 if (appendK != ConcatFnKind::none) {
2156 if (dstStrLength.isUndef())
2159 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2160 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2161 *dstStrLengthNL, sizeTy);
2164 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2167 if (amountCopiedNL && dstStrLengthNL) {
2169 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2173 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2174 *dstStrLengthNL, sizeTy);
2183 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2184 assert(!finalStrLength.
isUndef());
2186 if (std::optional<NonLoc> finalStrLengthNL =
2187 finalStrLength.
getAs<NonLoc>()) {
2188 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2192 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2193 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2199 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2202 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2207 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2217 finalStrLength = amountCopied;
2225 Result = (ReturnEnd ? UnknownVal() : DstVal);
2227 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2238 if (std::optional<loc::MemRegionVal> dstRegVal =
2239 DstVal.
getAs<loc::MemRegionVal>()) {
2240 QualType ptrTy = Dst.Expression->getType();
2244 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2245 SVal maxLastElement =
2246 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2249 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2253 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2259 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2260 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2261 *knownStrLength, ptrTy);
2264 if (!boundWarning) {
2266 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2270 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2276 if (returnPtr && ReturnEnd)
2289 bool CouldAccessOutOfBound =
true;
2290 if (IsBounded && amountCopied.
isUnknown()) {
2291 auto CouldAccessOutOfBoundForSVal =
2292 [&](std::optional<NonLoc> Val) ->
bool {
2295 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2296 Dst.Expression->getType(), *Val,
2297 C.getASTContext().getSizeType());
2300 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2302 if (CouldAccessOutOfBound) {
2304 const Expr *LenExpr =
Call.getArgExpr(2);
2305 SVal LenVal = state->getSVal(LenExpr, SF);
2313 CouldAccessOutOfBound =
2314 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2325 if (CouldAccessOutOfBound)
2326 state = invalidateDestinationBufferBySize(
2327 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2328 amountCopied,
C.getASTContext().getSizeType());
2330 state = invalidateDestinationBufferNeverOverflows(
2331 C, state,
Call.getCFGElementRef(), *dstRegVal);
2335 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2338 if (IsBounded && (appendK == ConcatFnKind::none)) {
2343 if (amountCopied != strLength)
2344 finalStrLength = UnknownVal();
2346 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2354 if (ReturnEnd &&
Result.isUnknown()) {
2359 state = state->BindExpr(
Call.getOriginExpr(), SF,
Result);
2360 C.addTransition(state);
2363void CStringChecker::evalStrxfrm(CheckerContext &
C,
2364 const CallEvent &
Call)
const {
2366 CurrentFunctionDescription =
"locale transformation function";
2369 const StackFrame *SF =
C.getStackFrame();
2370 SValBuilder &SVB =
C.getSValBuilder();
2373 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2374 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2375 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2378 SVal SrcVal = State->getSVal(Source.Expression, SF);
2379 State = checkNonNull(
C, State, Source, SrcVal);
2384 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2392 auto BindReturnAndTransition = [&RetVal, &
Call, SF,
2395 State = State->BindExpr(
Call.getOriginExpr(), SF, RetVal);
2396 C.addTransition(State);
2401 SVal SizeVal = State->getSVal(
Size.Expression, SF);
2402 QualType SizeTy =
Size.Expression->getType();
2404 auto [StateZeroSize, StateSizeNonZero] =
2405 assumeZero(
C, State, SizeVal, SizeTy);
2408 if (!StateZeroSize && !StateSizeNonZero)
2409 return BindReturnAndTransition(State);
2412 if (StateZeroSize && !StateSizeNonZero)
2413 return BindReturnAndTransition(StateZeroSize);
2416 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, SF);
2417 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2418 if (!StateSizeNonZero)
2422 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2423 AccessKind::write, CK_Regular);
2424 if (!StateSizeNonZero)
2429 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2431 .
getAs<DefinedOrUnknownSVal>();
2432 if (!ComparisonVal) {
2434 StateSizeNonZero = invalidateDestinationBufferBySize(
2435 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2436 SizeVal,
Size.Expression->getType());
2437 return BindReturnAndTransition(StateSizeNonZero);
2440 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2444 StateSuccess = invalidateDestinationBufferBySize(
2445 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2446 SizeVal,
Size.Expression->getType());
2447 BindReturnAndTransition(StateSuccess);
2453 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2454 StateFailure = StateFailure->killBinding(*DestLoc);
2456 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, SF);
2459 BindReturnAndTransition(StateFailure);
2463void CStringChecker::evalStrcmp(CheckerContext &
C,
2464 const CallEvent &
Call)
const {
2466 evalStrcmpCommon(
C,
Call,
false,
false);
2469void CStringChecker::evalStrncmp(CheckerContext &
C,
2470 const CallEvent &
Call)
const {
2472 evalStrcmpCommon(
C,
Call,
true,
false);
2475void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2476 const CallEvent &
Call)
const {
2478 evalStrcmpCommon(
C,
Call,
false,
true);
2481void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2482 const CallEvent &
Call)
const {
2484 evalStrcmpCommon(
C,
Call,
true,
true);
2487void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2488 bool IsBounded,
bool IgnoreCase)
const {
2489 CurrentFunctionDescription =
"string comparison function";
2491 const StackFrame *SF =
C.getStackFrame();
2494 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2495 SVal LeftVal = state->getSVal(
Left.Expression, SF);
2496 state = checkNonNull(
C, state, Left, LeftVal);
2501 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2502 SVal RightVal = state->getSVal(
Right.Expression, SF);
2503 state = checkNonNull(
C, state, Right, RightVal);
2508 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2513 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2520 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2521 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2524 SValBuilder &svalBuilder =
C.getSValBuilder();
2525 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2527 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2533 StSameBuf->BindExpr(
Call.getOriginExpr(), SF,
2534 svalBuilder.makeZeroVal(
Call.getResultType()));
2535 C.addTransition(StSameBuf);
2542 assert(StNotSameBuf);
2543 state = StNotSameBuf;
2549 const StringLiteral *LeftStrLiteral =
2550 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2551 const StringLiteral *RightStrLiteral =
2552 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2553 bool canComputeResult =
false;
2554 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2556 if (LeftStrLiteral && RightStrLiteral) {
2557 StringRef LeftStrRef = LeftStrLiteral->
getString();
2558 StringRef RightStrRef = RightStrLiteral->
getString();
2562 const Expr *lenExpr =
Call.getArgExpr(2);
2563 SVal lenVal = state->getSVal(lenExpr, SF);
2566 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2568 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2569 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2570 canComputeResult =
true;
2574 canComputeResult =
true;
2577 if (canComputeResult) {
2579 size_t s1Term = LeftStrRef.find(
'\0');
2580 if (s1Term != StringRef::npos)
2581 LeftStrRef = LeftStrRef.substr(0, s1Term);
2583 size_t s2Term = RightStrRef.find(
'\0');
2584 if (s2Term != StringRef::npos)
2585 RightStrRef = RightStrRef.substr(0, s2Term);
2588 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2589 : LeftStrRef.compare(RightStrRef);
2593 if (compareRes == 0) {
2594 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2597 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2601 SVal compareWithZero =
2602 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2603 svalBuilder.getConditionType());
2604 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2605 state = state->assume(compareWithZeroVal,
true);
2610 state = state->BindExpr(
Call.getOriginExpr(), SF, resultVal);
2613 C.addTransition(state);
2616void CStringChecker::evalStrsep(CheckerContext &
C,
2617 const CallEvent &
Call)
const {
2620 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2622 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2623 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2627 CurrentFunctionDescription =
"strsep()";
2629 const StackFrame *SF =
C.getStackFrame();
2633 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, SF);
2634 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2639 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2640 SVal DelimStrVal = State->getSVal(DelimStr.Expression, SF);
2641 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2645 SValBuilder &SVB =
C.getSValBuilder();
2647 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2649 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2654 State = invalidateDestinationBufferNeverOverflows(
2659 State = State->bindLoc(*SearchStrLoc,
2669 State = State->BindExpr(
Call.getOriginExpr(), SF,
Result);
2670 C.addTransition(State);
2679 SVal SrcVal = State->getSVal(
Call.getArgExpr(0), SF);
2680 return CStringChecker::getStringRefAtRegion(SrcVal.
getAsRegion());
2685 size_t NulPos = Haystack.find(
'\0');
2686 return (NulPos != StringRef::npos) ? Haystack.substr(0, NulPos) : Haystack;
2693 SVal Arg1Val =
C.getState()->getSVal(
Call.getArgExpr(1),
C.getStackFrame());
2694 const llvm::APSInt *CharInt = SVB.
getKnownValue(
C.getState(), Arg1Val);
2696 return std::nullopt;
2697 return static_cast<char>(CharInt->getExtValue());
2704static std::optional<size_t>
2708 return std::nullopt;
2709 return Search(
C,
Call, *Haystack);
2716 StringRef Haystack,
bool Reverse,
2720 return std::nullopt;
2721 StringRef CStr =
getCStr(Haystack);
2724 size_t Pos = Reverse ? CStr.rfind(*Ch) : CStr.find(*Ch);
2725 if (Pos == StringRef::npos && NulOnMiss)
2730void CStringChecker::evalStrchr(CheckerContext &
C,
2731 const CallEvent &
Call)
const {
2732 CurrentFunctionDescription =
"strchr()";
2740void CStringChecker::evalStrrchr(CheckerContext &
C,
2741 const CallEvent &
Call)
const {
2742 CurrentFunctionDescription =
"strrchr()";
2750void CStringChecker::evalStrchrnul(CheckerContext &
C,
2751 const CallEvent &
Call)
const {
2752 CurrentFunctionDescription =
"strchrnul()";
2760void CStringChecker::evalMemchr(CheckerContext &
C,
2761 const CallEvent &
Call)
const {
2762 CurrentFunctionDescription =
"memchr()";
2763 auto Search = [](CheckerContext &
C,
const CallEvent &
Call,
2764 StringRef Haystack) -> std::optional<size_t> {
2766 if (!Ch ||
Call.getNumArgs() < 3)
2767 return std::nullopt;
2768 SValBuilder &SVB =
C.getSValBuilder();
2771 C.getState()->getSVal(
Call.getArgExpr(2),
C.getStackFrame()));
2773 return std::nullopt;
2776 SmallString<64> Buf(Haystack);
2777 Buf.push_back(
'\0');
2778 StringRef Region = StringRef(Buf.data(), Buf.size());
2779 if (N > Region.size())
2780 return std::nullopt;
2781 return Region.substr(0, N).find(*Ch);
2783 evalStrchrCommon(
C,
Call,
true,
2787void CStringChecker::evalStrstr(CheckerContext &
C,
2788 const CallEvent &
Call)
const {
2789 CurrentFunctionDescription =
"strstr()";
2790 auto Search = [](CheckerContext &
C,
const CallEvent &
Call,
2791 StringRef Haystack) -> std::optional<size_t> {
2792 SVal Arg1Val =
C.getState()->getSVal(
Call.getArgExpr(1),
C.getStackFrame());
2793 auto Needle = CStringChecker::getStringRefAtRegion(Arg1Val.
getAsRegion());
2795 return std::nullopt;
2796 StringRef CStr =
getCStr(Haystack);
2797 StringRef CNeedle =
getCStr(*Needle);
2798 return CNeedle.empty() ?
size_t{0} : CStr.find(CNeedle);
2800 evalStrchrCommon(
C,
Call,
true,
2804void CStringChecker::evalStrpbrk(CheckerContext &
C,
2805 const CallEvent &
Call)
const {
2806 CurrentFunctionDescription =
"strpbrk()";
2807 auto Search = [](CheckerContext &
C,
const CallEvent &
Call,
2808 StringRef Haystack) -> std::optional<size_t> {
2809 SVal Arg1Val =
C.getState()->getSVal(
Call.getArgExpr(1),
C.getStackFrame());
2810 auto Accept = CStringChecker::getStringRefAtRegion(Arg1Val.
getAsRegion());
2812 return std::nullopt;
2815 evalStrchrCommon(
C,
Call,
true,
2819void CStringChecker::evalStrchrCommon(CheckerContext &
C,
const CallEvent &
Call,
2821 std::optional<size_t> ConstOffset)
const {
2822 const Expr *CE =
Call.getOriginExpr();
2829 const StackFrame *SF =
C.getStackFrame();
2830 SValBuilder &SVB =
C.getSValBuilder();
2831 ASTContext &Ctx =
C.getASTContext();
2833 SourceArgExpr Src = {{
Call.getArgExpr(0), 0}};
2834 SVal SrcVal = State->getSVal(Src.Expression, SF);
2835 State = checkNonNull(
C, State, Src, SrcVal);
2839 bool MustMatch = ConstOffset && *ConstOffset != StringRef::npos;
2840 bool MustNotMatch = ConstOffset && *ConstOffset == StringRef::npos;
2843 if (CanReturnNull && !MustMatch) {
2846 C.addTransition(NullState);
2853 std::optional<Loc> SrcLoc = SrcVal.
getAs<Loc>();
2856 State = State->BindExpr(CE, SF,
Result);
2857 C.addTransition(State);
2863 NonLoc ConcreteOffset =
2866 Src.Expression->getType());
2867 State = State->BindExpr(CE, SF,
Result);
2868 C.addTransition(State);
2873 auto RemainingExtentBytes =
2878 State = State->assumeInBound(SymOffset, RemainingExtentBytes,
true);
2883 Src.Expression->getType());
2884 State = State->BindExpr(CE, SF,
Result);
2885 C.addTransition(State);
2889void CStringChecker::evalStdCopy(CheckerContext &
C,
2890 const CallEvent &
Call)
const {
2891 evalStdCopyCommon(
C,
Call);
2894void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2895 const CallEvent &
Call)
const {
2896 evalStdCopyCommon(
C,
Call);
2899void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2900 const CallEvent &
Call)
const {
2901 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2906 const StackFrame *SF =
C.getStackFrame();
2914 const Expr *Dst =
Call.getArgExpr(2);
2915 SVal DstVal = State->getSVal(Dst, SF);
2918 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2919 C, State,
Call.getCFGElementRef(), DstVal);
2921 SValBuilder &SVB =
C.getSValBuilder();
2924 State = State->BindExpr(
Call.getOriginExpr(), SF, ResultVal);
2926 C.addTransition(State);
2929void CStringChecker::evalMemset(CheckerContext &
C,
2930 const CallEvent &
Call)
const {
2932 CurrentFunctionDescription =
"memory set function";
2934 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2935 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2936 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2941 const StackFrame *SF =
C.getStackFrame();
2942 SVal SizeVal =
C.getSVal(
Size.Expression);
2943 QualType SizeTy =
Size.Expression->getType();
2946 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2949 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2953 if (ZeroSize && !NonZeroSize) {
2954 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), SF, BufferPtrVal);
2955 C.addTransition(ZeroSize);
2961 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2965 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2972 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2973 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2976 State = State->BindExpr(
Call.getOriginExpr(), SF, BufferPtrVal);
2977 C.addTransition(State);
2980void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2981 CurrentFunctionDescription =
"memory clearance function";
2983 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2984 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2985 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2990 SVal SizeVal =
C.getSVal(
Size.Expression);
2991 QualType SizeTy =
Size.Expression->getType();
2994 std::tie(StateZeroSize, StateNonZeroSize) =
2995 assumeZero(
C, State, SizeVal, SizeTy);
2999 if (StateZeroSize && !StateNonZeroSize) {
3000 C.addTransition(StateZeroSize);
3005 SVal MemVal =
C.getSVal(Buffer.Expression);
3009 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
3013 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
3017 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
3018 Size.Expression,
C, State))
3021 C.addTransition(State);
3024void CStringChecker::evalSprintf(CheckerContext &
C,
3025 const CallEvent &
Call)
const {
3026 CurrentFunctionDescription =
"'sprintf'";
3027 evalSprintfCommon(
C,
Call,
false);
3030void CStringChecker::evalSnprintf(CheckerContext &
C,
3031 const CallEvent &
Call)
const {
3032 CurrentFunctionDescription =
"'snprintf'";
3033 evalSprintfCommon(
C,
Call,
true);
3036void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
3037 bool IsBounded)
const {
3040 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
3042 const auto NumParams =
Call.parameters().size();
3043 if (CE->getNumArgs() < NumParams) {
3048 const auto AllArguments =
3049 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
3050 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
3052 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
3054 if (
const QualType
type = ArgExpr->getType();
3055 !
type->isAnyPointerType() ||
3056 !
type->getPointeeType()->isAnyCharacterType())
3058 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
3061 SizeArgExpr SrcExprAsSizeDummy = {
3062 {Source.Expression, Source.ArgumentIndex}};
3063 State = CheckOverlap(
3065 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
3071 C.addTransition(State);
3078CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
3079 CheckerContext &
C)
const {
3080 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
3084 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
3089 return &CStringChecker::evalStdCopy;
3091 return &CStringChecker::evalStdCopyBackward;
3097 for (
auto I : CE->arguments()) {
3098 QualType
T = I->getType();
3103 const FnCheck *Callback = Callbacks.lookup(
Call);
3110bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
3111 FnCheck Callback = identifyCall(
Call,
C);
3119 Callback(
this,
C,
Call);
3127 return C.isDifferent();
3130void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
3134 for (
const auto *I : DS->
decls()) {
3135 const VarDecl *D = dyn_cast<VarDecl>(I);
3149 Loc VarLoc = state->getLValue(D,
C.getStackFrame());
3154 SVal StrVal =
C.getSVal(
Init);
3155 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
3156 DefinedOrUnknownSVal strLength =
3157 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
3159 state = state->set<CStringLength>(MR, strLength);
3162 C.addTransition(state);
3167 ArrayRef<const MemRegion *> ExplicitRegions,
3168 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
3169 const CallEvent *
Call)
const {
3170 CStringLengthTy Entries = state->get<CStringLength>();
3171 if (Entries.isEmpty())
3174 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
3175 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
3178 for (
const MemRegion *MR : Regions) {
3179 Invalidated.insert(MR);
3181 SuperRegions.insert(MR);
3182 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
3183 MR = SR->getSuperRegion();
3184 SuperRegions.insert(MR);
3188 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
3191 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
3193 if (SuperRegions.count(MR)) {
3194 Entries = F.remove(Entries, MR);
3199 const MemRegion *Super = MR;
3200 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
3201 Super = SR->getSuperRegion();
3202 if (Invalidated.count(Super)) {
3203 Entries = F.remove(Entries, MR);
3209 return state->set<CStringLength>(Entries);
3213 SymbolReaper &SR)
const {
3215 CStringLengthTy Entries = state->get<CStringLength>();
3217 for (SVal Len : llvm::make_second_range(Entries)) {
3223void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
3224 CheckerContext &
C)
const {
3226 CStringLengthTy Entries = state->get<CStringLength>();
3227 if (Entries.isEmpty())
3230 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
3231 for (
auto [Reg, Len] : Entries) {
3232 if (
SymbolRef Sym = Len.getAsSymbol()) {
3234 Entries = F.remove(Entries, Reg);
3238 state = state->set<CStringLength>(Entries);
3239 C.addTransition(state);
3242void ento::registerCStringModeling(CheckerManager &Mgr) {
3249bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
3253#define REGISTER_CHECKER(NAME) \
3254 void ento::registerCString##NAME(CheckerManager &Mgr) { \
3255 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
3258 bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \
3268#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.
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