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,
676 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
681 const LocationContext *LCtx =
C.getLocationContext();
682 SVal firstVal = state->getSVal(
First.Expression, LCtx);
683 SVal secondVal = state->getSVal(Second.Expression, LCtx);
685 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
689 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
694 SValBuilder &svalBuilder =
C.getSValBuilder();
695 std::tie(stateTrue, stateFalse) =
696 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
698 if (stateTrue && !stateFalse) {
700 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
711 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
712 std::optional<DefinedOrUnknownSVal> reverseTest =
713 reverse.
getAs<DefinedOrUnknownSVal>();
717 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
724 std::swap(firstLoc, secondLoc);
727 std::swap(
First, Second);
732 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
733 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
740 QualType CharPtrTy = getCharPtrType(Ctx, CK);
742 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
743 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
748 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
750 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
756 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
757 std::optional<DefinedOrUnknownSVal> OverlapTest =
758 Overlap.
getAs<DefinedOrUnknownSVal>();
762 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
764 if (stateTrue && !stateFalse) {
766 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
775void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
776 const Stmt *
First,
const Stmt *Second)
const {
777 ExplodedNode *N =
C.generateErrorNode(state);
782 auto report = std::make_unique<PathSensitiveBugReport>(
783 BufferOverlap,
"Arguments must not be overlapping buffers", N);
784 report->addRange(
First->getSourceRange());
787 C.emitReport(std::move(report));
790void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
791 const Stmt *S, StringRef WarningMsg)
const {
792 if (ExplodedNode *N =
C.generateErrorNode(State)) {
794 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
796 if (
const auto *Ex = dyn_cast<Expr>(S))
798 C.emitReport(std::move(
Report));
802void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
804 const Expr *E,
const MemRegion *R,
805 StringRef Msg)
const {
806 if (ExplodedNode *N =
C.generateErrorNode(State)) {
808 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
809 Report->addNote(
"Other elements might also be undefined",
813 Report->addVisitor<NoStoreFuncVisitor>(R->
castAs<SubRegion>());
814 C.emitReport(std::move(
Report));
818void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
820 StringRef WarningMsg)
const {
821 if (ExplodedNode *N =
C.generateErrorNode(State)) {
826 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
828 C.emitReport(std::move(
Report));
832void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
834 StringRef WarningMsg)
const {
835 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
837 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
840 C.emitReport(std::move(
Report));
847 NonLoc right)
const {
856 SValBuilder &svalBuilder =
C.getSValBuilder();
860 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
861 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
865 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
870 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
875 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
878 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
879 *maxMinusRightNL, cmpTy);
881 auto [StateOverflow, StateOkay] =
882 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
884 if (StateOverflow && !StateOkay) {
890 C.addSink(StateOverflow);
905 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
910 case MemRegion::StringRegionKind:
915 case MemRegion::SymbolicRegionKind:
916 case MemRegion::AllocaRegionKind:
917 case MemRegion::NonParamVarRegionKind:
918 case MemRegion::ParamVarRegionKind:
919 case MemRegion::FieldRegionKind:
920 case MemRegion::ObjCIvarRegionKind:
924 case MemRegion::ElementRegionKind:
938 return state->remove<CStringLength>(MR);
940 return state->set<CStringLength>(MR, strLength);
943SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
950 const SVal *Recorded = state->get<CStringLength>(MR);
956 SValBuilder &svalBuilder =
C.getSValBuilder();
960 C.getLocationContext(),
964 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
967 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
968 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
969 std::optional<APSIntPtr> maxLengthInt =
971 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
972 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
974 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
976 state = state->set<CStringLength>(MR, strLength);
982SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
983 const Expr *Ex, SVal Buf,
984 bool hypothetical)
const {
990 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
992 SmallString<120> buf;
993 llvm::raw_svector_ostream os(buf);
994 assert(CurrentFunctionDescription);
995 os <<
"Argument to " << CurrentFunctionDescription
996 <<
" is the address of the label '" << Label->getLabel()->getName()
997 <<
"', which is not a null-terminated string";
999 emitNotCStringBug(
C, state, Ex, os.str());
1001 return UndefinedVal();
1005 return UnknownVal();
1013 case MemRegion::StringRegionKind: {
1016 SValBuilder &svalBuilder =
C.getSValBuilder();
1021 case MemRegion::NonParamVarRegionKind: {
1025 if (
Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage()) {
1026 if (
const Expr *
Init =
Decl->getInit()) {
1027 if (
auto *StrLit = dyn_cast<StringLiteral>(
Init)) {
1028 SValBuilder &SvalBuilder =
C.getSValBuilder();
1030 return SvalBuilder.
makeIntVal(StrLit->getLength(), SizeTy);
1036 case MemRegion::SymbolicRegionKind:
1037 case MemRegion::AllocaRegionKind:
1038 case MemRegion::ParamVarRegionKind:
1039 case MemRegion::FieldRegionKind:
1040 case MemRegion::ObjCIvarRegionKind:
1041 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1042 case MemRegion::CompoundLiteralRegionKind:
1044 return UnknownVal();
1045 case MemRegion::ElementRegionKind:
1048 return UnknownVal();
1054 SmallString<120> buf;
1055 llvm::raw_svector_ostream os(buf);
1057 assert(CurrentFunctionDescription);
1058 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1060 if (SummarizeRegion(os,
C.getASTContext(), MR))
1061 os <<
", which is not a null-terminated string";
1063 os <<
"not a null-terminated string";
1065 emitNotCStringBug(
C, state, Ex, os.str());
1067 return UndefinedVal();
1071const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1083 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1091bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1092 SVal BufVal, QualType BufTy,
1093 SVal LengthVal, QualType LengthTy) {
1102 SValBuilder &SB =
C.getSValBuilder();
1103 ASTContext &Ctx =
C.getASTContext();
1107 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1113 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1114 if (Offset.isUnknown())
1116 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1119 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1120 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1124 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1131 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1137 C.getASTContext().CharTy &&
1138 "isFirstBufInBound should only be called with char* ElementRegions");
1145 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1149 return static_cast<bool>(StInBound);
1155 auto InvalidationTraitOperations =
1156 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1157 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1160 if (MemRegion::FieldRegionKind == R->
getKind() &&
1161 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1169 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1173CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1175 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1176 const MemRegion *R) {
1180 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1183ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1185 auto InvalidationTraitOperations =
1186 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1187 if (MemRegion::FieldRegionKind == R->
getKind())
1194 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1201 auto InvalidationTraitOperations =
1202 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *R) {
1211 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1216 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1218 InvalidationTraitOperations) {
1219 std::optional<Loc> L =
V.getAs<Loc>();
1226 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1227 const MemRegion *R = MR->getRegion()->
StripCasts();
1231 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1237 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
1238 RegionAndSymbolInvalidationTraits ITraits;
1239 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1241 return State->invalidateRegions(R, Elem,
C.blockCount(), LCtx,
1242 CausesPointerEscape,
nullptr,
nullptr,
1249 return State->killBinding(*L);
1252bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1253 const MemRegion *MR) {
1255 case MemRegion::FunctionCodeRegionKind: {
1257 os <<
"the address of the function '" << *FD <<
'\'';
1259 os <<
"the address of a function";
1262 case MemRegion::BlockCodeRegionKind:
1265 case MemRegion::BlockDataRegionKind:
1268 case MemRegion::CXXThisRegionKind:
1269 case MemRegion::CXXTempObjectRegionKind:
1270 os <<
"a C++ temp object of type "
1273 case MemRegion::NonParamVarRegionKind:
1276 case MemRegion::ParamVarRegionKind:
1279 case MemRegion::FieldRegionKind:
1282 case MemRegion::ObjCIvarRegionKind:
1283 os <<
"an instance variable of type "
1292 SVal CharVal,
const Expr *Size,
1294 SVal MemVal =
C.getSVal(DstBuffer);
1295 SVal SizeVal =
C.getSVal(Size);
1305 const MemRegion *BR = Offset.
getRegion();
1307 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1311 SValBuilder &svalBuilder =
C.getSValBuilder();
1312 ASTContext &Ctx =
C.getASTContext();
1322 std::tie(StateWholeReg, StateNotWholeReg) =
1323 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1330 std::tie(StateNullChar, StateNonNullChar) =
1333 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1334 !StateNonNullChar) {
1341 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1342 C.getLocationContext());
1346 State = invalidateDestinationBufferBySize(
1347 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1350 if (StateNullChar && !StateNonNullChar) {
1353 State = setCStringLength(State, MR,
1355 }
else if (!StateNullChar && StateNonNullChar) {
1357 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1358 C.getLocationContext(),
C.blockCount());
1362 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1365 State = setCStringLength(
1366 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1372 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1373 SizeVal,
Size->getType());
1382void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1384 DestinationArgExpr Dest,
1385 SourceArgExpr Source,
bool Restricted,
1386 bool IsMempcpy, CharKind CK)
const {
1387 CurrentFunctionDescription =
"memory copy function";
1390 const LocationContext *LCtx =
C.getLocationContext();
1391 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1392 QualType sizeTy =
Size.Expression->getType();
1395 std::tie(stateZeroSize, stateNonZeroSize) =
1396 assumeZero(
C, state, sizeVal, sizeTy);
1399 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1403 if (stateZeroSize && !stateNonZeroSize) {
1405 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1406 C.addTransition(stateZeroSize);
1411 if (stateNonZeroSize) {
1415 state = stateNonZeroSize;
1419 state = checkNonNull(
C, state, Dest, destVal);
1424 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1428 state = checkNonNull(
C, state, Source, srcVal);
1433 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1434 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1437 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1446 SValBuilder &SvalBuilder =
C.getSValBuilder();
1448 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1449 SVal DestRegCharVal =
1450 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1451 SVal lastElement =
C.getSValBuilder().evalBinOp(
1452 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1456 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1459 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1463 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1472 state = invalidateDestinationBufferBySize(
1473 C, state, Dest.Expression,
Call.getCFGElementRef(),
1474 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1478 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1479 C.getSVal(Source.Expression));
1481 C.addTransition(state);
1485void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1486 CharKind CK)
const {
1489 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1490 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1491 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1495 constexpr bool IsRestricted =
true;
1496 constexpr bool IsMempcpy =
false;
1497 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1500void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1501 CharKind CK)
const {
1504 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1505 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1506 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1508 constexpr bool IsRestricted =
true;
1509 constexpr bool IsMempcpy =
true;
1510 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1514void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1515 CharKind CK)
const {
1518 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1519 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1520 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1522 constexpr bool IsRestricted =
false;
1523 constexpr bool IsMempcpy =
false;
1524 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1528void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1530 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1531 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1532 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1534 constexpr bool IsRestricted =
false;
1535 constexpr bool IsMempcpy =
false;
1536 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1537 IsMempcpy, CharKind::Regular);
1540void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1541 CharKind CK)
const {
1543 CurrentFunctionDescription =
"memory comparison function";
1545 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1546 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1547 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1550 SValBuilder &Builder =
C.getSValBuilder();
1551 const LocationContext *LCtx =
C.getLocationContext();
1554 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1555 QualType sizeTy =
Size.Expression->getType();
1558 std::tie(stateZeroSize, stateNonZeroSize) =
1559 assumeZero(
C, State, sizeVal, sizeTy);
1563 if (stateZeroSize) {
1564 State = stateZeroSize;
1565 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1566 Builder.makeZeroVal(
Call.getResultType()));
1567 C.addTransition(State);
1571 if (stateNonZeroSize) {
1572 State = stateNonZeroSize;
1576 DefinedOrUnknownSVal LV =
1577 State->getSVal(
Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1578 DefinedOrUnknownSVal RV =
1579 State->getSVal(
Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1583 std::tie(SameBuffer, NotSameBuffer) =
1584 State->assume(Builder.evalEQ(State, LV, RV));
1588 if (SameBuffer && !NotSameBuffer) {
1590 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1592 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1593 Builder.makeZeroVal(
Call.getResultType()));
1594 C.addTransition(State);
1601 assert(NotSameBuffer);
1602 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1603 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1606 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1607 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1608 C.addTransition(State);
1613void CStringChecker::evalstrLength(CheckerContext &
C,
1614 const CallEvent &
Call)
const {
1616 evalstrLengthCommon(
C,
Call,
false);
1619void CStringChecker::evalstrnLength(CheckerContext &
C,
1620 const CallEvent &
Call)
const {
1622 evalstrLengthCommon(
C,
Call,
true);
1625void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1626 const CallEvent &
Call,
1627 bool IsStrnlen)
const {
1628 CurrentFunctionDescription =
"string length function";
1630 const LocationContext *LCtx =
C.getLocationContext();
1633 const Expr *maxlenExpr =
Call.getArgExpr(1);
1634 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1637 std::tie(stateZeroSize, stateNonZeroSize) =
1638 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1642 if (stateZeroSize) {
1643 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1644 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1645 C.addTransition(stateZeroSize);
1649 if (!stateNonZeroSize)
1653 state = stateNonZeroSize;
1657 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1658 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1659 state = checkNonNull(
C, state, Arg, ArgVal);
1664 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1671 DefinedOrUnknownSVal result = UnknownVal();
1676 QualType cmpTy =
C.getSValBuilder().getConditionType();
1680 const Expr *maxlenExpr =
Call.getArgExpr(1);
1681 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1683 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1684 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1686 if (strLengthNL && maxlenValNL) {
1690 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1692 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1693 .castAs<DefinedOrUnknownSVal>());
1695 if (stateStringTooLong && !stateStringNotTooLong) {
1697 result = *maxlenValNL;
1698 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1700 result = *strLengthNL;
1709 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1710 NonLoc resultNL = result.
castAs<NonLoc>();
1713 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1714 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1715 .castAs<DefinedOrUnknownSVal>(),
true);
1719 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1720 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1721 .castAs<DefinedOrUnknownSVal>(),
true);
1727 result = strLength.
castAs<DefinedOrUnknownSVal>();
1732 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1737 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1738 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1739 C.addTransition(state);
1742void CStringChecker::evalStrcpy(CheckerContext &
C,
1743 const CallEvent &
Call)
const {
1745 evalStrcpyCommon(
C,
Call,
1748 ConcatFnKind::none);
1751void CStringChecker::evalStrncpy(CheckerContext &
C,
1752 const CallEvent &
Call)
const {
1754 evalStrcpyCommon(
C,
Call,
1757 ConcatFnKind::none);
1760void CStringChecker::evalStpcpy(CheckerContext &
C,
1761 const CallEvent &
Call)
const {
1763 evalStrcpyCommon(
C,
Call,
1766 ConcatFnKind::none);
1769void CStringChecker::evalStrlcpy(CheckerContext &
C,
1770 const CallEvent &
Call)
const {
1772 evalStrcpyCommon(
C,
Call,
1779void CStringChecker::evalStrcat(CheckerContext &
C,
1780 const CallEvent &
Call)
const {
1782 evalStrcpyCommon(
C,
Call,
1785 ConcatFnKind::strcat);
1788void CStringChecker::evalStrncat(CheckerContext &
C,
1789 const CallEvent &
Call)
const {
1791 evalStrcpyCommon(
C,
Call,
1794 ConcatFnKind::strcat);
1797void CStringChecker::evalStrlcat(CheckerContext &
C,
1798 const CallEvent &
Call)
const {
1802 evalStrcpyCommon(
C,
Call,
1805 ConcatFnKind::strlcat,
1809void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1810 bool ReturnEnd,
bool IsBounded,
1811 ConcatFnKind appendK,
1812 bool returnPtr)
const {
1813 if (appendK == ConcatFnKind::none)
1814 CurrentFunctionDescription =
"string copy function";
1816 CurrentFunctionDescription =
"string concatenation function";
1819 const LocationContext *LCtx =
C.getLocationContext();
1822 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1823 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1824 state = checkNonNull(
C, state, Dst, DstVal);
1829 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1830 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1831 state = checkNonNull(
C, state, srcExpr, srcVal);
1836 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1837 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1840 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1841 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1847 SValBuilder &svalBuilder =
C.getSValBuilder();
1854 SVal amountCopied = UnknownVal();
1855 SVal maxLastElementIndex = UnknownVal();
1856 const char *boundWarning =
nullptr;
1860 SizeArgExpr SrcExprAsSizeDummy = {
1861 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1862 state = CheckOverlap(
1864 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1873 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1874 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1878 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1880 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1884 if (strLengthNL && lenValNL) {
1886 case ConcatFnKind::none:
1887 case ConcatFnKind::strcat: {
1892 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1894 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1895 .castAs<DefinedOrUnknownSVal>());
1897 if (stateSourceTooLong && !stateSourceNotTooLong) {
1900 state = stateSourceTooLong;
1901 amountCopied = lenVal;
1903 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1905 state = stateSourceNotTooLong;
1906 amountCopied = strLength;
1910 case ConcatFnKind::strlcat:
1911 if (!dstStrLengthNL)
1915 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
1916 *dstStrLengthNL, sizeTy);
1920 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1922 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
1929 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1932 std::tie(TrueState, FalseState) =
1933 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
1936 if (TrueState && !FalseState) {
1937 amountCopied = strLength;
1941 if (!TrueState && FalseState) {
1942 amountCopied = freeSpace;
1945 if (TrueState && FalseState)
1946 amountCopied = UnknownVal();
1953 case ConcatFnKind::strcat:
1959 if (dstStrLength.isUndef())
1962 if (dstStrLengthNL) {
1964 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1966 boundWarning =
"Size argument is greater than the free space in the "
1967 "destination buffer";
1970 case ConcatFnKind::none:
1971 case ConcatFnKind::strlcat:
1981 std::tie(StateZeroSize, StateNonZeroSize) =
1982 assumeZero(
C, state, *lenValNL, sizeTy);
1985 if (StateZeroSize && !StateNonZeroSize) {
1988 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
1990 if (appendK == ConcatFnKind::none) {
1992 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
1997 state, BO_Add, strLength, dstStrLength, sizeTy);
1999 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
2002 C.addTransition(StateZeroSize);
2010 maxLastElementIndex =
2011 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2012 boundWarning =
"Size argument is greater than the length of the "
2013 "destination buffer";
2020 amountCopied = strLength;
2028 SVal finalStrLength = UnknownVal();
2029 SVal strlRetVal = UnknownVal();
2031 if (appendK == ConcatFnKind::none && !returnPtr) {
2033 strlRetVal = strLength;
2039 if (appendK != ConcatFnKind::none) {
2042 if (dstStrLength.isUndef())
2045 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2046 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2047 *dstStrLengthNL, sizeTy);
2050 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2053 if (amountCopiedNL && dstStrLengthNL) {
2055 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2059 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2060 *dstStrLengthNL, sizeTy);
2069 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2070 assert(!finalStrLength.
isUndef());
2072 if (std::optional<NonLoc> finalStrLengthNL =
2073 finalStrLength.
getAs<NonLoc>()) {
2074 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2078 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2079 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2085 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2088 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2093 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2103 finalStrLength = amountCopied;
2111 Result = (ReturnEnd ? UnknownVal() : DstVal);
2113 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2124 if (std::optional<loc::MemRegionVal> dstRegVal =
2125 DstVal.
getAs<loc::MemRegionVal>()) {
2126 QualType ptrTy = Dst.Expression->getType();
2130 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2131 SVal maxLastElement =
2132 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2135 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2139 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2145 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2146 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2147 *knownStrLength, ptrTy);
2150 if (!boundWarning) {
2152 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2156 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2162 if (returnPtr && ReturnEnd)
2175 bool CouldAccessOutOfBound =
true;
2176 if (IsBounded && amountCopied.
isUnknown()) {
2177 auto CouldAccessOutOfBoundForSVal =
2178 [&](std::optional<NonLoc> Val) ->
bool {
2181 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2182 Dst.Expression->getType(), *Val,
2183 C.getASTContext().getSizeType());
2186 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2188 if (CouldAccessOutOfBound) {
2190 const Expr *LenExpr =
Call.getArgExpr(2);
2191 SVal LenVal = state->getSVal(LenExpr, LCtx);
2199 CouldAccessOutOfBound =
2200 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2211 if (CouldAccessOutOfBound)
2212 state = invalidateDestinationBufferBySize(
2213 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2214 amountCopied,
C.getASTContext().getSizeType());
2216 state = invalidateDestinationBufferNeverOverflows(
2217 C, state,
Call.getCFGElementRef(), *dstRegVal);
2221 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2224 if (IsBounded && (appendK == ConcatFnKind::none)) {
2229 if (amountCopied != strLength)
2230 finalStrLength = UnknownVal();
2232 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2240 if (ReturnEnd &&
Result.isUnknown()) {
2245 state = state->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2246 C.addTransition(state);
2249void CStringChecker::evalStrxfrm(CheckerContext &
C,
2250 const CallEvent &
Call)
const {
2252 CurrentFunctionDescription =
"locale transformation function";
2255 const LocationContext *LCtx =
C.getLocationContext();
2256 SValBuilder &SVB =
C.getSValBuilder();
2259 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2260 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2261 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2264 SVal SrcVal = State->getSVal(Source.Expression, LCtx);
2265 State = checkNonNull(
C, State, Source, SrcVal);
2270 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2278 auto BindReturnAndTransition = [&RetVal, &
Call, LCtx,
2281 State = State->BindExpr(
Call.getOriginExpr(), LCtx, RetVal);
2282 C.addTransition(State);
2287 SVal SizeVal = State->getSVal(
Size.Expression, LCtx);
2288 QualType SizeTy =
Size.Expression->getType();
2290 auto [StateZeroSize, StateSizeNonZero] =
2291 assumeZero(
C, State, SizeVal, SizeTy);
2294 if (!StateZeroSize && !StateSizeNonZero)
2295 return BindReturnAndTransition(State);
2298 if (StateZeroSize && !StateSizeNonZero)
2299 return BindReturnAndTransition(StateZeroSize);
2302 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, LCtx);
2303 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2304 if (!StateSizeNonZero)
2308 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2309 AccessKind::write, CK_Regular);
2310 if (!StateSizeNonZero)
2315 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2317 .
getAs<DefinedOrUnknownSVal>();
2318 if (!ComparisonVal) {
2320 StateSizeNonZero = invalidateDestinationBufferBySize(
2321 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2322 SizeVal,
Size.Expression->getType());
2323 return BindReturnAndTransition(StateSizeNonZero);
2326 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2330 StateSuccess = invalidateDestinationBufferBySize(
2331 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2332 SizeVal,
Size.Expression->getType());
2333 BindReturnAndTransition(StateSuccess);
2339 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2340 StateFailure = StateFailure->killBinding(*DestLoc);
2342 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, LCtx);
2345 BindReturnAndTransition(StateFailure);
2349void CStringChecker::evalStrcmp(CheckerContext &
C,
2350 const CallEvent &
Call)
const {
2352 evalStrcmpCommon(
C,
Call,
false,
false);
2355void CStringChecker::evalStrncmp(CheckerContext &
C,
2356 const CallEvent &
Call)
const {
2358 evalStrcmpCommon(
C,
Call,
true,
false);
2361void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2362 const CallEvent &
Call)
const {
2364 evalStrcmpCommon(
C,
Call,
false,
true);
2367void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2368 const CallEvent &
Call)
const {
2370 evalStrcmpCommon(
C,
Call,
true,
true);
2373void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2374 bool IsBounded,
bool IgnoreCase)
const {
2375 CurrentFunctionDescription =
"string comparison function";
2377 const LocationContext *LCtx =
C.getLocationContext();
2380 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2381 SVal LeftVal = state->getSVal(
Left.Expression, LCtx);
2382 state = checkNonNull(
C, state, Left, LeftVal);
2387 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2388 SVal RightVal = state->getSVal(
Right.Expression, LCtx);
2389 state = checkNonNull(
C, state, Right, RightVal);
2394 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2399 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2406 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2407 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2410 SValBuilder &svalBuilder =
C.getSValBuilder();
2411 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2413 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2419 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2420 svalBuilder.makeZeroVal(
Call.getResultType()));
2421 C.addTransition(StSameBuf);
2428 assert(StNotSameBuf);
2429 state = StNotSameBuf;
2435 const StringLiteral *LeftStrLiteral =
2436 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2437 const StringLiteral *RightStrLiteral =
2438 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2439 bool canComputeResult =
false;
2440 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2442 if (LeftStrLiteral && RightStrLiteral) {
2443 StringRef LeftStrRef = LeftStrLiteral->
getString();
2444 StringRef RightStrRef = RightStrLiteral->
getString();
2448 const Expr *lenExpr =
Call.getArgExpr(2);
2449 SVal lenVal = state->getSVal(lenExpr, LCtx);
2452 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2454 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2455 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2456 canComputeResult =
true;
2460 canComputeResult =
true;
2463 if (canComputeResult) {
2465 size_t s1Term = LeftStrRef.find(
'\0');
2466 if (s1Term != StringRef::npos)
2467 LeftStrRef = LeftStrRef.substr(0, s1Term);
2469 size_t s2Term = RightStrRef.find(
'\0');
2470 if (s2Term != StringRef::npos)
2471 RightStrRef = RightStrRef.substr(0, s2Term);
2474 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2475 : LeftStrRef.compare(RightStrRef);
2479 if (compareRes == 0) {
2480 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2483 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2487 SVal compareWithZero =
2488 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2489 svalBuilder.getConditionType());
2490 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2491 state = state->assume(compareWithZeroVal,
true);
2496 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2499 C.addTransition(state);
2502void CStringChecker::evalStrsep(CheckerContext &
C,
2503 const CallEvent &
Call)
const {
2506 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2508 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2509 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2513 CurrentFunctionDescription =
"strsep()";
2515 const LocationContext *LCtx =
C.getLocationContext();
2519 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2520 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2525 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2526 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2527 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2531 SValBuilder &SVB =
C.getSValBuilder();
2533 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2535 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2540 State = invalidateDestinationBufferNeverOverflows(
2545 State = State->bindLoc(*SearchStrLoc,
2555 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2556 C.addTransition(State);
2560void CStringChecker::evalStdCopy(CheckerContext &
C,
2561 const CallEvent &
Call)
const {
2562 evalStdCopyCommon(
C,
Call);
2565void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2566 const CallEvent &
Call)
const {
2567 evalStdCopyCommon(
C,
Call);
2570void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2571 const CallEvent &
Call)
const {
2572 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2577 const LocationContext *LCtx =
C.getLocationContext();
2585 const Expr *Dst =
Call.getArgExpr(2);
2586 SVal DstVal = State->getSVal(Dst, LCtx);
2589 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2590 C, State,
Call.getCFGElementRef(), DstVal);
2592 SValBuilder &SVB =
C.getSValBuilder();
2595 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2597 C.addTransition(State);
2600void CStringChecker::evalMemset(CheckerContext &
C,
2601 const CallEvent &
Call)
const {
2603 CurrentFunctionDescription =
"memory set function";
2605 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2606 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2607 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2612 const LocationContext *LCtx =
C.getLocationContext();
2613 SVal SizeVal =
C.getSVal(
Size.Expression);
2614 QualType SizeTy =
Size.Expression->getType();
2617 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2620 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2624 if (ZeroSize && !NonZeroSize) {
2625 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2626 C.addTransition(ZeroSize);
2632 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2636 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2643 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2644 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2647 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2648 C.addTransition(State);
2651void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2652 CurrentFunctionDescription =
"memory clearance function";
2654 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2655 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2656 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2661 SVal SizeVal =
C.getSVal(
Size.Expression);
2662 QualType SizeTy =
Size.Expression->getType();
2665 std::tie(StateZeroSize, StateNonZeroSize) =
2666 assumeZero(
C, State, SizeVal, SizeTy);
2670 if (StateZeroSize && !StateNonZeroSize) {
2671 C.addTransition(StateZeroSize);
2676 SVal MemVal =
C.getSVal(Buffer.Expression);
2680 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2684 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2688 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
2689 Size.Expression,
C, State))
2692 C.addTransition(State);
2695void CStringChecker::evalSprintf(CheckerContext &
C,
2696 const CallEvent &
Call)
const {
2697 CurrentFunctionDescription =
"'sprintf'";
2698 evalSprintfCommon(
C,
Call,
false);
2701void CStringChecker::evalSnprintf(CheckerContext &
C,
2702 const CallEvent &
Call)
const {
2703 CurrentFunctionDescription =
"'snprintf'";
2704 evalSprintfCommon(
C,
Call,
true);
2707void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
2708 bool IsBounded)
const {
2711 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2713 const auto NumParams =
Call.parameters().size();
2714 if (CE->getNumArgs() < NumParams) {
2719 const auto AllArguments =
2720 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2721 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2723 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2725 if (
const QualType
type = ArgExpr->getType();
2726 !
type->isAnyPointerType() ||
2727 !
type->getPointeeType()->isAnyCharacterType())
2729 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
2732 SizeArgExpr SrcExprAsSizeDummy = {
2733 {Source.Expression, Source.ArgumentIndex}};
2734 State = CheckOverlap(
2736 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2742 C.addTransition(State);
2749CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2750 CheckerContext &
C)
const {
2751 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2755 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
2760 return &CStringChecker::evalStdCopy;
2762 return &CStringChecker::evalStdCopyBackward;
2768 for (
auto I : CE->arguments()) {
2769 QualType
T = I->getType();
2774 const FnCheck *Callback = Callbacks.lookup(
Call);
2781bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
2782 FnCheck Callback = identifyCall(
Call,
C);
2790 Callback(
this,
C,
Call);
2798 return C.isDifferent();
2801void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
2805 for (
const auto *I : DS->
decls()) {
2806 const VarDecl *D = dyn_cast<VarDecl>(I);
2820 Loc VarLoc = state->getLValue(D,
C.getLocationContext());
2825 SVal StrVal =
C.getSVal(
Init);
2826 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2827 DefinedOrUnknownSVal strLength =
2828 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
2830 state = state->set<CStringLength>(MR, strLength);
2833 C.addTransition(state);
2839 ArrayRef<const MemRegion *> ExplicitRegions,
2840 ArrayRef<const MemRegion *> Regions,
2841 const LocationContext *LCtx,
2842 const CallEvent *
Call)
const {
2843 CStringLengthTy Entries = state->get<CStringLength>();
2844 if (Entries.isEmpty())
2847 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2848 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2851 for (
const MemRegion *MR : Regions) {
2852 Invalidated.insert(MR);
2854 SuperRegions.insert(MR);
2855 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2856 MR = SR->getSuperRegion();
2857 SuperRegions.insert(MR);
2861 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2864 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2866 if (SuperRegions.count(MR)) {
2867 Entries = F.remove(Entries, MR);
2872 const MemRegion *Super = MR;
2873 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2874 Super = SR->getSuperRegion();
2875 if (Invalidated.count(Super)) {
2876 Entries = F.remove(Entries, MR);
2882 return state->set<CStringLength>(Entries);
2886 SymbolReaper &SR)
const {
2888 CStringLengthTy Entries = state->get<CStringLength>();
2890 for (SVal Len : llvm::make_second_range(Entries)) {
2896void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2897 CheckerContext &
C)
const {
2899 CStringLengthTy Entries = state->get<CStringLength>();
2900 if (Entries.isEmpty())
2903 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2904 for (
auto [Reg, Len] : Entries) {
2905 if (
SymbolRef Sym = Len.getAsSymbol()) {
2907 Entries = F.remove(Entries, Reg);
2911 state = state->set<CStringLength>(Entries);
2912 C.addTransition(state);
2915void ento::registerCStringModeling(CheckerManager &Mgr) {
2922bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
2926#define REGISTER_CHECKER(NAME) \
2927 void ento::registerCString##NAME(CheckerManager &Mgr) { \
2928 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
2931 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.
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