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 SVal getCStringLength(CheckerContext &
C,
258 bool hypothetical =
false)
const;
260 const StringLiteral *getCStringLiteral(CheckerContext &
C,
269 SVal BufV, SVal SizeV, QualType SizeTy);
277 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
291 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
293 InvalidationTraitOperations);
295 static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
296 const MemRegion *MR);
299 SVal CharE,
const Expr *Size, CheckerContext &
C,
304 AnyArgExpr Arg, SVal l)
const;
308 AnyArgExpr Buffer, SVal Element, SVal Size)
const;
310 AnyArgExpr Buffer, SVal Element,
312 CharKind CK = CharKind::Regular)
const;
314 AnyArgExpr Buffer, SizeArgExpr Size,
316 CharKind CK = CharKind::Regular)
const;
318 SizeArgExpr Size, AnyArgExpr
First,
320 CharKind CK = CharKind::Regular)
const;
321 void emitOverlapBug(CheckerContext &
C,
324 const Stmt *Second)
const;
326 void emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
const Stmt *S,
327 StringRef WarningMsg)
const;
329 const Stmt *S, StringRef WarningMsg)
const;
331 const Stmt *S, StringRef WarningMsg)
const;
333 const Expr *E,
const MemRegion *R,
334 StringRef Msg)
const;
344 SVal BufVal, QualType BufTy, SVal LengthVal,
356std::pair<ProgramStateRef, ProgramStateRef>
359 std::optional<DefinedSVal> val =
V.getAs<DefinedSVal>();
361 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
363 SValBuilder &svalBuilder =
C.getSValBuilder();
364 DefinedOrUnknownSVal zero = svalBuilder.
makeZeroVal(Ty);
365 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
370 AnyArgExpr Arg, SVal l)
const {
376 std::tie(stateNull, stateNonNull) =
377 assumeZero(
C, State, l, Arg.Expression->
getType());
379 if (stateNull && !stateNonNull) {
382 llvm::raw_svector_ostream
OS(buf);
383 assert(CurrentFunctionDescription);
384 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
385 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
386 << CurrentFunctionDescription;
388 emitNullArgBug(
C, stateNull, Arg.Expression,
OS.str());
394 assert(stateNonNull);
403 if (CK == CharKind::Regular) {
419 if (Offset.isUnknown())
426 Os << Idx << llvm::getOrdinalSuffix(Idx);
431 AnyArgExpr Buffer, SVal Element,
439 const auto *ER = dyn_cast_or_null<ElementRegion>(R);
443 const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
449 if (!SuperR->getValueType()->isArrayType())
452 SValBuilder &SVB =
C.getSValBuilder();
458 std::optional<Loc> FirstElementVal =
459 State->getLValue(ElemTy,
Zero, loc::MemRegionVal(SuperR)).getAs<Loc>();
460 if (!FirstElementVal)
465 State->getSVal(*FirstElementVal).isUndef()) {
466 llvm::SmallString<258> Buf;
467 llvm::raw_svector_ostream
OS(Buf);
468 OS <<
"The first element of the ";
470 OS <<
" argument is undefined";
471 emitUninitializedReadBug(
C, State, Buffer.Expression,
472 FirstElementVal->getAsRegion(),
OS.str());
503 std::optional<NonLoc> Offset =
510 SVal LastIdx = SVB.
evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);
515 SVal LastElementVal =
516 State->getLValue(ElemTy, LastIdx, loc::MemRegionVal(SuperR));
521 State->getSVal(LastElementVal.
castAs<Loc>()).isUndef()) {
522 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
529 llvm::SmallString<258> Buf;
530 llvm::raw_svector_ostream
OS(Buf);
531 OS <<
"The last accessed element (at index ";
532 OS << IdxInt->getExtValue();
535 OS <<
" argument is undefined";
536 emitUninitializedReadBug(
C, State, Buffer.Expression,
548 AnyArgExpr Buffer, SVal Element,
561 const auto *ER = dyn_cast<ElementRegion>(R);
566 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
572 DefinedOrUnknownSVal
Size =
575 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
576 if (StOutBound && !StInBound) {
581 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
582 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
593 AnyArgExpr Buffer, SizeArgExpr Size,
594 AccessKind Access, CharKind CK)
const {
599 SValBuilder &svalBuilder =
C.getSValBuilder();
602 QualType SizeTy =
Size.Expression->getType();
603 QualType PtrTy = getCharPtrType(Ctx, CK);
606 SVal BufVal =
C.getSVal(Buffer.Expression);
607 State = checkNonNull(
C, State, Buffer, BufVal);
619 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
627 SVal LengthVal =
C.getSVal(
Size.Expression);
628 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
634 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
635 if (Offset.isUnknown())
637 NonLoc LastOffset = Offset.
castAs<NonLoc>();
640 if (std::optional<Loc> BufLoc = BufStart.
getAs<Loc>()) {
643 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
644 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
645 if (Access == AccessKind::read)
646 State = checkInit(
C, State, Buffer, BufEnd, *Length);
659 SizeArgExpr Size, AnyArgExpr
First,
675 if (!
First.Expression->getType()->isAnyPointerType() ||
680 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
685 const LocationContext *LCtx =
C.getLocationContext();
686 SVal firstVal = state->getSVal(
First.Expression, LCtx);
687 SVal secondVal = state->getSVal(Second.Expression, LCtx);
689 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
693 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
698 SValBuilder &svalBuilder =
C.getSValBuilder();
699 std::tie(stateTrue, stateFalse) =
700 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
702 if (stateTrue && !stateFalse) {
704 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
715 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
716 std::optional<DefinedOrUnknownSVal> reverseTest =
717 reverse.
getAs<DefinedOrUnknownSVal>();
721 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
728 std::swap(firstLoc, secondLoc);
731 std::swap(
First, Second);
736 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
737 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
744 QualType CharPtrTy = getCharPtrType(Ctx, CK);
746 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
747 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
752 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
754 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
760 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
761 std::optional<DefinedOrUnknownSVal> OverlapTest =
762 Overlap.
getAs<DefinedOrUnknownSVal>();
766 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
768 if (stateTrue && !stateFalse) {
770 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
779void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
780 const Stmt *
First,
const Stmt *Second)
const {
781 ExplodedNode *N =
C.generateErrorNode(state);
786 auto report = std::make_unique<PathSensitiveBugReport>(
787 BufferOverlap,
"Arguments must not be overlapping buffers", N);
788 report->addRange(
First->getSourceRange());
791 C.emitReport(std::move(report));
794void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
795 const Stmt *S, StringRef WarningMsg)
const {
796 if (ExplodedNode *N =
C.generateErrorNode(State)) {
798 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
800 if (
const auto *Ex = dyn_cast<Expr>(S))
802 C.emitReport(std::move(
Report));
806void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
808 const Expr *E,
const MemRegion *R,
809 StringRef Msg)
const {
810 if (ExplodedNode *N =
C.generateErrorNode(State)) {
812 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
813 Report->addNote(
"Other elements might also be undefined",
817 Report->addVisitor<NoStoreFuncVisitor>(R->
castAs<SubRegion>());
818 C.emitReport(std::move(
Report));
822void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
824 StringRef WarningMsg)
const {
825 if (ExplodedNode *N =
C.generateErrorNode(State)) {
830 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
832 C.emitReport(std::move(
Report));
836void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
838 StringRef WarningMsg)
const {
839 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
841 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
844 C.emitReport(std::move(
Report));
851 NonLoc right)
const {
860 SValBuilder &svalBuilder =
C.getSValBuilder();
864 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
865 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
869 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
874 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
879 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
882 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
883 *maxMinusRightNL, cmpTy);
885 auto [StateOverflow, StateOkay] =
886 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
888 if (StateOverflow && !StateOkay) {
894 C.addSink(StateOverflow);
909 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
914 case MemRegion::StringRegionKind:
919 case MemRegion::SymbolicRegionKind:
920 case MemRegion::AllocaRegionKind:
921 case MemRegion::NonParamVarRegionKind:
922 case MemRegion::ParamVarRegionKind:
923 case MemRegion::FieldRegionKind:
924 case MemRegion::ObjCIvarRegionKind:
928 case MemRegion::ElementRegionKind:
942 return state->remove<CStringLength>(MR);
944 return state->set<CStringLength>(MR, strLength);
947SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
954 const SVal *Recorded = state->get<CStringLength>(MR);
960 SValBuilder &svalBuilder =
C.getSValBuilder();
964 C.getLocationContext(),
968 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
971 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
972 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
973 std::optional<APSIntPtr> maxLengthInt =
975 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
976 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
978 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
980 state = state->set<CStringLength>(MR, strLength);
986SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
987 const Expr *Ex, SVal Buf,
988 bool hypothetical)
const {
994 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
996 SmallString<120> buf;
997 llvm::raw_svector_ostream os(buf);
998 assert(CurrentFunctionDescription);
999 os <<
"Argument to " << CurrentFunctionDescription
1000 <<
" is the address of the label '" << Label->getLabel()->getName()
1001 <<
"', which is not a null-terminated string";
1003 emitNotCStringBug(
C, state, Ex, os.str());
1005 return UndefinedVal();
1009 return UnknownVal();
1017 case MemRegion::StringRegionKind: {
1020 SValBuilder &svalBuilder =
C.getSValBuilder();
1025 case MemRegion::NonParamVarRegionKind: {
1029 if (
Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage()) {
1030 if (
const Expr *
Init =
Decl->getInit()) {
1031 if (
auto *StrLit = dyn_cast<StringLiteral>(
Init)) {
1032 SValBuilder &SvalBuilder =
C.getSValBuilder();
1034 return SvalBuilder.
makeIntVal(StrLit->getLength(), SizeTy);
1040 case MemRegion::SymbolicRegionKind:
1041 case MemRegion::AllocaRegionKind:
1042 case MemRegion::ParamVarRegionKind:
1043 case MemRegion::FieldRegionKind:
1044 case MemRegion::ObjCIvarRegionKind:
1045 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1046 case MemRegion::CompoundLiteralRegionKind:
1048 return UnknownVal();
1049 case MemRegion::ElementRegionKind:
1052 return UnknownVal();
1058 SmallString<120> buf;
1059 llvm::raw_svector_ostream os(buf);
1061 assert(CurrentFunctionDescription);
1062 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1064 if (SummarizeRegion(os,
C.getASTContext(), MR))
1065 os <<
", which is not a null-terminated string";
1067 os <<
"not a null-terminated string";
1069 emitNotCStringBug(
C, state, Ex, os.str());
1071 return UndefinedVal();
1075const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1087 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1095bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1096 SVal BufVal, QualType BufTy,
1097 SVal LengthVal, QualType LengthTy) {
1106 SValBuilder &SB =
C.getSValBuilder();
1107 ASTContext &Ctx =
C.getASTContext();
1111 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1117 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1118 if (Offset.isUnknown())
1120 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1123 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1124 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1128 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1135 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1141 C.getASTContext().CharTy &&
1142 "isFirstBufInBound should only be called with char* ElementRegions");
1149 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1153 return static_cast<bool>(StInBound);
1159 auto InvalidationTraitOperations =
1160 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1161 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1164 if (MemRegion::FieldRegionKind == R->
getKind() &&
1165 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1173 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1177CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1179 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1180 const MemRegion *R) {
1184 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1187ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1189 auto InvalidationTraitOperations =
1190 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1191 if (MemRegion::FieldRegionKind == R->
getKind())
1198 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1205 auto InvalidationTraitOperations =
1206 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1215 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1220 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1222 InvalidationTraitOperations) {
1223 std::optional<Loc> L =
V.getAs<Loc>();
1230 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1231 const MemRegion *R = MR->getRegion()->
StripCasts();
1235 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1241 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
1242 RegionAndSymbolInvalidationTraits ITraits;
1243 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1245 return State->invalidateRegions(R, Elem,
C.blockCount(), LCtx,
1246 CausesPointerEscape,
nullptr,
nullptr,
1253 return State->killBinding(*L);
1256bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1257 const MemRegion *MR) {
1259 case MemRegion::FunctionCodeRegionKind: {
1261 os <<
"the address of the function '" << *FD <<
'\'';
1263 os <<
"the address of a function";
1266 case MemRegion::BlockCodeRegionKind:
1269 case MemRegion::BlockDataRegionKind:
1272 case MemRegion::CXXThisRegionKind:
1273 case MemRegion::CXXTempObjectRegionKind:
1274 os <<
"a C++ temp object of type "
1277 case MemRegion::NonParamVarRegionKind:
1280 case MemRegion::ParamVarRegionKind:
1283 case MemRegion::FieldRegionKind:
1286 case MemRegion::ObjCIvarRegionKind:
1287 os <<
"an instance variable of type "
1296 SVal CharVal,
const Expr *Size,
1298 SVal MemVal =
C.getSVal(DstBuffer);
1299 SVal SizeVal =
C.getSVal(Size);
1309 const MemRegion *BR = Offset.
getRegion();
1311 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1315 SValBuilder &svalBuilder =
C.getSValBuilder();
1316 ASTContext &Ctx =
C.getASTContext();
1326 std::tie(StateWholeReg, StateNotWholeReg) =
1327 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1334 std::tie(StateNullChar, StateNonNullChar) =
1337 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1338 !StateNonNullChar) {
1345 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1346 C.getLocationContext());
1350 State = invalidateDestinationBufferBySize(
1351 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1354 if (StateNullChar && !StateNonNullChar) {
1357 State = setCStringLength(State, MR,
1359 }
else if (!StateNullChar && StateNonNullChar) {
1361 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1362 C.getLocationContext(),
C.blockCount());
1366 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1369 State = setCStringLength(
1370 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1376 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1377 SizeVal,
Size->getType());
1386void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1388 DestinationArgExpr Dest,
1389 SourceArgExpr Source,
bool Restricted,
1390 bool IsMempcpy, CharKind CK)
const {
1391 CurrentFunctionDescription =
"memory copy function";
1394 const LocationContext *LCtx =
C.getLocationContext();
1395 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1396 QualType sizeTy =
Size.Expression->getType();
1399 std::tie(stateZeroSize, stateNonZeroSize) =
1400 assumeZero(
C, state, sizeVal, sizeTy);
1403 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1407 if (stateZeroSize && !stateNonZeroSize) {
1409 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1410 C.addTransition(stateZeroSize);
1415 if (stateNonZeroSize) {
1419 state = stateNonZeroSize;
1423 state = checkNonNull(
C, state, Dest, destVal);
1428 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1432 state = checkNonNull(
C, state, Source, srcVal);
1437 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1438 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1441 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1450 SValBuilder &SvalBuilder =
C.getSValBuilder();
1452 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1453 SVal DestRegCharVal =
1454 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1455 SVal lastElement =
C.getSValBuilder().evalBinOp(
1456 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1460 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1463 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1467 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1476 state = invalidateDestinationBufferBySize(
1477 C, state, Dest.Expression,
Call.getCFGElementRef(),
1478 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1482 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1483 C.getSVal(Source.Expression));
1485 C.addTransition(state);
1489void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1490 CharKind CK)
const {
1493 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1494 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1495 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1499 constexpr bool IsRestricted =
true;
1500 constexpr bool IsMempcpy =
false;
1501 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1504void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1505 CharKind CK)
const {
1508 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1509 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1510 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1512 constexpr bool IsRestricted =
true;
1513 constexpr bool IsMempcpy =
true;
1514 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1518void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1519 CharKind CK)
const {
1522 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1523 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1524 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1526 constexpr bool IsRestricted =
false;
1527 constexpr bool IsMempcpy =
false;
1528 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1532void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1534 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1535 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1536 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1538 constexpr bool IsRestricted =
false;
1539 constexpr bool IsMempcpy =
false;
1540 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1541 IsMempcpy, CharKind::Regular);
1544void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1545 CharKind CK)
const {
1547 CurrentFunctionDescription =
"memory comparison function";
1549 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1550 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1551 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1554 SValBuilder &Builder =
C.getSValBuilder();
1555 const LocationContext *LCtx =
C.getLocationContext();
1558 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1559 QualType sizeTy =
Size.Expression->getType();
1562 std::tie(stateZeroSize, stateNonZeroSize) =
1563 assumeZero(
C, State, sizeVal, sizeTy);
1567 if (stateZeroSize) {
1568 State = stateZeroSize;
1569 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1570 Builder.makeZeroVal(
Call.getResultType()));
1571 C.addTransition(State);
1575 if (stateNonZeroSize) {
1576 State = stateNonZeroSize;
1580 DefinedOrUnknownSVal LV =
1581 State->getSVal(
Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1582 DefinedOrUnknownSVal RV =
1583 State->getSVal(
Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1587 std::tie(SameBuffer, NotSameBuffer) =
1588 State->assume(Builder.evalEQ(State, LV, RV));
1592 if (SameBuffer && !NotSameBuffer) {
1594 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1596 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1597 Builder.makeZeroVal(
Call.getResultType()));
1598 C.addTransition(State);
1605 assert(NotSameBuffer);
1606 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1607 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1610 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1611 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1612 C.addTransition(State);
1617void CStringChecker::evalstrLength(CheckerContext &
C,
1618 const CallEvent &
Call)
const {
1620 evalstrLengthCommon(
C,
Call,
false);
1623void CStringChecker::evalstrnLength(CheckerContext &
C,
1624 const CallEvent &
Call)
const {
1626 evalstrLengthCommon(
C,
Call,
true);
1629void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1630 const CallEvent &
Call,
1631 bool IsStrnlen)
const {
1632 CurrentFunctionDescription =
"string length function";
1634 const LocationContext *LCtx =
C.getLocationContext();
1637 const Expr *maxlenExpr =
Call.getArgExpr(1);
1638 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1641 std::tie(stateZeroSize, stateNonZeroSize) =
1642 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1646 if (stateZeroSize) {
1647 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1648 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1649 C.addTransition(stateZeroSize);
1653 if (!stateNonZeroSize)
1657 state = stateNonZeroSize;
1661 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1662 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1663 state = checkNonNull(
C, state, Arg, ArgVal);
1668 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1675 DefinedOrUnknownSVal result = UnknownVal();
1680 QualType cmpTy =
C.getSValBuilder().getConditionType();
1684 const Expr *maxlenExpr =
Call.getArgExpr(1);
1685 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1687 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1688 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1690 if (strLengthNL && maxlenValNL) {
1694 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1696 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1697 .castAs<DefinedOrUnknownSVal>());
1699 if (stateStringTooLong && !stateStringNotTooLong) {
1701 result = *maxlenValNL;
1702 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1704 result = *strLengthNL;
1713 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1714 NonLoc resultNL = result.
castAs<NonLoc>();
1717 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1718 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1719 .castAs<DefinedOrUnknownSVal>(),
true);
1723 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1724 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1725 .castAs<DefinedOrUnknownSVal>(),
true);
1731 result = strLength.
castAs<DefinedOrUnknownSVal>();
1736 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1741 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1742 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1743 C.addTransition(state);
1746void CStringChecker::evalStrcpy(CheckerContext &
C,
1747 const CallEvent &
Call)
const {
1749 evalStrcpyCommon(
C,
Call,
1752 ConcatFnKind::none);
1755void CStringChecker::evalStrncpy(CheckerContext &
C,
1756 const CallEvent &
Call)
const {
1758 evalStrcpyCommon(
C,
Call,
1761 ConcatFnKind::none);
1764void CStringChecker::evalStpcpy(CheckerContext &
C,
1765 const CallEvent &
Call)
const {
1767 evalStrcpyCommon(
C,
Call,
1770 ConcatFnKind::none);
1773void CStringChecker::evalStrlcpy(CheckerContext &
C,
1774 const CallEvent &
Call)
const {
1776 evalStrcpyCommon(
C,
Call,
1783void CStringChecker::evalStrcat(CheckerContext &
C,
1784 const CallEvent &
Call)
const {
1786 evalStrcpyCommon(
C,
Call,
1789 ConcatFnKind::strcat);
1792void CStringChecker::evalStrncat(CheckerContext &
C,
1793 const CallEvent &
Call)
const {
1795 evalStrcpyCommon(
C,
Call,
1798 ConcatFnKind::strcat);
1801void CStringChecker::evalStrlcat(CheckerContext &
C,
1802 const CallEvent &
Call)
const {
1806 evalStrcpyCommon(
C,
Call,
1809 ConcatFnKind::strlcat,
1813void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1814 bool ReturnEnd,
bool IsBounded,
1815 ConcatFnKind appendK,
1816 bool returnPtr)
const {
1817 if (appendK == ConcatFnKind::none)
1818 CurrentFunctionDescription =
"string copy function";
1820 CurrentFunctionDescription =
"string concatenation function";
1823 const LocationContext *LCtx =
C.getLocationContext();
1826 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1827 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1828 state = checkNonNull(
C, state, Dst, DstVal);
1833 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1834 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1835 state = checkNonNull(
C, state, srcExpr, srcVal);
1840 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1841 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1844 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1845 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1851 SValBuilder &svalBuilder =
C.getSValBuilder();
1858 SVal amountCopied = UnknownVal();
1859 SVal maxLastElementIndex = UnknownVal();
1860 const char *boundWarning =
nullptr;
1864 SizeArgExpr SrcExprAsSizeDummy = {
1865 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1866 state = CheckOverlap(
1868 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1877 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1878 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1882 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1884 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1888 if (strLengthNL && lenValNL) {
1890 case ConcatFnKind::none:
1891 case ConcatFnKind::strcat: {
1896 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1898 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1899 .castAs<DefinedOrUnknownSVal>());
1901 if (stateSourceTooLong && !stateSourceNotTooLong) {
1904 state = stateSourceTooLong;
1905 amountCopied = lenVal;
1907 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1909 state = stateSourceNotTooLong;
1910 amountCopied = strLength;
1914 case ConcatFnKind::strlcat:
1915 if (!dstStrLengthNL)
1919 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
1920 *dstStrLengthNL, sizeTy);
1924 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1926 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
1933 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1936 std::tie(TrueState, FalseState) =
1937 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
1940 if (TrueState && !FalseState) {
1941 amountCopied = strLength;
1945 if (!TrueState && FalseState) {
1946 amountCopied = freeSpace;
1949 if (TrueState && FalseState)
1950 amountCopied = UnknownVal();
1957 case ConcatFnKind::strcat:
1963 if (dstStrLength.isUndef())
1966 if (dstStrLengthNL) {
1968 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1970 boundWarning =
"Size argument is greater than the free space in the "
1971 "destination buffer";
1974 case ConcatFnKind::none:
1975 case ConcatFnKind::strlcat:
1985 std::tie(StateZeroSize, StateNonZeroSize) =
1986 assumeZero(
C, state, *lenValNL, sizeTy);
1989 if (StateZeroSize && !StateNonZeroSize) {
1992 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
1994 if (appendK == ConcatFnKind::none) {
1996 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
2001 state, BO_Add, strLength, dstStrLength, sizeTy);
2003 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
2006 C.addTransition(StateZeroSize);
2014 maxLastElementIndex =
2015 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2016 boundWarning =
"Size argument is greater than the length of the "
2017 "destination buffer";
2024 amountCopied = strLength;
2032 SVal finalStrLength = UnknownVal();
2033 SVal strlRetVal = UnknownVal();
2035 if (appendK == ConcatFnKind::none && !returnPtr) {
2037 strlRetVal = strLength;
2043 if (appendK != ConcatFnKind::none) {
2046 if (dstStrLength.isUndef())
2049 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2050 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2051 *dstStrLengthNL, sizeTy);
2054 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2057 if (amountCopiedNL && dstStrLengthNL) {
2059 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2063 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2064 *dstStrLengthNL, sizeTy);
2073 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2074 assert(!finalStrLength.
isUndef());
2076 if (std::optional<NonLoc> finalStrLengthNL =
2077 finalStrLength.
getAs<NonLoc>()) {
2078 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2082 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2083 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2089 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2092 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2097 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2107 finalStrLength = amountCopied;
2115 Result = (ReturnEnd ? UnknownVal() : DstVal);
2117 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2128 if (std::optional<loc::MemRegionVal> dstRegVal =
2129 DstVal.
getAs<loc::MemRegionVal>()) {
2130 QualType ptrTy = Dst.Expression->getType();
2134 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2135 SVal maxLastElement =
2136 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2139 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2143 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2149 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2150 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2151 *knownStrLength, ptrTy);
2154 if (!boundWarning) {
2156 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2160 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2166 if (returnPtr && ReturnEnd)
2179 bool CouldAccessOutOfBound =
true;
2180 if (IsBounded && amountCopied.
isUnknown()) {
2181 auto CouldAccessOutOfBoundForSVal =
2182 [&](std::optional<NonLoc> Val) ->
bool {
2185 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2186 Dst.Expression->getType(), *Val,
2187 C.getASTContext().getSizeType());
2190 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2192 if (CouldAccessOutOfBound) {
2194 const Expr *LenExpr =
Call.getArgExpr(2);
2195 SVal LenVal = state->getSVal(LenExpr, LCtx);
2203 CouldAccessOutOfBound =
2204 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2215 if (CouldAccessOutOfBound)
2216 state = invalidateDestinationBufferBySize(
2217 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2218 amountCopied,
C.getASTContext().getSizeType());
2220 state = invalidateDestinationBufferNeverOverflows(
2221 C, state,
Call.getCFGElementRef(), *dstRegVal);
2225 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2228 if (IsBounded && (appendK == ConcatFnKind::none)) {
2233 if (amountCopied != strLength)
2234 finalStrLength = UnknownVal();
2236 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2244 if (ReturnEnd &&
Result.isUnknown()) {
2249 state = state->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2250 C.addTransition(state);
2253void CStringChecker::evalStrxfrm(CheckerContext &
C,
2254 const CallEvent &
Call)
const {
2256 CurrentFunctionDescription =
"locale transformation function";
2259 const LocationContext *LCtx =
C.getLocationContext();
2260 SValBuilder &SVB =
C.getSValBuilder();
2263 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2264 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2265 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2268 SVal SrcVal = State->getSVal(Source.Expression, LCtx);
2269 State = checkNonNull(
C, State, Source, SrcVal);
2274 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2282 auto BindReturnAndTransition = [&RetVal, &
Call, LCtx,
2285 State = State->BindExpr(
Call.getOriginExpr(), LCtx, RetVal);
2286 C.addTransition(State);
2291 SVal SizeVal = State->getSVal(
Size.Expression, LCtx);
2292 QualType SizeTy =
Size.Expression->getType();
2294 auto [StateZeroSize, StateSizeNonZero] =
2295 assumeZero(
C, State, SizeVal, SizeTy);
2298 if (!StateZeroSize && !StateSizeNonZero)
2299 return BindReturnAndTransition(State);
2302 if (StateZeroSize && !StateSizeNonZero)
2303 return BindReturnAndTransition(StateZeroSize);
2306 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, LCtx);
2307 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2308 if (!StateSizeNonZero)
2312 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2313 AccessKind::write, CK_Regular);
2314 if (!StateSizeNonZero)
2319 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2321 .
getAs<DefinedOrUnknownSVal>();
2322 if (!ComparisonVal) {
2324 StateSizeNonZero = invalidateDestinationBufferBySize(
2325 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2326 SizeVal,
Size.Expression->getType());
2327 return BindReturnAndTransition(StateSizeNonZero);
2330 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2334 StateSuccess = invalidateDestinationBufferBySize(
2335 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2336 SizeVal,
Size.Expression->getType());
2337 BindReturnAndTransition(StateSuccess);
2343 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2344 StateFailure = StateFailure->killBinding(*DestLoc);
2346 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, LCtx);
2349 BindReturnAndTransition(StateFailure);
2353void CStringChecker::evalStrcmp(CheckerContext &
C,
2354 const CallEvent &
Call)
const {
2356 evalStrcmpCommon(
C,
Call,
false,
false);
2359void CStringChecker::evalStrncmp(CheckerContext &
C,
2360 const CallEvent &
Call)
const {
2362 evalStrcmpCommon(
C,
Call,
true,
false);
2365void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2366 const CallEvent &
Call)
const {
2368 evalStrcmpCommon(
C,
Call,
false,
true);
2371void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2372 const CallEvent &
Call)
const {
2374 evalStrcmpCommon(
C,
Call,
true,
true);
2377void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2378 bool IsBounded,
bool IgnoreCase)
const {
2379 CurrentFunctionDescription =
"string comparison function";
2381 const LocationContext *LCtx =
C.getLocationContext();
2384 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2385 SVal LeftVal = state->getSVal(
Left.Expression, LCtx);
2386 state = checkNonNull(
C, state, Left, LeftVal);
2391 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2392 SVal RightVal = state->getSVal(
Right.Expression, LCtx);
2393 state = checkNonNull(
C, state, Right, RightVal);
2398 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2403 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2410 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2411 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2414 SValBuilder &svalBuilder =
C.getSValBuilder();
2415 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2417 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2423 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2424 svalBuilder.makeZeroVal(
Call.getResultType()));
2425 C.addTransition(StSameBuf);
2432 assert(StNotSameBuf);
2433 state = StNotSameBuf;
2439 const StringLiteral *LeftStrLiteral =
2440 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2441 const StringLiteral *RightStrLiteral =
2442 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2443 bool canComputeResult =
false;
2444 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2446 if (LeftStrLiteral && RightStrLiteral) {
2447 StringRef LeftStrRef = LeftStrLiteral->
getString();
2448 StringRef RightStrRef = RightStrLiteral->
getString();
2452 const Expr *lenExpr =
Call.getArgExpr(2);
2453 SVal lenVal = state->getSVal(lenExpr, LCtx);
2456 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2458 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2459 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2460 canComputeResult =
true;
2464 canComputeResult =
true;
2467 if (canComputeResult) {
2469 size_t s1Term = LeftStrRef.find(
'\0');
2470 if (s1Term != StringRef::npos)
2471 LeftStrRef = LeftStrRef.substr(0, s1Term);
2473 size_t s2Term = RightStrRef.find(
'\0');
2474 if (s2Term != StringRef::npos)
2475 RightStrRef = RightStrRef.substr(0, s2Term);
2478 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2479 : LeftStrRef.compare(RightStrRef);
2483 if (compareRes == 0) {
2484 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2487 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2491 SVal compareWithZero =
2492 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2493 svalBuilder.getConditionType());
2494 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2495 state = state->assume(compareWithZeroVal,
true);
2500 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2503 C.addTransition(state);
2506void CStringChecker::evalStrsep(CheckerContext &
C,
2507 const CallEvent &
Call)
const {
2510 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2512 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2513 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2517 CurrentFunctionDescription =
"strsep()";
2519 const LocationContext *LCtx =
C.getLocationContext();
2523 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2524 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2529 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2530 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2531 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2535 SValBuilder &SVB =
C.getSValBuilder();
2537 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2539 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2544 State = invalidateDestinationBufferNeverOverflows(
2549 State = State->bindLoc(*SearchStrLoc,
2559 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2560 C.addTransition(State);
2564void CStringChecker::evalStdCopy(CheckerContext &
C,
2565 const CallEvent &
Call)
const {
2566 evalStdCopyCommon(
C,
Call);
2569void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2570 const CallEvent &
Call)
const {
2571 evalStdCopyCommon(
C,
Call);
2574void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2575 const CallEvent &
Call)
const {
2576 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2581 const LocationContext *LCtx =
C.getLocationContext();
2589 const Expr *Dst =
Call.getArgExpr(2);
2590 SVal DstVal = State->getSVal(Dst, LCtx);
2593 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2594 C, State,
Call.getCFGElementRef(), DstVal);
2596 SValBuilder &SVB =
C.getSValBuilder();
2599 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2601 C.addTransition(State);
2604void CStringChecker::evalMemset(CheckerContext &
C,
2605 const CallEvent &
Call)
const {
2607 CurrentFunctionDescription =
"memory set function";
2609 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2610 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2611 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2616 const LocationContext *LCtx =
C.getLocationContext();
2617 SVal SizeVal =
C.getSVal(
Size.Expression);
2618 QualType SizeTy =
Size.Expression->getType();
2621 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2624 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2628 if (ZeroSize && !NonZeroSize) {
2629 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2630 C.addTransition(ZeroSize);
2636 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2640 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2647 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2648 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2651 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2652 C.addTransition(State);
2655void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2656 CurrentFunctionDescription =
"memory clearance function";
2658 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2659 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2660 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2665 SVal SizeVal =
C.getSVal(
Size.Expression);
2666 QualType SizeTy =
Size.Expression->getType();
2669 std::tie(StateZeroSize, StateNonZeroSize) =
2670 assumeZero(
C, State, SizeVal, SizeTy);
2674 if (StateZeroSize && !StateNonZeroSize) {
2675 C.addTransition(StateZeroSize);
2680 SVal MemVal =
C.getSVal(Buffer.Expression);
2684 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2688 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2692 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
2693 Size.Expression,
C, State))
2696 C.addTransition(State);
2699void CStringChecker::evalSprintf(CheckerContext &
C,
2700 const CallEvent &
Call)
const {
2701 CurrentFunctionDescription =
"'sprintf'";
2702 evalSprintfCommon(
C,
Call,
false);
2705void CStringChecker::evalSnprintf(CheckerContext &
C,
2706 const CallEvent &
Call)
const {
2707 CurrentFunctionDescription =
"'snprintf'";
2708 evalSprintfCommon(
C,
Call,
true);
2711void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
2712 bool IsBounded)
const {
2715 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2717 const auto NumParams =
Call.parameters().size();
2718 if (CE->getNumArgs() < NumParams) {
2723 const auto AllArguments =
2724 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2725 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2727 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2729 if (
const QualType
type = ArgExpr->getType();
2730 !
type->isAnyPointerType() ||
2731 !
type->getPointeeType()->isAnyCharacterType())
2733 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
2736 SizeArgExpr SrcExprAsSizeDummy = {
2737 {Source.Expression, Source.ArgumentIndex}};
2738 State = CheckOverlap(
2740 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2746 C.addTransition(State);
2753CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2754 CheckerContext &
C)
const {
2755 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2759 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
2764 return &CStringChecker::evalStdCopy;
2766 return &CStringChecker::evalStdCopyBackward;
2772 for (
auto I : CE->arguments()) {
2773 QualType
T = I->getType();
2778 const FnCheck *Callback = Callbacks.lookup(
Call);
2785bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
2786 FnCheck Callback = identifyCall(
Call,
C);
2794 Callback(
this,
C,
Call);
2802 return C.isDifferent();
2805void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
2809 for (
const auto *I : DS->
decls()) {
2810 const VarDecl *D = dyn_cast<VarDecl>(I);
2824 Loc VarLoc = state->getLValue(D,
C.getLocationContext());
2829 SVal StrVal =
C.getSVal(
Init);
2830 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2831 DefinedOrUnknownSVal strLength =
2832 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
2834 state = state->set<CStringLength>(MR, strLength);
2837 C.addTransition(state);
2843 ArrayRef<const MemRegion *> ExplicitRegions,
2844 ArrayRef<const MemRegion *> Regions,
2845 const LocationContext *LCtx,
2846 const CallEvent *
Call)
const {
2847 CStringLengthTy Entries = state->get<CStringLength>();
2848 if (Entries.isEmpty())
2851 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2852 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2855 for (
const MemRegion *MR : Regions) {
2856 Invalidated.insert(MR);
2858 SuperRegions.insert(MR);
2859 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2860 MR = SR->getSuperRegion();
2861 SuperRegions.insert(MR);
2865 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2868 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2870 if (SuperRegions.count(MR)) {
2871 Entries = F.remove(Entries, MR);
2876 const MemRegion *Super = MR;
2877 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2878 Super = SR->getSuperRegion();
2879 if (Invalidated.count(Super)) {
2880 Entries = F.remove(Entries, MR);
2886 return state->set<CStringLength>(Entries);
2890 SymbolReaper &SR)
const {
2892 CStringLengthTy Entries = state->get<CStringLength>();
2894 for (SVal Len : llvm::make_second_range(Entries)) {
2900void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2901 CheckerContext &
C)
const {
2903 CStringLengthTy Entries = state->get<CStringLength>();
2904 if (Entries.isEmpty())
2907 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2908 for (
auto [Reg, Len] : Entries) {
2909 if (
SymbolRef Sym = Len.getAsSymbol()) {
2911 Entries = F.remove(Entries, Reg);
2915 state = state->set<CStringLength>(Entries);
2916 C.addTransition(state);
2919void ento::registerCStringModeling(CheckerManager &Mgr) {
2926bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
2930#define REGISTER_CHECKER(NAME) \
2931 void ento::registerCString##NAME(CheckerManager &Mgr) { \
2932 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
2935 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