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 =
515 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) {
595 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
596 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
607 AnyArgExpr Buffer, SizeArgExpr Size,
608 AccessKind Access, CharKind CK)
const {
613 SValBuilder &svalBuilder =
C.getSValBuilder();
616 QualType SizeTy =
Size.Expression->getType();
617 QualType PtrTy = getCharPtrType(Ctx, CK);
620 SVal BufVal =
C.getSVal(Buffer.Expression);
621 State = checkNonNull(
C, State, Buffer, BufVal);
629 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
637 SVal LengthVal =
C.getSVal(
Size.Expression);
638 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
644 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
645 if (Offset.isUnknown())
647 NonLoc LastOffset = Offset.
castAs<NonLoc>();
650 if (std::optional<Loc> BufLoc = BufStart.
getAs<Loc>()) {
653 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
654 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
655 if (Access == AccessKind::read)
656 State = checkInit(
C, State, Buffer, BufEnd, *Length);
669 SizeArgExpr Size, AnyArgExpr
First,
682 if (!
First.Expression->getType()->isAnyPointerType() ||
687 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
692 const LocationContext *LCtx =
C.getLocationContext();
693 SVal firstVal = state->getSVal(
First.Expression, LCtx);
694 SVal secondVal = state->getSVal(Second.Expression, LCtx);
696 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
700 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
705 SValBuilder &svalBuilder =
C.getSValBuilder();
706 std::tie(stateTrue, stateFalse) =
707 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
709 if (stateTrue && !stateFalse) {
712 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
737 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
738 std::optional<DefinedOrUnknownSVal> reverseTest =
739 reverse.
getAs<DefinedOrUnknownSVal>();
743 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
750 std::swap(firstLoc, secondLoc);
753 std::swap(
First, Second);
758 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
759 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
766 QualType CharPtrTy = getCharPtrType(Ctx, CK);
768 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
769 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
774 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
776 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
782 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
783 std::optional<DefinedOrUnknownSVal> OverlapTest =
784 Overlap.
getAs<DefinedOrUnknownSVal>();
788 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
790 if (stateTrue && !stateFalse) {
792 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
812void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
814 const Stmt *Second)
const {
816 "Can't emit from a checker that is not enabled!");
817 ExplodedNode *N =
C.generateErrorNode(state);
822 auto report = std::make_unique<PathSensitiveBugReport>(
823 BufferOverlap,
"Arguments must not be overlapping buffers", N);
824 report->addRange(
First->getSourceRange());
827 C.emitReport(std::move(report));
830void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
831 const Stmt *S, StringRef WarningMsg)
const {
833 "Can't emit from a checker that is not enabled!");
834 if (ExplodedNode *N =
C.generateErrorNode(State)) {
836 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
838 if (
const auto *Ex = dyn_cast<Expr>(S))
840 C.emitReport(std::move(
Report));
844void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
846 const Expr *E,
const MemRegion *R,
847 StringRef Msg)
const {
849 "Can't emit from a checker that is not enabled!");
850 if (ExplodedNode *N =
C.generateErrorNode(State)) {
852 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
853 Report->addNote(
"Other elements might also be undefined",
857 Report->addVisitor<NoStoreFuncVisitor>(
R->castAs<SubRegion>());
858 C.emitReport(std::move(
Report));
862void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
864 StringRef WarningMsg)
const {
866 "Can't emit from a checker that is not enabled!");
867 if (ExplodedNode *N =
C.generateErrorNode(State)) {
872 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
874 C.emitReport(std::move(
Report));
878void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
880 StringRef WarningMsg)
const {
882 "Can't emit from a checker that is not enabled!");
883 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
885 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
888 C.emitReport(std::move(
Report));
895 NonLoc right)
const {
900 SValBuilder &svalBuilder =
C.getSValBuilder();
904 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
905 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
909 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
914 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
919 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
922 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
923 *maxMinusRightNL, cmpTy);
925 auto [StateOverflow, StateOkay] =
926 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
928 if (StateOverflow && !StateOkay) {
934 C.addSink(StateOverflow);
949 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
954 case MemRegion::StringRegionKind:
959 case MemRegion::SymbolicRegionKind:
960 case MemRegion::AllocaRegionKind:
961 case MemRegion::NonParamVarRegionKind:
962 case MemRegion::ParamVarRegionKind:
963 case MemRegion::FieldRegionKind:
964 case MemRegion::ObjCIvarRegionKind:
968 case MemRegion::ElementRegionKind:
982 return state->remove<CStringLength>(MR);
984 return state->set<CStringLength>(MR, strLength);
987SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
994 const SVal *Recorded = state->get<CStringLength>(MR);
1000 SValBuilder &svalBuilder =
C.getSValBuilder();
1004 C.getLocationContext(),
1007 if (!hypothetical) {
1008 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
1011 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1012 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
1013 std::optional<APSIntPtr> maxLengthInt =
1015 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
1016 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1018 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
1020 state = state->set<CStringLength>(MR, strLength);
1026const StringLiteral *
1027CStringChecker::getStringLiteralFromRegion(
const MemRegion *MR) {
1029 case MemRegion::StringRegionKind:
1031 case MemRegion::NonParamVarRegionKind:
1033 Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage())
1034 return dyn_cast_or_null<StringLiteral>(
Decl->getInit());
1041SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
1042 const Expr *Ex, SVal Buf,
1043 bool hypothetical)
const {
1049 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
1051 SmallString<120> buf;
1052 llvm::raw_svector_ostream os(buf);
1053 assert(CurrentFunctionDescription);
1054 os <<
"Argument to " << CurrentFunctionDescription
1055 <<
" is the address of the label '" << Label->getLabel()->getName()
1056 <<
"', which is not a null-terminated string";
1058 emitNotCStringBug(
C, state, Ex, os.str());
1060 return UndefinedVal();
1064 return UnknownVal();
1071 if (
const StringLiteral *StrLit = getStringLiteralFromRegion(MR)) {
1077 SValBuilder &SVB =
C.getSValBuilder();
1082 case MemRegion::StringRegionKind:
1083 case MemRegion::NonParamVarRegionKind:
1084 case MemRegion::SymbolicRegionKind:
1085 case MemRegion::AllocaRegionKind:
1086 case MemRegion::ParamVarRegionKind:
1087 case MemRegion::FieldRegionKind:
1088 case MemRegion::ObjCIvarRegionKind:
1089 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1090 case MemRegion::CompoundLiteralRegionKind:
1092 return UnknownVal();
1093 case MemRegion::ElementRegionKind: {
1098 const SubRegion *SuperReg =
1100 const StringLiteral *StrLit = getStringLiteralFromRegion(SuperReg);
1102 return UnknownVal();
1103 SValBuilder &SVB =
C.getSValBuilder();
1108 if (state->assume(SVB.
evalBinOpNN(state, BO_LE, Idx, LengthVal,
1110 .
castAs<DefinedOrUnknownSVal>(),
1112 return SVB.
evalBinOp(state, BO_Sub, LengthVal, Idx, SizeTy);
1113 return UnknownVal();
1120 SmallString<120> buf;
1121 llvm::raw_svector_ostream os(buf);
1123 assert(CurrentFunctionDescription);
1124 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1126 if (SummarizeRegion(os,
C.getASTContext(), MR))
1127 os <<
", which is not a null-terminated string";
1129 os <<
"not a null-terminated string";
1131 emitNotCStringBug(
C, state, Ex, os.str());
1133 return UndefinedVal();
1137const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1150 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1158bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1159 SVal BufVal, QualType BufTy,
1160 SVal LengthVal, QualType LengthTy) {
1169 SValBuilder &SB =
C.getSValBuilder();
1170 ASTContext &Ctx =
C.getASTContext();
1174 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1180 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1181 if (Offset.isUnknown())
1183 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1186 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1187 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1191 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1198 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1204 C.getASTContext().CharTy &&
1205 "isFirstBufInBound should only be called with char* ElementRegions");
1212 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1216 return static_cast<bool>(StInBound);
1222 auto InvalidationTraitOperations =
1223 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1224 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1227 if (MemRegion::FieldRegionKind ==
R->getKind() &&
1228 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1236 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1240CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1242 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1243 const MemRegion *
R) {
1247 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1250ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1252 auto InvalidationTraitOperations =
1253 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1254 if (MemRegion::FieldRegionKind ==
R->getKind())
1261 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1268 auto InvalidationTraitOperations =
1269 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1278 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1283 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1285 InvalidationTraitOperations) {
1286 std::optional<Loc> L =
V.getAs<Loc>();
1293 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1294 const MemRegion *
R = MR->getRegion()->
StripCasts();
1298 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1304 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
1305 RegionAndSymbolInvalidationTraits ITraits;
1306 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1308 return State->invalidateRegions(R, Elem,
C.blockCount(), LCtx,
1309 CausesPointerEscape,
nullptr,
nullptr,
1316 return State->killBinding(*L);
1319bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1320 const MemRegion *MR) {
1322 case MemRegion::FunctionCodeRegionKind: {
1324 os <<
"the address of the function '" << *FD <<
'\'';
1326 os <<
"the address of a function";
1329 case MemRegion::BlockCodeRegionKind:
1332 case MemRegion::BlockDataRegionKind:
1335 case MemRegion::CXXThisRegionKind:
1336 case MemRegion::CXXTempObjectRegionKind:
1337 os <<
"a C++ temp object of type "
1340 case MemRegion::NonParamVarRegionKind:
1343 case MemRegion::ParamVarRegionKind:
1346 case MemRegion::FieldRegionKind:
1349 case MemRegion::ObjCIvarRegionKind:
1350 os <<
"an instance variable of type "
1359 SVal CharVal,
const Expr *Size,
1361 SVal MemVal =
C.getSVal(DstBuffer);
1362 SVal SizeVal =
C.getSVal(Size);
1372 const MemRegion *BR = Offset.
getRegion();
1374 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1378 SValBuilder &svalBuilder =
C.getSValBuilder();
1379 ASTContext &Ctx =
C.getASTContext();
1389 std::tie(StateWholeReg, StateNotWholeReg) =
1390 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1397 std::tie(StateNullChar, StateNonNullChar) =
1400 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1401 !StateNonNullChar) {
1408 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1409 C.getLocationContext());
1413 State = invalidateDestinationBufferBySize(
1414 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1417 if (StateNullChar && !StateNonNullChar) {
1420 State = setCStringLength(State, MR,
1422 }
else if (!StateNullChar && StateNonNullChar) {
1424 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1425 C.getLocationContext(),
C.blockCount());
1429 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1432 State = setCStringLength(
1433 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1439 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1440 SizeVal,
Size->getType());
1449void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1451 DestinationArgExpr Dest,
1452 SourceArgExpr Source,
bool Restricted,
1453 bool IsMempcpy, CharKind CK)
const {
1454 CurrentFunctionDescription =
"memory copy function";
1457 const LocationContext *LCtx =
C.getLocationContext();
1458 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1459 QualType sizeTy =
Size.Expression->getType();
1462 std::tie(stateZeroSize, stateNonZeroSize) =
1463 assumeZero(
C, state, sizeVal, sizeTy);
1466 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1470 if (stateZeroSize && !stateNonZeroSize) {
1472 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1473 C.addTransition(stateZeroSize);
1478 if (stateNonZeroSize) {
1482 state = stateNonZeroSize;
1486 state = checkNonNull(
C, state, Dest, destVal);
1491 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1495 state = checkNonNull(
C, state, Source, srcVal);
1500 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1501 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1504 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1513 SValBuilder &SvalBuilder =
C.getSValBuilder();
1515 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1516 SVal DestRegCharVal =
1517 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1518 SVal lastElement =
C.getSValBuilder().evalBinOp(
1519 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1523 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1526 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1530 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1539 state = invalidateDestinationBufferBySize(
1540 C, state, Dest.Expression,
Call.getCFGElementRef(),
1541 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1545 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1546 C.getSVal(Source.Expression));
1548 C.addTransition(state);
1552void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1553 CharKind CK)
const {
1556 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1557 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1558 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1562 constexpr bool IsRestricted =
true;
1563 constexpr bool IsMempcpy =
false;
1564 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1567void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1568 CharKind CK)
const {
1571 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1572 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1573 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1575 constexpr bool IsRestricted =
true;
1576 constexpr bool IsMempcpy =
true;
1577 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1581void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1582 CharKind CK)
const {
1585 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1586 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1587 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1589 constexpr bool IsRestricted =
false;
1590 constexpr bool IsMempcpy =
false;
1591 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1595void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1597 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1598 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1599 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1601 constexpr bool IsRestricted =
false;
1602 constexpr bool IsMempcpy =
false;
1603 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1604 IsMempcpy, CharKind::Regular);
1607void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1608 CharKind CK)
const {
1610 CurrentFunctionDescription =
"memory comparison function";
1612 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1613 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1614 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1617 SValBuilder &Builder =
C.getSValBuilder();
1618 const LocationContext *LCtx =
C.getLocationContext();
1621 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1622 QualType sizeTy =
Size.Expression->getType();
1625 std::tie(stateZeroSize, stateNonZeroSize) =
1626 assumeZero(
C, State, sizeVal, sizeTy);
1630 if (stateZeroSize) {
1631 State = stateZeroSize;
1632 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1633 Builder.makeZeroVal(
Call.getResultType()));
1634 C.addTransition(State);
1638 if (stateNonZeroSize) {
1639 State = stateNonZeroSize;
1643 DefinedOrUnknownSVal LV =
1644 State->getSVal(
Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1645 DefinedOrUnknownSVal RV =
1646 State->getSVal(
Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1650 std::tie(SameBuffer, NotSameBuffer) =
1651 State->assume(Builder.evalEQ(State, LV, RV));
1655 if (SameBuffer && !NotSameBuffer) {
1657 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1659 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1660 Builder.makeZeroVal(
Call.getResultType()));
1661 C.addTransition(State);
1668 assert(NotSameBuffer);
1669 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1670 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1673 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1674 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1675 C.addTransition(State);
1680void CStringChecker::evalstrLength(CheckerContext &
C,
1681 const CallEvent &
Call)
const {
1683 evalstrLengthCommon(
C,
Call,
false);
1686void CStringChecker::evalstrnLength(CheckerContext &
C,
1687 const CallEvent &
Call)
const {
1689 evalstrLengthCommon(
C,
Call,
true);
1692void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1693 const CallEvent &
Call,
1694 bool IsStrnlen)
const {
1695 CurrentFunctionDescription =
"string length function";
1697 const LocationContext *LCtx =
C.getLocationContext();
1700 const Expr *maxlenExpr =
Call.getArgExpr(1);
1701 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1704 std::tie(stateZeroSize, stateNonZeroSize) =
1705 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1709 if (stateZeroSize) {
1710 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1711 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1712 C.addTransition(stateZeroSize);
1716 if (!stateNonZeroSize)
1720 state = stateNonZeroSize;
1724 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1725 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1726 state = checkNonNull(
C, state, Arg, ArgVal);
1731 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1738 DefinedOrUnknownSVal result = UnknownVal();
1743 QualType cmpTy =
C.getSValBuilder().getConditionType();
1747 const Expr *maxlenExpr =
Call.getArgExpr(1);
1748 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1750 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1751 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1753 if (strLengthNL && maxlenValNL) {
1757 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1759 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1760 .castAs<DefinedOrUnknownSVal>());
1762 if (stateStringTooLong && !stateStringNotTooLong) {
1764 result = *maxlenValNL;
1765 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1767 result = *strLengthNL;
1776 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1777 NonLoc resultNL = result.
castAs<NonLoc>();
1780 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1781 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1782 .castAs<DefinedOrUnknownSVal>(),
true);
1786 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1787 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1788 .castAs<DefinedOrUnknownSVal>(),
true);
1794 result = strLength.
castAs<DefinedOrUnknownSVal>();
1799 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1804 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1805 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1806 C.addTransition(state);
1809void CStringChecker::evalStrcpy(CheckerContext &
C,
1810 const CallEvent &
Call)
const {
1812 evalStrcpyCommon(
C,
Call,
1815 ConcatFnKind::none);
1818void CStringChecker::evalStrncpy(CheckerContext &
C,
1819 const CallEvent &
Call)
const {
1821 evalStrcpyCommon(
C,
Call,
1824 ConcatFnKind::none);
1827void CStringChecker::evalStpcpy(CheckerContext &
C,
1828 const CallEvent &
Call)
const {
1830 evalStrcpyCommon(
C,
Call,
1833 ConcatFnKind::none);
1836void CStringChecker::evalStrlcpy(CheckerContext &
C,
1837 const CallEvent &
Call)
const {
1839 evalStrcpyCommon(
C,
Call,
1846void CStringChecker::evalStrcat(CheckerContext &
C,
1847 const CallEvent &
Call)
const {
1849 evalStrcpyCommon(
C,
Call,
1852 ConcatFnKind::strcat);
1855void CStringChecker::evalStrncat(CheckerContext &
C,
1856 const CallEvent &
Call)
const {
1858 evalStrcpyCommon(
C,
Call,
1861 ConcatFnKind::strcat);
1864void CStringChecker::evalStrlcat(CheckerContext &
C,
1865 const CallEvent &
Call)
const {
1869 evalStrcpyCommon(
C,
Call,
1872 ConcatFnKind::strlcat,
1876void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1877 bool ReturnEnd,
bool IsBounded,
1878 ConcatFnKind appendK,
1879 bool returnPtr)
const {
1880 if (appendK == ConcatFnKind::none)
1881 CurrentFunctionDescription =
"string copy function";
1883 CurrentFunctionDescription =
"string concatenation function";
1886 const LocationContext *LCtx =
C.getLocationContext();
1889 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1890 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1891 state = checkNonNull(
C, state, Dst, DstVal);
1896 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1897 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1898 state = checkNonNull(
C, state, srcExpr, srcVal);
1903 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1904 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1907 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1908 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1914 SValBuilder &svalBuilder =
C.getSValBuilder();
1921 SVal amountCopied = UnknownVal();
1922 SVal maxLastElementIndex = UnknownVal();
1923 const char *boundWarning =
nullptr;
1927 SizeArgExpr SrcExprAsSizeDummy = {
1928 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1929 state = CheckOverlap(
1931 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1940 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1941 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1945 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1947 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1951 if (strLengthNL && lenValNL) {
1953 case ConcatFnKind::none:
1954 case ConcatFnKind::strcat: {
1959 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1961 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1962 .castAs<DefinedOrUnknownSVal>());
1964 if (stateSourceTooLong && !stateSourceNotTooLong) {
1967 state = stateSourceTooLong;
1968 amountCopied = lenVal;
1970 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1972 state = stateSourceNotTooLong;
1973 amountCopied = strLength;
1977 case ConcatFnKind::strlcat:
1978 if (!dstStrLengthNL)
1982 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
1983 *dstStrLengthNL, sizeTy);
1987 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1989 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
1996 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1999 std::tie(TrueState, FalseState) =
2000 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
2003 if (TrueState && !FalseState) {
2004 amountCopied = strLength;
2008 if (!TrueState && FalseState) {
2009 amountCopied = freeSpace;
2012 if (TrueState && FalseState)
2013 amountCopied = UnknownVal();
2020 case ConcatFnKind::strcat:
2026 if (dstStrLength.isUndef())
2029 if (dstStrLengthNL) {
2031 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2033 boundWarning =
"Size argument is greater than the free space in the "
2034 "destination buffer";
2037 case ConcatFnKind::none:
2038 case ConcatFnKind::strlcat:
2048 std::tie(StateZeroSize, StateNonZeroSize) =
2049 assumeZero(
C, state, *lenValNL, sizeTy);
2052 if (StateZeroSize && !StateNonZeroSize) {
2055 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
2057 if (appendK == ConcatFnKind::none) {
2059 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
2064 state, BO_Add, strLength, dstStrLength, sizeTy);
2066 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
2069 C.addTransition(StateZeroSize);
2077 maxLastElementIndex =
2078 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2079 boundWarning =
"Size argument is greater than the length of the "
2080 "destination buffer";
2087 amountCopied = strLength;
2095 SVal finalStrLength = UnknownVal();
2096 SVal strlRetVal = UnknownVal();
2098 if (appendK == ConcatFnKind::none && !returnPtr) {
2100 strlRetVal = strLength;
2106 if (appendK != ConcatFnKind::none) {
2109 if (dstStrLength.isUndef())
2112 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2113 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2114 *dstStrLengthNL, sizeTy);
2117 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2120 if (amountCopiedNL && dstStrLengthNL) {
2122 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2126 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2127 *dstStrLengthNL, sizeTy);
2136 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2137 assert(!finalStrLength.
isUndef());
2139 if (std::optional<NonLoc> finalStrLengthNL =
2140 finalStrLength.
getAs<NonLoc>()) {
2141 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2145 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2146 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2152 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2155 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2160 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2170 finalStrLength = amountCopied;
2178 Result = (ReturnEnd ? UnknownVal() : DstVal);
2180 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2191 if (std::optional<loc::MemRegionVal> dstRegVal =
2192 DstVal.
getAs<loc::MemRegionVal>()) {
2193 QualType ptrTy = Dst.Expression->getType();
2197 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2198 SVal maxLastElement =
2199 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2202 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2206 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2212 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2213 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2214 *knownStrLength, ptrTy);
2217 if (!boundWarning) {
2219 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2223 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2229 if (returnPtr && ReturnEnd)
2242 bool CouldAccessOutOfBound =
true;
2243 if (IsBounded && amountCopied.
isUnknown()) {
2244 auto CouldAccessOutOfBoundForSVal =
2245 [&](std::optional<NonLoc> Val) ->
bool {
2248 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2249 Dst.Expression->getType(), *Val,
2250 C.getASTContext().getSizeType());
2253 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2255 if (CouldAccessOutOfBound) {
2257 const Expr *LenExpr =
Call.getArgExpr(2);
2258 SVal LenVal = state->getSVal(LenExpr, LCtx);
2266 CouldAccessOutOfBound =
2267 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2278 if (CouldAccessOutOfBound)
2279 state = invalidateDestinationBufferBySize(
2280 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2281 amountCopied,
C.getASTContext().getSizeType());
2283 state = invalidateDestinationBufferNeverOverflows(
2284 C, state,
Call.getCFGElementRef(), *dstRegVal);
2288 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2291 if (IsBounded && (appendK == ConcatFnKind::none)) {
2296 if (amountCopied != strLength)
2297 finalStrLength = UnknownVal();
2299 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2307 if (ReturnEnd &&
Result.isUnknown()) {
2312 state = state->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2313 C.addTransition(state);
2316void CStringChecker::evalStrxfrm(CheckerContext &
C,
2317 const CallEvent &
Call)
const {
2319 CurrentFunctionDescription =
"locale transformation function";
2322 const LocationContext *LCtx =
C.getLocationContext();
2323 SValBuilder &SVB =
C.getSValBuilder();
2326 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2327 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2328 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2331 SVal SrcVal = State->getSVal(Source.Expression, LCtx);
2332 State = checkNonNull(
C, State, Source, SrcVal);
2337 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2345 auto BindReturnAndTransition = [&RetVal, &
Call, LCtx,
2348 State = State->BindExpr(
Call.getOriginExpr(), LCtx, RetVal);
2349 C.addTransition(State);
2354 SVal SizeVal = State->getSVal(
Size.Expression, LCtx);
2355 QualType SizeTy =
Size.Expression->getType();
2357 auto [StateZeroSize, StateSizeNonZero] =
2358 assumeZero(
C, State, SizeVal, SizeTy);
2361 if (!StateZeroSize && !StateSizeNonZero)
2362 return BindReturnAndTransition(State);
2365 if (StateZeroSize && !StateSizeNonZero)
2366 return BindReturnAndTransition(StateZeroSize);
2369 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, LCtx);
2370 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2371 if (!StateSizeNonZero)
2375 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2376 AccessKind::write, CK_Regular);
2377 if (!StateSizeNonZero)
2382 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2384 .
getAs<DefinedOrUnknownSVal>();
2385 if (!ComparisonVal) {
2387 StateSizeNonZero = invalidateDestinationBufferBySize(
2388 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2389 SizeVal,
Size.Expression->getType());
2390 return BindReturnAndTransition(StateSizeNonZero);
2393 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2397 StateSuccess = invalidateDestinationBufferBySize(
2398 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2399 SizeVal,
Size.Expression->getType());
2400 BindReturnAndTransition(StateSuccess);
2406 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2407 StateFailure = StateFailure->killBinding(*DestLoc);
2409 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, LCtx);
2412 BindReturnAndTransition(StateFailure);
2416void CStringChecker::evalStrcmp(CheckerContext &
C,
2417 const CallEvent &
Call)
const {
2419 evalStrcmpCommon(
C,
Call,
false,
false);
2422void CStringChecker::evalStrncmp(CheckerContext &
C,
2423 const CallEvent &
Call)
const {
2425 evalStrcmpCommon(
C,
Call,
true,
false);
2428void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2429 const CallEvent &
Call)
const {
2431 evalStrcmpCommon(
C,
Call,
false,
true);
2434void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2435 const CallEvent &
Call)
const {
2437 evalStrcmpCommon(
C,
Call,
true,
true);
2440void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2441 bool IsBounded,
bool IgnoreCase)
const {
2442 CurrentFunctionDescription =
"string comparison function";
2444 const LocationContext *LCtx =
C.getLocationContext();
2447 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2448 SVal LeftVal = state->getSVal(
Left.Expression, LCtx);
2449 state = checkNonNull(
C, state, Left, LeftVal);
2454 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2455 SVal RightVal = state->getSVal(
Right.Expression, LCtx);
2456 state = checkNonNull(
C, state, Right, RightVal);
2461 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2466 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2473 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2474 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2477 SValBuilder &svalBuilder =
C.getSValBuilder();
2478 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2480 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2486 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2487 svalBuilder.makeZeroVal(
Call.getResultType()));
2488 C.addTransition(StSameBuf);
2495 assert(StNotSameBuf);
2496 state = StNotSameBuf;
2502 const StringLiteral *LeftStrLiteral =
2503 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2504 const StringLiteral *RightStrLiteral =
2505 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2506 bool canComputeResult =
false;
2507 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2509 if (LeftStrLiteral && RightStrLiteral) {
2510 StringRef LeftStrRef = LeftStrLiteral->
getString();
2511 StringRef RightStrRef = RightStrLiteral->
getString();
2515 const Expr *lenExpr =
Call.getArgExpr(2);
2516 SVal lenVal = state->getSVal(lenExpr, LCtx);
2519 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2521 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2522 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2523 canComputeResult =
true;
2527 canComputeResult =
true;
2530 if (canComputeResult) {
2532 size_t s1Term = LeftStrRef.find(
'\0');
2533 if (s1Term != StringRef::npos)
2534 LeftStrRef = LeftStrRef.substr(0, s1Term);
2536 size_t s2Term = RightStrRef.find(
'\0');
2537 if (s2Term != StringRef::npos)
2538 RightStrRef = RightStrRef.substr(0, s2Term);
2541 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2542 : LeftStrRef.compare(RightStrRef);
2546 if (compareRes == 0) {
2547 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2550 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2554 SVal compareWithZero =
2555 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2556 svalBuilder.getConditionType());
2557 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2558 state = state->assume(compareWithZeroVal,
true);
2563 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2566 C.addTransition(state);
2569void CStringChecker::evalStrsep(CheckerContext &
C,
2570 const CallEvent &
Call)
const {
2573 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2575 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2576 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2580 CurrentFunctionDescription =
"strsep()";
2582 const LocationContext *LCtx =
C.getLocationContext();
2586 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2587 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2592 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2593 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2594 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2598 SValBuilder &SVB =
C.getSValBuilder();
2600 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2602 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2607 State = invalidateDestinationBufferNeverOverflows(
2612 State = State->bindLoc(*SearchStrLoc,
2622 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2623 C.addTransition(State);
2627void CStringChecker::evalStdCopy(CheckerContext &
C,
2628 const CallEvent &
Call)
const {
2629 evalStdCopyCommon(
C,
Call);
2632void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2633 const CallEvent &
Call)
const {
2634 evalStdCopyCommon(
C,
Call);
2637void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2638 const CallEvent &
Call)
const {
2639 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2644 const LocationContext *LCtx =
C.getLocationContext();
2652 const Expr *Dst =
Call.getArgExpr(2);
2653 SVal DstVal = State->getSVal(Dst, LCtx);
2656 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2657 C, State,
Call.getCFGElementRef(), DstVal);
2659 SValBuilder &SVB =
C.getSValBuilder();
2662 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2664 C.addTransition(State);
2667void CStringChecker::evalMemset(CheckerContext &
C,
2668 const CallEvent &
Call)
const {
2670 CurrentFunctionDescription =
"memory set function";
2672 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2673 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2674 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2679 const LocationContext *LCtx =
C.getLocationContext();
2680 SVal SizeVal =
C.getSVal(
Size.Expression);
2681 QualType SizeTy =
Size.Expression->getType();
2684 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2687 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2691 if (ZeroSize && !NonZeroSize) {
2692 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2693 C.addTransition(ZeroSize);
2699 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2703 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2710 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2711 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2714 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2715 C.addTransition(State);
2718void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2719 CurrentFunctionDescription =
"memory clearance function";
2721 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2722 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2723 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2728 SVal SizeVal =
C.getSVal(
Size.Expression);
2729 QualType SizeTy =
Size.Expression->getType();
2732 std::tie(StateZeroSize, StateNonZeroSize) =
2733 assumeZero(
C, State, SizeVal, SizeTy);
2737 if (StateZeroSize && !StateNonZeroSize) {
2738 C.addTransition(StateZeroSize);
2743 SVal MemVal =
C.getSVal(Buffer.Expression);
2747 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2751 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2755 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
2756 Size.Expression,
C, State))
2759 C.addTransition(State);
2762void CStringChecker::evalSprintf(CheckerContext &
C,
2763 const CallEvent &
Call)
const {
2764 CurrentFunctionDescription =
"'sprintf'";
2765 evalSprintfCommon(
C,
Call,
false);
2768void CStringChecker::evalSnprintf(CheckerContext &
C,
2769 const CallEvent &
Call)
const {
2770 CurrentFunctionDescription =
"'snprintf'";
2771 evalSprintfCommon(
C,
Call,
true);
2774void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
2775 bool IsBounded)
const {
2778 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2780 const auto NumParams =
Call.parameters().size();
2781 if (CE->getNumArgs() < NumParams) {
2786 const auto AllArguments =
2787 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2788 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2790 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2792 if (
const QualType
type = ArgExpr->getType();
2793 !
type->isAnyPointerType() ||
2794 !
type->getPointeeType()->isAnyCharacterType())
2796 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
2799 SizeArgExpr SrcExprAsSizeDummy = {
2800 {Source.Expression, Source.ArgumentIndex}};
2801 State = CheckOverlap(
2803 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2809 C.addTransition(State);
2816CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2817 CheckerContext &
C)
const {
2818 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2822 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
2827 return &CStringChecker::evalStdCopy;
2829 return &CStringChecker::evalStdCopyBackward;
2835 for (
auto I : CE->arguments()) {
2836 QualType T = I->getType();
2841 const FnCheck *Callback = Callbacks.lookup(
Call);
2848bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
2849 FnCheck Callback = identifyCall(
Call,
C);
2857 Callback(
this,
C,
Call);
2865 return C.isDifferent();
2868void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
2872 for (
const auto *I : DS->
decls()) {
2873 const VarDecl *D = dyn_cast<VarDecl>(I);
2887 Loc VarLoc = state->getLValue(D,
C.getLocationContext());
2892 SVal StrVal =
C.getSVal(
Init);
2893 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2894 DefinedOrUnknownSVal strLength =
2895 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
2897 state = state->set<CStringLength>(MR, strLength);
2900 C.addTransition(state);
2906 ArrayRef<const MemRegion *> ExplicitRegions,
2907 ArrayRef<const MemRegion *> Regions,
2908 const LocationContext *LCtx,
2909 const CallEvent *
Call)
const {
2910 CStringLengthTy Entries = state->get<CStringLength>();
2911 if (Entries.isEmpty())
2914 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2915 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2918 for (
const MemRegion *MR : Regions) {
2919 Invalidated.insert(MR);
2921 SuperRegions.insert(MR);
2922 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2923 MR = SR->getSuperRegion();
2924 SuperRegions.insert(MR);
2928 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2931 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2933 if (SuperRegions.count(MR)) {
2934 Entries = F.remove(Entries, MR);
2939 const MemRegion *Super = MR;
2940 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2941 Super = SR->getSuperRegion();
2942 if (Invalidated.count(Super)) {
2943 Entries = F.remove(Entries, MR);
2949 return state->set<CStringLength>(Entries);
2953 SymbolReaper &SR)
const {
2955 CStringLengthTy Entries = state->get<CStringLength>();
2957 for (SVal Len : llvm::make_second_range(Entries)) {
2963void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2964 CheckerContext &
C)
const {
2966 CStringLengthTy Entries = state->get<CStringLength>();
2967 if (Entries.isEmpty())
2970 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2971 for (
auto [Reg, Len] : Entries) {
2972 if (
SymbolRef Sym = Len.getAsSymbol()) {
2974 Entries = F.remove(Entries, Reg);
2978 state = state->set<CStringLength>(Entries);
2979 C.addTransition(state);
2982void ento::registerCStringModeling(CheckerManager &Mgr) {
2989bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
2993#define REGISTER_CHECKER(NAME) \
2994 void ento::registerCString##NAME(CheckerManager &Mgr) { \
2995 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
2998 bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \
3008#undef REGISTER_CHECKER
static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx)
#define REGISTER_CHECKER(name)
#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.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
SValBuilder & getSValBuilder()
@ TK_PreserveContents
Tells that a region's contents is not changed.
@ TK_DoNotInvalidateSuperRegion
@ TK_SuppressEscape
Suppress pointer-escaping of a region.
void setTrait(SymbolRef Sym, InvalidationKinds IK)
bool hasSymbolicOffset() const
const MemRegion * getRegion() const
It might return null.
int64_t getOffset() const
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with a memory location and non-location opera...
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.
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
U cast(CodeGen::Address addr)
int const char * function