29#include "llvm/ADT/APSInt.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/Support/raw_ostream.h"
38using namespace std::placeholders;
42 const Expr *Expression;
43 unsigned ArgumentIndex;
45struct SourceArgExpr : AnyArgExpr {};
46struct DestinationArgExpr : AnyArgExpr {};
47struct SizeArgExpr : AnyArgExpr {};
50enum class AccessKind { write, read };
52static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
55 llvm::raw_svector_ostream Os(Message);
59 << &FunctionDescription.data()[1];
61 if (Access == AccessKind::write) {
62 Os <<
" overflows the destination buffer";
64 Os <<
" accesses out-of-bound array element";
70enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
72enum class CharKind { Regular = 0,
Wide };
73constexpr CharKind CK_Regular = CharKind::Regular;
74constexpr CharKind CK_Wide = CharKind::Wide;
83 check::LiveSymbols, check::DeadSymbols,
84 check::RegionChanges> {
85 mutable const char *CurrentFunctionDescription =
nullptr;
93 CheckerFrontendWithBugType OutOfBounds{
"Out-of-bound array access"};
95 "Improper arguments"};
97 CheckerFrontendWithBugType UninitializedRead{
98 "Accessing unitialized/garbage values"};
100 StringRef getDebugTag()
const override {
return "MallocChecker"; }
102 static void *getTag() {
static int tag;
return &tag; }
104 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
105 void checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const;
107 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &
C)
const;
112 ArrayRef<const MemRegion *> ExplicitRegions,
113 ArrayRef<const MemRegion *> Regions,
114 const LocationContext *LCtx,
115 const CallEvent *
Call)
const;
117 using FnCheck =
std::function<void(
const CStringChecker *, CheckerContext &,
120 CallDescriptionMap<FnCheck> Callbacks = {
121 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
122 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
123 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
124 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
125 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
126 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
127 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
128 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
129 {{CDM::CLibrary, {
"memcmp"}, 3},
130 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
131 {{CDM::CLibrary, {
"wmemcmp"}, 3},
132 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
133 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
134 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
135 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
136 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
137 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
138 &CStringChecker::evalMemset},
139 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
141 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
142 &CStringChecker::evalStrcpy},
143 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
144 &CStringChecker::evalStrncpy},
145 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
146 &CStringChecker::evalStpcpy},
147 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
148 &CStringChecker::evalStrlcpy},
149 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
150 &CStringChecker::evalStrcat},
151 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
152 &CStringChecker::evalStrncat},
153 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
154 &CStringChecker::evalStrlcat},
155 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
156 &CStringChecker::evalstrLength},
157 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
158 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
159 &CStringChecker::evalstrnLength},
160 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
161 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
162 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
163 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
164 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
165 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
166 {{CDM::CLibrary, {
"strxfrm"}, 3}, &CStringChecker::evalStrxfrm},
167 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
168 {{CDM::CLibrary, {
"bcmp"}, 3},
169 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
170 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
171 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
172 &CStringChecker::evalBzero},
180 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
181 &CStringChecker::evalSprintf},
182 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
183 &CStringChecker::evalSnprintf},
187 CallDescription StdCopy{CDM::SimpleFunc, {
"std",
"copy"}, 3},
188 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
190 FnCheck identifyCall(
const CallEvent &
Call, CheckerContext &
C)
const;
191 void evalMemcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
192 void evalMempcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
193 void evalMemmove(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
194 void evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const;
195 void evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
197 DestinationArgExpr Dest, SourceArgExpr Source,
198 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
200 void evalMemcmp(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
202 void evalstrLength(CheckerContext &
C,
const CallEvent &
Call)
const;
203 void evalstrnLength(CheckerContext &
C,
const CallEvent &
Call)
const;
204 void evalstrLengthCommon(CheckerContext &
C,
const CallEvent &
Call,
205 bool IsStrnlen =
false)
const;
207 void evalStrcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
208 void evalStrncpy(CheckerContext &
C,
const CallEvent &
Call)
const;
209 void evalStpcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
210 void evalStrlcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
211 void evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
212 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
213 bool returnPtr =
true)
const;
215 void evalStrxfrm(CheckerContext &
C,
const CallEvent &
Call)
const;
217 void evalStrcat(CheckerContext &
C,
const CallEvent &
Call)
const;
218 void evalStrncat(CheckerContext &
C,
const CallEvent &
Call)
const;
219 void evalStrlcat(CheckerContext &
C,
const CallEvent &
Call)
const;
221 void evalStrcmp(CheckerContext &
C,
const CallEvent &
Call)
const;
222 void evalStrncmp(CheckerContext &
C,
const CallEvent &
Call)
const;
223 void evalStrcasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
224 void evalStrncasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
225 void evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
226 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
228 void evalStrsep(CheckerContext &
C,
const CallEvent &
Call)
const;
230 void evalStdCopy(CheckerContext &
C,
const CallEvent &
Call)
const;
231 void evalStdCopyBackward(CheckerContext &
C,
const CallEvent &
Call)
const;
232 void evalStdCopyCommon(CheckerContext &
C,
const CallEvent &
Call)
const;
233 void evalMemset(CheckerContext &
C,
const CallEvent &
Call)
const;
234 void evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const;
236 void evalSprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
237 void evalSnprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
238 void evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
239 bool IsBounded)
const;
242 std::pair<ProgramStateRef , ProgramStateRef >
243 static assumeZero(CheckerContext &
C,
249 static SVal getCStringLengthForRegion(CheckerContext &
C,
254 static const StringLiteral *getStringLiteralFromRegion(
const MemRegion *MR);
256 SVal getCStringLength(CheckerContext &
C,
260 bool hypothetical =
false)
const;
262 const StringLiteral *getCStringLiteral(CheckerContext &
C,
271 SVal BufV, SVal SizeV, QualType SizeTy);
279 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
293 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
295 InvalidationTraitOperations);
297 static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
298 const MemRegion *MR);
301 SVal CharE,
const Expr *Size, CheckerContext &
C,
306 AnyArgExpr Arg, SVal l)
const;
310 AnyArgExpr Buffer, SVal Element, SVal Size)
const;
312 AnyArgExpr Buffer, SVal Element,
314 CharKind CK = CharKind::Regular)
const;
316 AnyArgExpr Buffer, SizeArgExpr Size,
318 CharKind CK = CharKind::Regular)
const;
320 SizeArgExpr Size, AnyArgExpr
First,
322 CharKind CK = CharKind::Regular)
const;
323 void emitOverlapBug(CheckerContext &
C,
326 const Stmt *Second)
const;
328 void emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
const Stmt *S,
329 StringRef WarningMsg)
const;
331 const Stmt *S, StringRef WarningMsg)
const;
333 const Stmt *S, StringRef WarningMsg)
const;
335 const Expr *E,
const MemRegion *R,
336 StringRef Msg)
const;
346 SVal BufVal, QualType BufTy, SVal LengthVal,
358std::pair<ProgramStateRef, ProgramStateRef>
361 std::optional<DefinedSVal> val =
V.getAs<DefinedSVal>();
363 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
365 SValBuilder &svalBuilder =
C.getSValBuilder();
366 DefinedOrUnknownSVal zero = svalBuilder.
makeZeroVal(Ty);
367 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
372 AnyArgExpr Arg, SVal l)
const {
378 std::tie(stateNull, stateNonNull) =
379 assumeZero(
C, State, l, Arg.Expression->
getType());
381 if (stateNull && !stateNonNull) {
384 llvm::raw_svector_ostream
OS(buf);
385 assert(CurrentFunctionDescription);
386 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
387 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
388 << CurrentFunctionDescription;
390 emitNullArgBug(
C, stateNull, Arg.Expression,
OS.str());
396 assert(stateNonNull);
405 if (CK == CharKind::Regular) {
421 if (Offset.isUnknown())
428 Os << Idx << llvm::getOrdinalSuffix(Idx);
433 AnyArgExpr Buffer, SVal Element,
441 const auto *ER = dyn_cast_or_null<ElementRegion>(R);
445 const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
451 if (!SuperR->getValueType()->isArrayType())
454 SValBuilder &SVB =
C.getSValBuilder();
460 std::optional<Loc> FirstElementVal =
461 State->getLValue(ElemTy,
Zero, loc::MemRegionVal(SuperR)).getAs<Loc>();
462 if (!FirstElementVal)
467 State->getSVal(*FirstElementVal).isUndef()) {
468 llvm::SmallString<258> Buf;
469 llvm::raw_svector_ostream
OS(Buf);
470 OS <<
"The first element of the ";
472 OS <<
" argument is undefined";
473 emitUninitializedReadBug(
C, State, Buffer.Expression,
474 FirstElementVal->getAsRegion(),
OS.str());
505 std::optional<NonLoc> Offset =
512 SVal LastIdx = SVB.
evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);
517 SVal LastElementVal =
518 State->getLValue(ElemTy, LastIdx, loc::MemRegionVal(SuperR));
523 State->getSVal(LastElementVal.
castAs<Loc>()).isUndef()) {
524 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
531 llvm::SmallString<258> Buf;
532 llvm::raw_svector_ostream
OS(Buf);
533 OS <<
"The last accessed element (at index ";
534 OS << IdxInt->getExtValue();
537 OS <<
" argument is undefined";
538 emitUninitializedReadBug(
C, State, Buffer.Expression,
550 AnyArgExpr Buffer, SVal Element,
563 const auto *ER = dyn_cast<ElementRegion>(R);
568 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
574 DefinedOrUnknownSVal
Size =
577 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
578 if (StOutBound && !StInBound) {
583 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
584 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
595 AnyArgExpr Buffer, SizeArgExpr Size,
596 AccessKind Access, CharKind CK)
const {
601 SValBuilder &svalBuilder =
C.getSValBuilder();
604 QualType SizeTy =
Size.Expression->getType();
605 QualType PtrTy = getCharPtrType(Ctx, CK);
608 SVal BufVal =
C.getSVal(Buffer.Expression);
609 State = checkNonNull(
C, State, Buffer, BufVal);
621 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
629 SVal LengthVal =
C.getSVal(
Size.Expression);
630 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
636 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
637 if (Offset.isUnknown())
639 NonLoc LastOffset = Offset.
castAs<NonLoc>();
642 if (std::optional<Loc> BufLoc = BufStart.
getAs<Loc>()) {
645 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
646 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
647 if (Access == AccessKind::read)
648 State = checkInit(
C, State, Buffer, BufEnd, *Length);
661 SizeArgExpr Size, AnyArgExpr
First,
677 if (!
First.Expression->getType()->isAnyPointerType() ||
682 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
687 const LocationContext *LCtx =
C.getLocationContext();
688 SVal firstVal = state->getSVal(
First.Expression, LCtx);
689 SVal secondVal = state->getSVal(Second.Expression, LCtx);
691 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
695 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
700 SValBuilder &svalBuilder =
C.getSValBuilder();
701 std::tie(stateTrue, stateFalse) =
702 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
704 if (stateTrue && !stateFalse) {
706 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
717 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
718 std::optional<DefinedOrUnknownSVal> reverseTest =
719 reverse.
getAs<DefinedOrUnknownSVal>();
723 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
730 std::swap(firstLoc, secondLoc);
733 std::swap(
First, Second);
738 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
739 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
746 QualType CharPtrTy = getCharPtrType(Ctx, CK);
748 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
749 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
754 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
756 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
762 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
763 std::optional<DefinedOrUnknownSVal> OverlapTest =
764 Overlap.
getAs<DefinedOrUnknownSVal>();
768 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
770 if (stateTrue && !stateFalse) {
772 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
781void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
782 const Stmt *
First,
const Stmt *Second)
const {
783 ExplodedNode *N =
C.generateErrorNode(state);
788 auto report = std::make_unique<PathSensitiveBugReport>(
789 BufferOverlap,
"Arguments must not be overlapping buffers", N);
790 report->addRange(
First->getSourceRange());
793 C.emitReport(std::move(report));
796void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
797 const Stmt *S, StringRef WarningMsg)
const {
798 if (ExplodedNode *N =
C.generateErrorNode(State)) {
800 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
802 if (
const auto *Ex = dyn_cast<Expr>(S))
804 C.emitReport(std::move(
Report));
808void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
810 const Expr *E,
const MemRegion *R,
811 StringRef Msg)
const {
812 if (ExplodedNode *N =
C.generateErrorNode(State)) {
814 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
815 Report->addNote(
"Other elements might also be undefined",
819 Report->addVisitor<NoStoreFuncVisitor>(R->
castAs<SubRegion>());
820 C.emitReport(std::move(
Report));
824void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
826 StringRef WarningMsg)
const {
827 if (ExplodedNode *N =
C.generateErrorNode(State)) {
832 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
834 C.emitReport(std::move(
Report));
838void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
840 StringRef WarningMsg)
const {
841 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
843 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
846 C.emitReport(std::move(
Report));
853 NonLoc right)
const {
862 SValBuilder &svalBuilder =
C.getSValBuilder();
866 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
867 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
871 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
876 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
881 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
884 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
885 *maxMinusRightNL, cmpTy);
887 auto [StateOverflow, StateOkay] =
888 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
890 if (StateOverflow && !StateOkay) {
896 C.addSink(StateOverflow);
911 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
916 case MemRegion::StringRegionKind:
921 case MemRegion::SymbolicRegionKind:
922 case MemRegion::AllocaRegionKind:
923 case MemRegion::NonParamVarRegionKind:
924 case MemRegion::ParamVarRegionKind:
925 case MemRegion::FieldRegionKind:
926 case MemRegion::ObjCIvarRegionKind:
930 case MemRegion::ElementRegionKind:
944 return state->remove<CStringLength>(MR);
946 return state->set<CStringLength>(MR, strLength);
949SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
956 const SVal *Recorded = state->get<CStringLength>(MR);
962 SValBuilder &svalBuilder =
C.getSValBuilder();
966 C.getLocationContext(),
970 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
973 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
974 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
975 std::optional<APSIntPtr> maxLengthInt =
977 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
978 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
980 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
982 state = state->set<CStringLength>(MR, strLength);
989CStringChecker::getStringLiteralFromRegion(
const MemRegion *MR) {
991 case MemRegion::StringRegionKind:
993 case MemRegion::NonParamVarRegionKind:
995 Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage())
996 return dyn_cast_or_null<StringLiteral>(
Decl->getInit());
1003SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
1004 const Expr *Ex, SVal Buf,
1005 bool hypothetical)
const {
1011 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
1013 SmallString<120> buf;
1014 llvm::raw_svector_ostream os(buf);
1015 assert(CurrentFunctionDescription);
1016 os <<
"Argument to " << CurrentFunctionDescription
1017 <<
" is the address of the label '" << Label->getLabel()->getName()
1018 <<
"', which is not a null-terminated string";
1020 emitNotCStringBug(
C, state, Ex, os.str());
1022 return UndefinedVal();
1026 return UnknownVal();
1033 if (
const StringLiteral *StrLit = getStringLiteralFromRegion(MR)) {
1039 SValBuilder &SVB =
C.getSValBuilder();
1044 case MemRegion::StringRegionKind:
1045 case MemRegion::NonParamVarRegionKind:
1046 case MemRegion::SymbolicRegionKind:
1047 case MemRegion::AllocaRegionKind:
1048 case MemRegion::ParamVarRegionKind:
1049 case MemRegion::FieldRegionKind:
1050 case MemRegion::ObjCIvarRegionKind:
1051 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1052 case MemRegion::CompoundLiteralRegionKind:
1054 return UnknownVal();
1055 case MemRegion::ElementRegionKind: {
1060 const SubRegion *SuperReg =
1062 const StringLiteral *StrLit = getStringLiteralFromRegion(SuperReg);
1064 return UnknownVal();
1065 SValBuilder &SVB =
C.getSValBuilder();
1070 if (state->assume(SVB.
evalBinOpNN(state, BO_LE, Idx, LengthVal,
1072 .
castAs<DefinedOrUnknownSVal>(),
1074 return SVB.
evalBinOp(state, BO_Sub, LengthVal, Idx, SizeTy);
1075 return UnknownVal();
1082 SmallString<120> buf;
1083 llvm::raw_svector_ostream os(buf);
1085 assert(CurrentFunctionDescription);
1086 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1088 if (SummarizeRegion(os,
C.getASTContext(), MR))
1089 os <<
", which is not a null-terminated string";
1091 os <<
"not a null-terminated string";
1093 emitNotCStringBug(
C, state, Ex, os.str());
1095 return UndefinedVal();
1099const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1112 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1120bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1121 SVal BufVal, QualType BufTy,
1122 SVal LengthVal, QualType LengthTy) {
1131 SValBuilder &SB =
C.getSValBuilder();
1132 ASTContext &Ctx =
C.getASTContext();
1136 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1142 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1143 if (Offset.isUnknown())
1145 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1148 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1149 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1153 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1160 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1166 C.getASTContext().CharTy &&
1167 "isFirstBufInBound should only be called with char* ElementRegions");
1174 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1178 return static_cast<bool>(StInBound);
1184 auto InvalidationTraitOperations =
1185 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1186 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1189 if (MemRegion::FieldRegionKind == R->
getKind() &&
1190 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1198 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1202CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1204 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1205 const MemRegion *R) {
1209 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1212ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1214 auto InvalidationTraitOperations =
1215 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1216 if (MemRegion::FieldRegionKind == R->
getKind())
1223 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1230 auto InvalidationTraitOperations =
1231 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1240 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1245 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1247 InvalidationTraitOperations) {
1248 std::optional<Loc> L =
V.getAs<Loc>();
1255 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1256 const MemRegion *R = MR->getRegion()->
StripCasts();
1260 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1266 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
1267 RegionAndSymbolInvalidationTraits ITraits;
1268 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1270 return State->invalidateRegions(R, Elem,
C.blockCount(), LCtx,
1271 CausesPointerEscape,
nullptr,
nullptr,
1278 return State->killBinding(*L);
1281bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1282 const MemRegion *MR) {
1284 case MemRegion::FunctionCodeRegionKind: {
1286 os <<
"the address of the function '" << *FD <<
'\'';
1288 os <<
"the address of a function";
1291 case MemRegion::BlockCodeRegionKind:
1294 case MemRegion::BlockDataRegionKind:
1297 case MemRegion::CXXThisRegionKind:
1298 case MemRegion::CXXTempObjectRegionKind:
1299 os <<
"a C++ temp object of type "
1302 case MemRegion::NonParamVarRegionKind:
1305 case MemRegion::ParamVarRegionKind:
1308 case MemRegion::FieldRegionKind:
1311 case MemRegion::ObjCIvarRegionKind:
1312 os <<
"an instance variable of type "
1321 SVal CharVal,
const Expr *Size,
1323 SVal MemVal =
C.getSVal(DstBuffer);
1324 SVal SizeVal =
C.getSVal(Size);
1334 const MemRegion *BR = Offset.
getRegion();
1336 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1340 SValBuilder &svalBuilder =
C.getSValBuilder();
1341 ASTContext &Ctx =
C.getASTContext();
1351 std::tie(StateWholeReg, StateNotWholeReg) =
1352 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1359 std::tie(StateNullChar, StateNonNullChar) =
1362 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1363 !StateNonNullChar) {
1370 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1371 C.getLocationContext());
1375 State = invalidateDestinationBufferBySize(
1376 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1379 if (StateNullChar && !StateNonNullChar) {
1382 State = setCStringLength(State, MR,
1384 }
else if (!StateNullChar && StateNonNullChar) {
1386 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1387 C.getLocationContext(),
C.blockCount());
1391 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1394 State = setCStringLength(
1395 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1401 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1402 SizeVal,
Size->getType());
1411void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1413 DestinationArgExpr Dest,
1414 SourceArgExpr Source,
bool Restricted,
1415 bool IsMempcpy, CharKind CK)
const {
1416 CurrentFunctionDescription =
"memory copy function";
1419 const LocationContext *LCtx =
C.getLocationContext();
1420 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1421 QualType sizeTy =
Size.Expression->getType();
1424 std::tie(stateZeroSize, stateNonZeroSize) =
1425 assumeZero(
C, state, sizeVal, sizeTy);
1428 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1432 if (stateZeroSize && !stateNonZeroSize) {
1434 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1435 C.addTransition(stateZeroSize);
1440 if (stateNonZeroSize) {
1444 state = stateNonZeroSize;
1448 state = checkNonNull(
C, state, Dest, destVal);
1453 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1457 state = checkNonNull(
C, state, Source, srcVal);
1462 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1463 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1466 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1475 SValBuilder &SvalBuilder =
C.getSValBuilder();
1477 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1478 SVal DestRegCharVal =
1479 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1480 SVal lastElement =
C.getSValBuilder().evalBinOp(
1481 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1485 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1488 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1492 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1501 state = invalidateDestinationBufferBySize(
1502 C, state, Dest.Expression,
Call.getCFGElementRef(),
1503 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1507 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1508 C.getSVal(Source.Expression));
1510 C.addTransition(state);
1514void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1515 CharKind CK)
const {
1518 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1519 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1520 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1524 constexpr bool IsRestricted =
true;
1525 constexpr bool IsMempcpy =
false;
1526 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1529void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1530 CharKind CK)
const {
1533 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1534 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1535 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1537 constexpr bool IsRestricted =
true;
1538 constexpr bool IsMempcpy =
true;
1539 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1543void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1544 CharKind CK)
const {
1547 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1548 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1549 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1551 constexpr bool IsRestricted =
false;
1552 constexpr bool IsMempcpy =
false;
1553 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1557void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1559 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1560 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1561 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1563 constexpr bool IsRestricted =
false;
1564 constexpr bool IsMempcpy =
false;
1565 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1566 IsMempcpy, CharKind::Regular);
1569void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1570 CharKind CK)
const {
1572 CurrentFunctionDescription =
"memory comparison function";
1574 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1575 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1576 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1579 SValBuilder &Builder =
C.getSValBuilder();
1580 const LocationContext *LCtx =
C.getLocationContext();
1583 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1584 QualType sizeTy =
Size.Expression->getType();
1587 std::tie(stateZeroSize, stateNonZeroSize) =
1588 assumeZero(
C, State, sizeVal, sizeTy);
1592 if (stateZeroSize) {
1593 State = stateZeroSize;
1594 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1595 Builder.makeZeroVal(
Call.getResultType()));
1596 C.addTransition(State);
1600 if (stateNonZeroSize) {
1601 State = stateNonZeroSize;
1605 DefinedOrUnknownSVal LV =
1606 State->getSVal(
Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1607 DefinedOrUnknownSVal RV =
1608 State->getSVal(
Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1612 std::tie(SameBuffer, NotSameBuffer) =
1613 State->assume(Builder.evalEQ(State, LV, RV));
1617 if (SameBuffer && !NotSameBuffer) {
1619 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1621 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1622 Builder.makeZeroVal(
Call.getResultType()));
1623 C.addTransition(State);
1630 assert(NotSameBuffer);
1631 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1632 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1635 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1636 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1637 C.addTransition(State);
1642void CStringChecker::evalstrLength(CheckerContext &
C,
1643 const CallEvent &
Call)
const {
1645 evalstrLengthCommon(
C,
Call,
false);
1648void CStringChecker::evalstrnLength(CheckerContext &
C,
1649 const CallEvent &
Call)
const {
1651 evalstrLengthCommon(
C,
Call,
true);
1654void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1655 const CallEvent &
Call,
1656 bool IsStrnlen)
const {
1657 CurrentFunctionDescription =
"string length function";
1659 const LocationContext *LCtx =
C.getLocationContext();
1662 const Expr *maxlenExpr =
Call.getArgExpr(1);
1663 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1666 std::tie(stateZeroSize, stateNonZeroSize) =
1667 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1671 if (stateZeroSize) {
1672 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1673 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1674 C.addTransition(stateZeroSize);
1678 if (!stateNonZeroSize)
1682 state = stateNonZeroSize;
1686 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1687 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1688 state = checkNonNull(
C, state, Arg, ArgVal);
1693 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1700 DefinedOrUnknownSVal result = UnknownVal();
1705 QualType cmpTy =
C.getSValBuilder().getConditionType();
1709 const Expr *maxlenExpr =
Call.getArgExpr(1);
1710 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1712 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1713 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1715 if (strLengthNL && maxlenValNL) {
1719 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1721 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1722 .castAs<DefinedOrUnknownSVal>());
1724 if (stateStringTooLong && !stateStringNotTooLong) {
1726 result = *maxlenValNL;
1727 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1729 result = *strLengthNL;
1738 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1739 NonLoc resultNL = result.
castAs<NonLoc>();
1742 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1743 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1744 .castAs<DefinedOrUnknownSVal>(),
true);
1748 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1749 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1750 .castAs<DefinedOrUnknownSVal>(),
true);
1756 result = strLength.
castAs<DefinedOrUnknownSVal>();
1761 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1766 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1767 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1768 C.addTransition(state);
1771void CStringChecker::evalStrcpy(CheckerContext &
C,
1772 const CallEvent &
Call)
const {
1774 evalStrcpyCommon(
C,
Call,
1777 ConcatFnKind::none);
1780void CStringChecker::evalStrncpy(CheckerContext &
C,
1781 const CallEvent &
Call)
const {
1783 evalStrcpyCommon(
C,
Call,
1786 ConcatFnKind::none);
1789void CStringChecker::evalStpcpy(CheckerContext &
C,
1790 const CallEvent &
Call)
const {
1792 evalStrcpyCommon(
C,
Call,
1795 ConcatFnKind::none);
1798void CStringChecker::evalStrlcpy(CheckerContext &
C,
1799 const CallEvent &
Call)
const {
1801 evalStrcpyCommon(
C,
Call,
1808void CStringChecker::evalStrcat(CheckerContext &
C,
1809 const CallEvent &
Call)
const {
1811 evalStrcpyCommon(
C,
Call,
1814 ConcatFnKind::strcat);
1817void CStringChecker::evalStrncat(CheckerContext &
C,
1818 const CallEvent &
Call)
const {
1820 evalStrcpyCommon(
C,
Call,
1823 ConcatFnKind::strcat);
1826void CStringChecker::evalStrlcat(CheckerContext &
C,
1827 const CallEvent &
Call)
const {
1831 evalStrcpyCommon(
C,
Call,
1834 ConcatFnKind::strlcat,
1838void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1839 bool ReturnEnd,
bool IsBounded,
1840 ConcatFnKind appendK,
1841 bool returnPtr)
const {
1842 if (appendK == ConcatFnKind::none)
1843 CurrentFunctionDescription =
"string copy function";
1845 CurrentFunctionDescription =
"string concatenation function";
1848 const LocationContext *LCtx =
C.getLocationContext();
1851 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1852 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1853 state = checkNonNull(
C, state, Dst, DstVal);
1858 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1859 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1860 state = checkNonNull(
C, state, srcExpr, srcVal);
1865 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1866 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1869 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1870 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1876 SValBuilder &svalBuilder =
C.getSValBuilder();
1883 SVal amountCopied = UnknownVal();
1884 SVal maxLastElementIndex = UnknownVal();
1885 const char *boundWarning =
nullptr;
1889 SizeArgExpr SrcExprAsSizeDummy = {
1890 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1891 state = CheckOverlap(
1893 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1902 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1903 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1907 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1909 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1913 if (strLengthNL && lenValNL) {
1915 case ConcatFnKind::none:
1916 case ConcatFnKind::strcat: {
1921 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1923 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1924 .castAs<DefinedOrUnknownSVal>());
1926 if (stateSourceTooLong && !stateSourceNotTooLong) {
1929 state = stateSourceTooLong;
1930 amountCopied = lenVal;
1932 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1934 state = stateSourceNotTooLong;
1935 amountCopied = strLength;
1939 case ConcatFnKind::strlcat:
1940 if (!dstStrLengthNL)
1944 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
1945 *dstStrLengthNL, sizeTy);
1949 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1951 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
1958 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1961 std::tie(TrueState, FalseState) =
1962 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
1965 if (TrueState && !FalseState) {
1966 amountCopied = strLength;
1970 if (!TrueState && FalseState) {
1971 amountCopied = freeSpace;
1974 if (TrueState && FalseState)
1975 amountCopied = UnknownVal();
1982 case ConcatFnKind::strcat:
1988 if (dstStrLength.isUndef())
1991 if (dstStrLengthNL) {
1993 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1995 boundWarning =
"Size argument is greater than the free space in the "
1996 "destination buffer";
1999 case ConcatFnKind::none:
2000 case ConcatFnKind::strlcat:
2010 std::tie(StateZeroSize, StateNonZeroSize) =
2011 assumeZero(
C, state, *lenValNL, sizeTy);
2014 if (StateZeroSize && !StateNonZeroSize) {
2017 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
2019 if (appendK == ConcatFnKind::none) {
2021 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
2026 state, BO_Add, strLength, dstStrLength, sizeTy);
2028 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
2031 C.addTransition(StateZeroSize);
2039 maxLastElementIndex =
2040 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2041 boundWarning =
"Size argument is greater than the length of the "
2042 "destination buffer";
2049 amountCopied = strLength;
2057 SVal finalStrLength = UnknownVal();
2058 SVal strlRetVal = UnknownVal();
2060 if (appendK == ConcatFnKind::none && !returnPtr) {
2062 strlRetVal = strLength;
2068 if (appendK != ConcatFnKind::none) {
2071 if (dstStrLength.isUndef())
2074 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2075 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2076 *dstStrLengthNL, sizeTy);
2079 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2082 if (amountCopiedNL && dstStrLengthNL) {
2084 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2088 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2089 *dstStrLengthNL, sizeTy);
2098 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2099 assert(!finalStrLength.
isUndef());
2101 if (std::optional<NonLoc> finalStrLengthNL =
2102 finalStrLength.
getAs<NonLoc>()) {
2103 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2107 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2108 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2114 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2117 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2122 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2132 finalStrLength = amountCopied;
2140 Result = (ReturnEnd ? UnknownVal() : DstVal);
2142 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2153 if (std::optional<loc::MemRegionVal> dstRegVal =
2154 DstVal.
getAs<loc::MemRegionVal>()) {
2155 QualType ptrTy = Dst.Expression->getType();
2159 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2160 SVal maxLastElement =
2161 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2164 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2168 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2174 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2175 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2176 *knownStrLength, ptrTy);
2179 if (!boundWarning) {
2181 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2185 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2191 if (returnPtr && ReturnEnd)
2204 bool CouldAccessOutOfBound =
true;
2205 if (IsBounded && amountCopied.
isUnknown()) {
2206 auto CouldAccessOutOfBoundForSVal =
2207 [&](std::optional<NonLoc> Val) ->
bool {
2210 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2211 Dst.Expression->getType(), *Val,
2212 C.getASTContext().getSizeType());
2215 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2217 if (CouldAccessOutOfBound) {
2219 const Expr *LenExpr =
Call.getArgExpr(2);
2220 SVal LenVal = state->getSVal(LenExpr, LCtx);
2228 CouldAccessOutOfBound =
2229 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2240 if (CouldAccessOutOfBound)
2241 state = invalidateDestinationBufferBySize(
2242 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2243 amountCopied,
C.getASTContext().getSizeType());
2245 state = invalidateDestinationBufferNeverOverflows(
2246 C, state,
Call.getCFGElementRef(), *dstRegVal);
2250 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2253 if (IsBounded && (appendK == ConcatFnKind::none)) {
2258 if (amountCopied != strLength)
2259 finalStrLength = UnknownVal();
2261 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2269 if (ReturnEnd &&
Result.isUnknown()) {
2274 state = state->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2275 C.addTransition(state);
2278void CStringChecker::evalStrxfrm(CheckerContext &
C,
2279 const CallEvent &
Call)
const {
2281 CurrentFunctionDescription =
"locale transformation function";
2284 const LocationContext *LCtx =
C.getLocationContext();
2285 SValBuilder &SVB =
C.getSValBuilder();
2288 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2289 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2290 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2293 SVal SrcVal = State->getSVal(Source.Expression, LCtx);
2294 State = checkNonNull(
C, State, Source, SrcVal);
2299 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2307 auto BindReturnAndTransition = [&RetVal, &
Call, LCtx,
2310 State = State->BindExpr(
Call.getOriginExpr(), LCtx, RetVal);
2311 C.addTransition(State);
2316 SVal SizeVal = State->getSVal(
Size.Expression, LCtx);
2317 QualType SizeTy =
Size.Expression->getType();
2319 auto [StateZeroSize, StateSizeNonZero] =
2320 assumeZero(
C, State, SizeVal, SizeTy);
2323 if (!StateZeroSize && !StateSizeNonZero)
2324 return BindReturnAndTransition(State);
2327 if (StateZeroSize && !StateSizeNonZero)
2328 return BindReturnAndTransition(StateZeroSize);
2331 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, LCtx);
2332 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2333 if (!StateSizeNonZero)
2337 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2338 AccessKind::write, CK_Regular);
2339 if (!StateSizeNonZero)
2344 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2346 .
getAs<DefinedOrUnknownSVal>();
2347 if (!ComparisonVal) {
2349 StateSizeNonZero = invalidateDestinationBufferBySize(
2350 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2351 SizeVal,
Size.Expression->getType());
2352 return BindReturnAndTransition(StateSizeNonZero);
2355 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2359 StateSuccess = invalidateDestinationBufferBySize(
2360 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2361 SizeVal,
Size.Expression->getType());
2362 BindReturnAndTransition(StateSuccess);
2368 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2369 StateFailure = StateFailure->killBinding(*DestLoc);
2371 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, LCtx);
2374 BindReturnAndTransition(StateFailure);
2378void CStringChecker::evalStrcmp(CheckerContext &
C,
2379 const CallEvent &
Call)
const {
2381 evalStrcmpCommon(
C,
Call,
false,
false);
2384void CStringChecker::evalStrncmp(CheckerContext &
C,
2385 const CallEvent &
Call)
const {
2387 evalStrcmpCommon(
C,
Call,
true,
false);
2390void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2391 const CallEvent &
Call)
const {
2393 evalStrcmpCommon(
C,
Call,
false,
true);
2396void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2397 const CallEvent &
Call)
const {
2399 evalStrcmpCommon(
C,
Call,
true,
true);
2402void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2403 bool IsBounded,
bool IgnoreCase)
const {
2404 CurrentFunctionDescription =
"string comparison function";
2406 const LocationContext *LCtx =
C.getLocationContext();
2409 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2410 SVal LeftVal = state->getSVal(
Left.Expression, LCtx);
2411 state = checkNonNull(
C, state, Left, LeftVal);
2416 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2417 SVal RightVal = state->getSVal(
Right.Expression, LCtx);
2418 state = checkNonNull(
C, state, Right, RightVal);
2423 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2428 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2435 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2436 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2439 SValBuilder &svalBuilder =
C.getSValBuilder();
2440 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2442 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2448 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2449 svalBuilder.makeZeroVal(
Call.getResultType()));
2450 C.addTransition(StSameBuf);
2457 assert(StNotSameBuf);
2458 state = StNotSameBuf;
2464 const StringLiteral *LeftStrLiteral =
2465 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2466 const StringLiteral *RightStrLiteral =
2467 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2468 bool canComputeResult =
false;
2469 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2471 if (LeftStrLiteral && RightStrLiteral) {
2472 StringRef LeftStrRef = LeftStrLiteral->
getString();
2473 StringRef RightStrRef = RightStrLiteral->
getString();
2477 const Expr *lenExpr =
Call.getArgExpr(2);
2478 SVal lenVal = state->getSVal(lenExpr, LCtx);
2481 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2483 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2484 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2485 canComputeResult =
true;
2489 canComputeResult =
true;
2492 if (canComputeResult) {
2494 size_t s1Term = LeftStrRef.find(
'\0');
2495 if (s1Term != StringRef::npos)
2496 LeftStrRef = LeftStrRef.substr(0, s1Term);
2498 size_t s2Term = RightStrRef.find(
'\0');
2499 if (s2Term != StringRef::npos)
2500 RightStrRef = RightStrRef.substr(0, s2Term);
2503 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2504 : LeftStrRef.compare(RightStrRef);
2508 if (compareRes == 0) {
2509 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2512 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2516 SVal compareWithZero =
2517 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2518 svalBuilder.getConditionType());
2519 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2520 state = state->assume(compareWithZeroVal,
true);
2525 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2528 C.addTransition(state);
2531void CStringChecker::evalStrsep(CheckerContext &
C,
2532 const CallEvent &
Call)
const {
2535 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2537 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2538 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2542 CurrentFunctionDescription =
"strsep()";
2544 const LocationContext *LCtx =
C.getLocationContext();
2548 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2549 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2554 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2555 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2556 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2560 SValBuilder &SVB =
C.getSValBuilder();
2562 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2564 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2569 State = invalidateDestinationBufferNeverOverflows(
2574 State = State->bindLoc(*SearchStrLoc,
2584 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2585 C.addTransition(State);
2589void CStringChecker::evalStdCopy(CheckerContext &
C,
2590 const CallEvent &
Call)
const {
2591 evalStdCopyCommon(
C,
Call);
2594void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2595 const CallEvent &
Call)
const {
2596 evalStdCopyCommon(
C,
Call);
2599void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2600 const CallEvent &
Call)
const {
2601 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2606 const LocationContext *LCtx =
C.getLocationContext();
2614 const Expr *Dst =
Call.getArgExpr(2);
2615 SVal DstVal = State->getSVal(Dst, LCtx);
2618 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2619 C, State,
Call.getCFGElementRef(), DstVal);
2621 SValBuilder &SVB =
C.getSValBuilder();
2624 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2626 C.addTransition(State);
2629void CStringChecker::evalMemset(CheckerContext &
C,
2630 const CallEvent &
Call)
const {
2632 CurrentFunctionDescription =
"memory set function";
2634 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2635 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2636 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2641 const LocationContext *LCtx =
C.getLocationContext();
2642 SVal SizeVal =
C.getSVal(
Size.Expression);
2643 QualType SizeTy =
Size.Expression->getType();
2646 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2649 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2653 if (ZeroSize && !NonZeroSize) {
2654 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2655 C.addTransition(ZeroSize);
2661 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2665 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2672 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2673 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2676 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2677 C.addTransition(State);
2680void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2681 CurrentFunctionDescription =
"memory clearance function";
2683 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2684 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2685 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2690 SVal SizeVal =
C.getSVal(
Size.Expression);
2691 QualType SizeTy =
Size.Expression->getType();
2694 std::tie(StateZeroSize, StateNonZeroSize) =
2695 assumeZero(
C, State, SizeVal, SizeTy);
2699 if (StateZeroSize && !StateNonZeroSize) {
2700 C.addTransition(StateZeroSize);
2705 SVal MemVal =
C.getSVal(Buffer.Expression);
2709 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2713 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2717 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
2718 Size.Expression,
C, State))
2721 C.addTransition(State);
2724void CStringChecker::evalSprintf(CheckerContext &
C,
2725 const CallEvent &
Call)
const {
2726 CurrentFunctionDescription =
"'sprintf'";
2727 evalSprintfCommon(
C,
Call,
false);
2730void CStringChecker::evalSnprintf(CheckerContext &
C,
2731 const CallEvent &
Call)
const {
2732 CurrentFunctionDescription =
"'snprintf'";
2733 evalSprintfCommon(
C,
Call,
true);
2736void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
2737 bool IsBounded)
const {
2740 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2742 const auto NumParams =
Call.parameters().size();
2743 if (CE->getNumArgs() < NumParams) {
2748 const auto AllArguments =
2749 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2750 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2752 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2754 if (
const QualType
type = ArgExpr->getType();
2755 !
type->isAnyPointerType() ||
2756 !
type->getPointeeType()->isAnyCharacterType())
2758 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
2761 SizeArgExpr SrcExprAsSizeDummy = {
2762 {Source.Expression, Source.ArgumentIndex}};
2763 State = CheckOverlap(
2765 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2771 C.addTransition(State);
2778CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2779 CheckerContext &
C)
const {
2780 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2784 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
2789 return &CStringChecker::evalStdCopy;
2791 return &CStringChecker::evalStdCopyBackward;
2797 for (
auto I : CE->arguments()) {
2798 QualType
T = I->getType();
2803 const FnCheck *Callback = Callbacks.lookup(
Call);
2810bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
2811 FnCheck Callback = identifyCall(
Call,
C);
2819 Callback(
this,
C,
Call);
2827 return C.isDifferent();
2830void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
2834 for (
const auto *I : DS->
decls()) {
2835 const VarDecl *D = dyn_cast<VarDecl>(I);
2849 Loc VarLoc = state->getLValue(D,
C.getLocationContext());
2854 SVal StrVal =
C.getSVal(
Init);
2855 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2856 DefinedOrUnknownSVal strLength =
2857 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
2859 state = state->set<CStringLength>(MR, strLength);
2862 C.addTransition(state);
2868 ArrayRef<const MemRegion *> ExplicitRegions,
2869 ArrayRef<const MemRegion *> Regions,
2870 const LocationContext *LCtx,
2871 const CallEvent *
Call)
const {
2872 CStringLengthTy Entries = state->get<CStringLength>();
2873 if (Entries.isEmpty())
2876 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2877 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2880 for (
const MemRegion *MR : Regions) {
2881 Invalidated.insert(MR);
2883 SuperRegions.insert(MR);
2884 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2885 MR = SR->getSuperRegion();
2886 SuperRegions.insert(MR);
2890 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2893 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2895 if (SuperRegions.count(MR)) {
2896 Entries = F.remove(Entries, MR);
2901 const MemRegion *Super = MR;
2902 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2903 Super = SR->getSuperRegion();
2904 if (Invalidated.count(Super)) {
2905 Entries = F.remove(Entries, MR);
2911 return state->set<CStringLength>(Entries);
2915 SymbolReaper &SR)
const {
2917 CStringLengthTy Entries = state->get<CStringLength>();
2919 for (SVal Len : llvm::make_second_range(Entries)) {
2925void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2926 CheckerContext &
C)
const {
2928 CStringLengthTy Entries = state->get<CStringLength>();
2929 if (Entries.isEmpty())
2932 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2933 for (
auto [Reg, Len] : Entries) {
2934 if (
SymbolRef Sym = Len.getAsSymbol()) {
2936 Entries = F.remove(Entries, Reg);
2940 state = state->set<CStringLength>(Entries);
2941 C.addTransition(state);
2944void ento::registerCStringModeling(CheckerManager &Mgr) {
2951bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
2955#define REGISTER_CHECKER(NAME) \
2956 void ento::registerCString##NAME(CheckerManager &Mgr) { \
2957 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
2960 bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \
static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx)
#define REGISTER_CHECKER(name)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedCharTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
LangAS getAddressSpace() const
Return the address space of this type.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
unsigned getLength() const
StringRef getString() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
bool isAnyPointerType() const
const Expr * getInit() const
APSIntPtr getMaxValue(const llvm::APSInt &v)
std::optional< APSIntPtr > evalAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt &V1, const llvm::APSInt &V2)
bool matches(const CallEvent &Call) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
Checker families (where a single backend class implements multiple related frontends) should derive f...
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
ElementRegion is used to represent both array elements and casts.
QualType getValueType() const override
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const RegionTy * castAs() const
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
SValBuilder & getSValBuilder()
@ TK_PreserveContents
Tells that a region's contents is not changed.
@ TK_DoNotInvalidateSuperRegion
@ TK_SuppressEscape
Suppress pointer-escaping of a region.
void setTrait(SymbolRef Sym, InvalidationKinds IK)
bool hasSymbolicOffset() const
const MemRegion * getRegion() const
It might return null.
int64_t getOffset() const
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with a memory location and non-location opera...
DefinedSVal getMetadataSymbolVal(const void *symbolTag, const MemRegion *region, const Expr *expr, QualType type, const LocationContext *LCtx, unsigned count)
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)
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, ConstCFGElementRef elem, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
NonLoc makeZeroArrayIndex()
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
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
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
@ Result
The result type of a method or function.
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