29#include "llvm/ADT/APSInt.h"
30#include "llvm/ADT/STLExtras.h"
31#include "llvm/ADT/StringExtras.h"
32#include "llvm/Support/raw_ostream.h"
38using namespace std::placeholders;
42 const Expr *Expression;
43 unsigned ArgumentIndex;
45struct SourceArgExpr : AnyArgExpr {};
46struct DestinationArgExpr : AnyArgExpr {};
47struct SizeArgExpr : AnyArgExpr {};
50enum class AccessKind { write, read };
52static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
55 llvm::raw_svector_ostream Os(Message);
59 << &FunctionDescription.data()[1];
61 if (Access == AccessKind::write) {
62 Os <<
" overflows the destination buffer";
64 Os <<
" accesses out-of-bound array element";
70enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
72enum class CharKind { Regular = 0,
Wide };
73constexpr CharKind CK_Regular = CharKind::Regular;
74constexpr CharKind CK_Wide = CharKind::Wide;
83 check::LiveSymbols, check::DeadSymbols,
84 check::RegionChanges> {
85 mutable const char *CurrentFunctionDescription =
nullptr;
93 CheckerFrontendWithBugType OutOfBounds{
"Out-of-bound array access"};
95 "Improper arguments"};
97 CheckerFrontendWithBugType UninitializedRead{
98 "Accessing unitialized/garbage values"};
100 StringRef getDebugTag()
const override {
return "MallocChecker"; }
102 static void *getTag() {
static int tag;
return &tag; }
104 bool evalCall(
const CallEvent &
Call, CheckerContext &
C)
const;
105 void checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const;
107 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &
C)
const;
112 ArrayRef<const MemRegion *> ExplicitRegions,
113 ArrayRef<const MemRegion *> Regions,
114 const LocationContext *LCtx,
115 const CallEvent *
Call)
const;
117 using FnCheck =
std::function<void(
const CStringChecker *, CheckerContext &,
120 CallDescriptionMap<FnCheck> Callbacks = {
121 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
122 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
123 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
124 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
125 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
126 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
127 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
128 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
129 {{CDM::CLibrary, {
"memcmp"}, 3},
130 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
131 {{CDM::CLibrary, {
"wmemcmp"}, 3},
132 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
133 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
134 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
135 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
136 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
137 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
138 &CStringChecker::evalMemset},
139 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
141 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
142 &CStringChecker::evalStrcpy},
143 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
144 &CStringChecker::evalStrncpy},
145 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
146 &CStringChecker::evalStpcpy},
147 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
148 &CStringChecker::evalStrlcpy},
149 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
150 &CStringChecker::evalStrcat},
151 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
152 &CStringChecker::evalStrncat},
153 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
154 &CStringChecker::evalStrlcat},
155 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
156 &CStringChecker::evalstrLength},
157 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
158 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
159 &CStringChecker::evalstrnLength},
160 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
161 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
162 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
163 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
164 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
165 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
166 {{CDM::CLibrary, {
"strxfrm"}, 3}, &CStringChecker::evalStrxfrm},
167 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
168 {{CDM::CLibrary, {
"bcmp"}, 3},
169 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
170 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
171 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
172 &CStringChecker::evalBzero},
180 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
181 &CStringChecker::evalSprintf},
182 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
183 &CStringChecker::evalSnprintf},
187 CallDescription StdCopy{CDM::SimpleFunc, {
"std",
"copy"}, 3},
188 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
190 FnCheck identifyCall(
const CallEvent &
Call, CheckerContext &
C)
const;
191 void evalMemcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
192 void evalMempcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
193 void evalMemmove(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
194 void evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const;
195 void evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
197 DestinationArgExpr Dest, SourceArgExpr Source,
198 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
200 void evalMemcmp(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
202 void evalstrLength(CheckerContext &
C,
const CallEvent &
Call)
const;
203 void evalstrnLength(CheckerContext &
C,
const CallEvent &
Call)
const;
204 void evalstrLengthCommon(CheckerContext &
C,
const CallEvent &
Call,
205 bool IsStrnlen =
false)
const;
207 void evalStrcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
208 void evalStrncpy(CheckerContext &
C,
const CallEvent &
Call)
const;
209 void evalStpcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
210 void evalStrlcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
211 void evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
212 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
213 bool returnPtr =
true)
const;
215 void evalStrxfrm(CheckerContext &
C,
const CallEvent &
Call)
const;
217 void evalStrcat(CheckerContext &
C,
const CallEvent &
Call)
const;
218 void evalStrncat(CheckerContext &
C,
const CallEvent &
Call)
const;
219 void evalStrlcat(CheckerContext &
C,
const CallEvent &
Call)
const;
221 void evalStrcmp(CheckerContext &
C,
const CallEvent &
Call)
const;
222 void evalStrncmp(CheckerContext &
C,
const CallEvent &
Call)
const;
223 void evalStrcasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
224 void evalStrncasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
225 void evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
226 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
228 void evalStrsep(CheckerContext &
C,
const CallEvent &
Call)
const;
230 void evalStdCopy(CheckerContext &
C,
const CallEvent &
Call)
const;
231 void evalStdCopyBackward(CheckerContext &
C,
const CallEvent &
Call)
const;
232 void evalStdCopyCommon(CheckerContext &
C,
const CallEvent &
Call)
const;
233 void evalMemset(CheckerContext &
C,
const CallEvent &
Call)
const;
234 void evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const;
236 void evalSprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
237 void evalSnprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
238 void evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
239 bool IsBounded)
const;
242 std::pair<ProgramStateRef , ProgramStateRef >
243 static assumeZero(CheckerContext &
C,
249 static SVal getCStringLengthForRegion(CheckerContext &
C,
254 static const StringLiteral *getStringLiteralFromRegion(
const MemRegion *MR);
256 SVal getCStringLength(CheckerContext &
C,
260 bool hypothetical =
false)
const;
262 const StringLiteral *getCStringLiteral(CheckerContext &
C,
271 SVal BufV, SVal SizeV, QualType SizeTy);
279 static ProgramStateRef invalidateDestinationBufferAlwaysEscapeSuperRegion(
293 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
295 InvalidationTraitOperations);
297 static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
298 const MemRegion *MR);
301 SVal CharE,
const Expr *Size, CheckerContext &
C,
306 AnyArgExpr Arg, SVal l)
const;
310 AnyArgExpr Buffer, SVal Element, SVal Size)
const;
312 AnyArgExpr Buffer, SVal Element,
314 CharKind CK = CharKind::Regular)
const;
316 AnyArgExpr Buffer, SizeArgExpr Size,
318 CharKind CK = CharKind::Regular)
const;
320 SizeArgExpr Size, AnyArgExpr
First,
322 CharKind CK = CharKind::Regular)
const;
323 void emitOverlapBug(CheckerContext &
C,
326 const Stmt *Second)
const;
328 void emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
const Stmt *S,
329 StringRef WarningMsg)
const;
331 const Stmt *S, StringRef WarningMsg)
const;
333 const Stmt *S, StringRef WarningMsg)
const;
335 const Expr *E,
const MemRegion *R,
336 StringRef Msg)
const;
346 SVal BufVal, QualType BufTy, SVal LengthVal,
358std::pair<ProgramStateRef, ProgramStateRef>
361 std::optional<DefinedSVal> val =
V.getAs<DefinedSVal>();
363 return std::pair<ProgramStateRef, ProgramStateRef>(State, State);
365 SValBuilder &svalBuilder =
C.getSValBuilder();
366 DefinedOrUnknownSVal zero = svalBuilder.
makeZeroVal(Ty);
367 return State->assume(svalBuilder.
evalEQ(State, *val, zero));
372 AnyArgExpr Arg, SVal l)
const {
378 std::tie(stateNull, stateNonNull) =
379 assumeZero(
C, State, l, Arg.Expression->
getType());
381 if (stateNull && !stateNonNull) {
384 llvm::raw_svector_ostream
OS(buf);
385 assert(CurrentFunctionDescription);
386 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
387 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
388 << CurrentFunctionDescription;
390 emitNullArgBug(
C, stateNull, Arg.Expression,
OS.str());
396 assert(stateNonNull);
405 if (CK == CharKind::Regular) {
421 if (Offset.isUnknown())
428 Os << Idx << llvm::getOrdinalSuffix(Idx);
433 AnyArgExpr Buffer, SVal Element,
440 SVal BufVal =
C.getSVal(Buffer.Expression);
441 const auto *ER = dyn_cast_or_null<ElementRegion>(BufVal.
getAsRegion());
445 const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
451 if (!SuperR->getValueType()->isArrayType())
454 SValBuilder &SVB =
C.getSValBuilder();
459 std::optional<Loc> FirstElementVal =
461 if (!FirstElementVal)
466 State->getSVal(*FirstElementVal).isUndef()) {
467 llvm::SmallString<258> Buf;
468 llvm::raw_svector_ostream
OS(Buf);
469 OS <<
"The first element of the ";
471 OS <<
" argument is undefined";
472 emitUninitializedReadBug(
C, State, Buffer.Expression,
473 FirstElementVal->getAsRegion(),
OS.str());
504 std::optional<NonLoc> Offset =
514 SVal LastIdx = SVB.
evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);
516 SVal LastElementVal = State->getLValue(ElemTy, LastIdx, BufVal);
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) {
593 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
594 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
605 AnyArgExpr Buffer, SizeArgExpr Size,
606 AccessKind Access, CharKind CK)
const {
611 SValBuilder &svalBuilder =
C.getSValBuilder();
614 QualType SizeTy =
Size.Expression->getType();
615 QualType PtrTy = getCharPtrType(Ctx, CK);
618 SVal BufVal =
C.getSVal(Buffer.Expression);
619 State = checkNonNull(
C, State, Buffer, BufVal);
627 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
635 SVal LengthVal =
C.getSVal(
Size.Expression);
636 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
642 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
643 if (Offset.isUnknown())
645 NonLoc LastOffset = Offset.
castAs<NonLoc>();
648 if (std::optional<Loc> BufLoc = BufStart.
getAs<Loc>()) {
651 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
652 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
653 if (Access == AccessKind::read)
654 State = checkInit(
C, State, Buffer, BufStart, *Length);
667 SizeArgExpr Size, AnyArgExpr
First,
680 if (!
First.Expression->getType()->isAnyPointerType() ||
685 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
690 const LocationContext *LCtx =
C.getLocationContext();
691 SVal firstVal = state->getSVal(
First.Expression, LCtx);
692 SVal secondVal = state->getSVal(Second.Expression, LCtx);
694 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
698 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
703 SValBuilder &svalBuilder =
C.getSValBuilder();
704 std::tie(stateTrue, stateFalse) =
705 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
707 if (stateTrue && !stateFalse) {
710 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
735 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
736 std::optional<DefinedOrUnknownSVal> reverseTest =
737 reverse.
getAs<DefinedOrUnknownSVal>();
741 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
748 std::swap(firstLoc, secondLoc);
751 std::swap(
First, Second);
756 SVal LengthVal = state->getSVal(
Size.Expression, LCtx);
757 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
764 QualType CharPtrTy = getCharPtrType(Ctx, CK);
766 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
767 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
772 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
774 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
780 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
781 std::optional<DefinedOrUnknownSVal> OverlapTest =
782 Overlap.
getAs<DefinedOrUnknownSVal>();
786 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
788 if (stateTrue && !stateFalse) {
790 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
810void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
812 const Stmt *Second)
const {
814 "Can't emit from a checker that is not enabled!");
815 ExplodedNode *N =
C.generateErrorNode(state);
820 auto report = std::make_unique<PathSensitiveBugReport>(
821 BufferOverlap,
"Arguments must not be overlapping buffers", N);
822 report->addRange(
First->getSourceRange());
825 C.emitReport(std::move(report));
828void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
829 const Stmt *S, StringRef WarningMsg)
const {
831 "Can't emit from a checker that is not enabled!");
832 if (ExplodedNode *N =
C.generateErrorNode(State)) {
834 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
836 if (
const auto *Ex = dyn_cast<Expr>(S))
838 C.emitReport(std::move(
Report));
842void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
844 const Expr *E,
const MemRegion *R,
845 StringRef Msg)
const {
847 "Can't emit from a checker that is not enabled!");
848 if (ExplodedNode *N =
C.generateErrorNode(State)) {
850 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
851 Report->addNote(
"Other elements might also be undefined",
855 Report->addVisitor<NoStoreFuncVisitor>(
R->castAs<SubRegion>());
856 C.emitReport(std::move(
Report));
860void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
862 StringRef WarningMsg)
const {
864 "Can't emit from a checker that is not enabled!");
865 if (ExplodedNode *N =
C.generateErrorNode(State)) {
870 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
872 C.emitReport(std::move(
Report));
876void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
878 StringRef WarningMsg)
const {
880 "Can't emit from a checker that is not enabled!");
881 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
883 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
886 C.emitReport(std::move(
Report));
893 NonLoc right)
const {
898 SValBuilder &svalBuilder =
C.getSValBuilder();
902 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
903 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
907 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
912 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
917 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
920 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
921 *maxMinusRightNL, cmpTy);
923 auto [StateOverflow, StateOkay] =
924 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
926 if (StateOverflow && !StateOkay) {
932 C.addSink(StateOverflow);
947 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
952 case MemRegion::StringRegionKind:
957 case MemRegion::SymbolicRegionKind:
958 case MemRegion::AllocaRegionKind:
959 case MemRegion::NonParamVarRegionKind:
960 case MemRegion::ParamVarRegionKind:
961 case MemRegion::FieldRegionKind:
962 case MemRegion::ObjCIvarRegionKind:
966 case MemRegion::ElementRegionKind:
980 return state->remove<CStringLength>(MR);
982 return state->set<CStringLength>(MR, strLength);
985SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
992 const SVal *Recorded = state->get<CStringLength>(MR);
998 SValBuilder &svalBuilder =
C.getSValBuilder();
1002 C.getLocationContext(),
1005 if (!hypothetical) {
1006 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
1009 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1010 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
1011 std::optional<APSIntPtr> maxLengthInt =
1013 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
1014 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1016 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
1018 state = state->set<CStringLength>(MR, strLength);
1024const StringLiteral *
1025CStringChecker::getStringLiteralFromRegion(
const MemRegion *MR) {
1027 case MemRegion::StringRegionKind:
1029 case MemRegion::NonParamVarRegionKind:
1031 Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage())
1032 return dyn_cast_or_null<StringLiteral>(
Decl->getInit());
1039SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
1040 const Expr *Ex, SVal Buf,
1041 bool hypothetical)
const {
1047 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
1049 SmallString<120> buf;
1050 llvm::raw_svector_ostream os(buf);
1051 assert(CurrentFunctionDescription);
1052 os <<
"Argument to " << CurrentFunctionDescription
1053 <<
" is the address of the label '" << Label->getLabel()->getName()
1054 <<
"', which is not a null-terminated string";
1056 emitNotCStringBug(
C, state, Ex, os.str());
1058 return UndefinedVal();
1062 return UnknownVal();
1069 if (
const StringLiteral *StrLit = getStringLiteralFromRegion(MR)) {
1075 SValBuilder &SVB =
C.getSValBuilder();
1080 case MemRegion::StringRegionKind:
1081 case MemRegion::NonParamVarRegionKind:
1082 case MemRegion::SymbolicRegionKind:
1083 case MemRegion::AllocaRegionKind:
1084 case MemRegion::ParamVarRegionKind:
1085 case MemRegion::FieldRegionKind:
1086 case MemRegion::ObjCIvarRegionKind:
1087 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1088 case MemRegion::CompoundLiteralRegionKind:
1090 return UnknownVal();
1091 case MemRegion::ElementRegionKind: {
1096 const SubRegion *SuperReg =
1098 const StringLiteral *StrLit = getStringLiteralFromRegion(SuperReg);
1100 return UnknownVal();
1101 SValBuilder &SVB =
C.getSValBuilder();
1106 if (state->assume(SVB.
evalBinOpNN(state, BO_LE, Idx, LengthVal,
1108 .
castAs<DefinedOrUnknownSVal>(),
1110 return SVB.
evalBinOp(state, BO_Sub, LengthVal, Idx, SizeTy);
1111 return UnknownVal();
1118 SmallString<120> buf;
1119 llvm::raw_svector_ostream os(buf);
1121 assert(CurrentFunctionDescription);
1122 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1124 if (SummarizeRegion(os,
C.getASTContext(), MR))
1125 os <<
", which is not a null-terminated string";
1127 os <<
"not a null-terminated string";
1129 emitNotCStringBug(
C, state, Ex, os.str());
1131 return UndefinedVal();
1135const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1148 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1156bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1157 SVal BufVal, QualType BufTy,
1158 SVal LengthVal, QualType LengthTy) {
1167 SValBuilder &SB =
C.getSValBuilder();
1168 ASTContext &Ctx =
C.getASTContext();
1172 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1178 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1179 if (Offset.isUnknown())
1181 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1184 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1185 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1189 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1196 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1202 C.getASTContext().CharTy &&
1203 "isFirstBufInBound should only be called with char* ElementRegions");
1210 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1214 return static_cast<bool>(StInBound);
1220 auto InvalidationTraitOperations =
1221 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1222 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1225 if (MemRegion::FieldRegionKind ==
R->getKind() &&
1226 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1234 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1238CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1240 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1241 const MemRegion *
R) {
1245 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1248ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1250 auto InvalidationTraitOperations =
1251 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1252 if (MemRegion::FieldRegionKind ==
R->getKind())
1259 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1266 auto InvalidationTraitOperations =
1267 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1276 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1281 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1283 InvalidationTraitOperations) {
1284 std::optional<Loc> L =
V.getAs<Loc>();
1291 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1292 const MemRegion *
R = MR->getRegion()->
StripCasts();
1296 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1302 const LocationContext *LCtx =
C.getPredecessor()->getLocationContext();
1303 RegionAndSymbolInvalidationTraits ITraits;
1304 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1306 return State->invalidateRegions(R, Elem,
C.blockCount(), LCtx,
1307 CausesPointerEscape,
nullptr,
nullptr,
1314 return State->killBinding(*L);
1317bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1318 const MemRegion *MR) {
1320 case MemRegion::FunctionCodeRegionKind: {
1322 os <<
"the address of the function '" << *FD <<
'\'';
1324 os <<
"the address of a function";
1327 case MemRegion::BlockCodeRegionKind:
1330 case MemRegion::BlockDataRegionKind:
1333 case MemRegion::CXXThisRegionKind:
1334 case MemRegion::CXXTempObjectRegionKind:
1335 os <<
"a C++ temp object of type "
1338 case MemRegion::NonParamVarRegionKind:
1341 case MemRegion::ParamVarRegionKind:
1344 case MemRegion::FieldRegionKind:
1347 case MemRegion::ObjCIvarRegionKind:
1348 os <<
"an instance variable of type "
1357 SVal CharVal,
const Expr *Size,
1359 SVal MemVal =
C.getSVal(DstBuffer);
1360 SVal SizeVal =
C.getSVal(Size);
1370 const MemRegion *BR = Offset.
getRegion();
1372 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1376 SValBuilder &svalBuilder =
C.getSValBuilder();
1377 ASTContext &Ctx =
C.getASTContext();
1387 std::tie(StateWholeReg, StateNotWholeReg) =
1388 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1395 std::tie(StateNullChar, StateNonNullChar) =
1398 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1399 !StateNonNullChar) {
1406 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1407 C.getLocationContext());
1411 State = invalidateDestinationBufferBySize(
1412 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1415 if (StateNullChar && !StateNonNullChar) {
1418 State = setCStringLength(State, MR,
1420 }
else if (!StateNullChar && StateNonNullChar) {
1422 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1423 C.getLocationContext(),
C.blockCount());
1427 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1430 State = setCStringLength(
1431 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1437 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1438 SizeVal,
Size->getType());
1447void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1449 DestinationArgExpr Dest,
1450 SourceArgExpr Source,
bool Restricted,
1451 bool IsMempcpy, CharKind CK)
const {
1452 CurrentFunctionDescription =
"memory copy function";
1455 const LocationContext *LCtx =
C.getLocationContext();
1456 SVal sizeVal = state->getSVal(
Size.Expression, LCtx);
1457 QualType sizeTy =
Size.Expression->getType();
1460 std::tie(stateZeroSize, stateNonZeroSize) =
1461 assumeZero(
C, state, sizeVal, sizeTy);
1464 SVal destVal = state->getSVal(Dest.Expression, LCtx);
1468 if (stateZeroSize && !stateNonZeroSize) {
1470 stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1471 C.addTransition(stateZeroSize);
1476 if (stateNonZeroSize) {
1480 state = stateNonZeroSize;
1484 state = checkNonNull(
C, state, Dest, destVal);
1489 SVal srcVal = state->getSVal(Source.Expression, LCtx);
1493 state = checkNonNull(
C, state, Source, srcVal);
1498 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1499 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1502 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1511 SValBuilder &SvalBuilder =
C.getSValBuilder();
1513 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1514 SVal DestRegCharVal =
1515 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1516 SVal lastElement =
C.getSValBuilder().evalBinOp(
1517 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1521 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1524 state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1528 state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1537 state = invalidateDestinationBufferBySize(
1538 C, state, Dest.Expression,
Call.getCFGElementRef(),
1539 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1543 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1544 C.getSVal(Source.Expression));
1546 C.addTransition(state);
1550void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1551 CharKind CK)
const {
1554 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1555 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1556 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1560 constexpr bool IsRestricted =
true;
1561 constexpr bool IsMempcpy =
false;
1562 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1565void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1566 CharKind CK)
const {
1569 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1570 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1571 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1573 constexpr bool IsRestricted =
true;
1574 constexpr bool IsMempcpy =
true;
1575 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1579void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1580 CharKind CK)
const {
1583 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1584 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1585 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1587 constexpr bool IsRestricted =
false;
1588 constexpr bool IsMempcpy =
false;
1589 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1593void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1595 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1596 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1597 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1599 constexpr bool IsRestricted =
false;
1600 constexpr bool IsMempcpy =
false;
1601 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1602 IsMempcpy, CharKind::Regular);
1605void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1606 CharKind CK)
const {
1608 CurrentFunctionDescription =
"memory comparison function";
1610 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1611 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1612 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1615 SValBuilder &Builder =
C.getSValBuilder();
1616 const LocationContext *LCtx =
C.getLocationContext();
1619 SVal sizeVal = State->getSVal(
Size.Expression, LCtx);
1620 QualType sizeTy =
Size.Expression->getType();
1623 std::tie(stateZeroSize, stateNonZeroSize) =
1624 assumeZero(
C, State, sizeVal, sizeTy);
1628 if (stateZeroSize) {
1629 State = stateZeroSize;
1630 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1631 Builder.makeZeroVal(
Call.getResultType()));
1632 C.addTransition(State);
1636 if (stateNonZeroSize) {
1637 State = stateNonZeroSize;
1641 DefinedOrUnknownSVal LV =
1642 State->getSVal(
Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1643 DefinedOrUnknownSVal RV =
1644 State->getSVal(
Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1648 std::tie(SameBuffer, NotSameBuffer) =
1649 State->assume(Builder.evalEQ(State, LV, RV));
1653 if (SameBuffer && !NotSameBuffer) {
1655 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1657 State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1658 Builder.makeZeroVal(
Call.getResultType()));
1659 C.addTransition(State);
1666 assert(NotSameBuffer);
1667 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1668 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1671 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1672 State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1673 C.addTransition(State);
1678void CStringChecker::evalstrLength(CheckerContext &
C,
1679 const CallEvent &
Call)
const {
1681 evalstrLengthCommon(
C,
Call,
false);
1684void CStringChecker::evalstrnLength(CheckerContext &
C,
1685 const CallEvent &
Call)
const {
1687 evalstrLengthCommon(
C,
Call,
true);
1690void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1691 const CallEvent &
Call,
1692 bool IsStrnlen)
const {
1693 CurrentFunctionDescription =
"string length function";
1695 const LocationContext *LCtx =
C.getLocationContext();
1698 const Expr *maxlenExpr =
Call.getArgExpr(1);
1699 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1702 std::tie(stateZeroSize, stateNonZeroSize) =
1703 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1707 if (stateZeroSize) {
1708 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1709 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1710 C.addTransition(stateZeroSize);
1714 if (!stateNonZeroSize)
1718 state = stateNonZeroSize;
1722 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1723 SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
1724 state = checkNonNull(
C, state, Arg, ArgVal);
1729 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1736 DefinedOrUnknownSVal result = UnknownVal();
1741 QualType cmpTy =
C.getSValBuilder().getConditionType();
1745 const Expr *maxlenExpr =
Call.getArgExpr(1);
1746 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1748 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1749 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1751 if (strLengthNL && maxlenValNL) {
1755 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1757 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1758 .castAs<DefinedOrUnknownSVal>());
1760 if (stateStringTooLong && !stateStringNotTooLong) {
1762 result = *maxlenValNL;
1763 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1765 result = *strLengthNL;
1774 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1775 NonLoc resultNL = result.
castAs<NonLoc>();
1778 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1779 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1780 .castAs<DefinedOrUnknownSVal>(),
true);
1784 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1785 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1786 .castAs<DefinedOrUnknownSVal>(),
true);
1792 result = strLength.
castAs<DefinedOrUnknownSVal>();
1797 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1802 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1803 state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1804 C.addTransition(state);
1807void CStringChecker::evalStrcpy(CheckerContext &
C,
1808 const CallEvent &
Call)
const {
1810 evalStrcpyCommon(
C,
Call,
1813 ConcatFnKind::none);
1816void CStringChecker::evalStrncpy(CheckerContext &
C,
1817 const CallEvent &
Call)
const {
1819 evalStrcpyCommon(
C,
Call,
1822 ConcatFnKind::none);
1825void CStringChecker::evalStpcpy(CheckerContext &
C,
1826 const CallEvent &
Call)
const {
1828 evalStrcpyCommon(
C,
Call,
1831 ConcatFnKind::none);
1834void CStringChecker::evalStrlcpy(CheckerContext &
C,
1835 const CallEvent &
Call)
const {
1837 evalStrcpyCommon(
C,
Call,
1844void CStringChecker::evalStrcat(CheckerContext &
C,
1845 const CallEvent &
Call)
const {
1847 evalStrcpyCommon(
C,
Call,
1850 ConcatFnKind::strcat);
1853void CStringChecker::evalStrncat(CheckerContext &
C,
1854 const CallEvent &
Call)
const {
1856 evalStrcpyCommon(
C,
Call,
1859 ConcatFnKind::strcat);
1862void CStringChecker::evalStrlcat(CheckerContext &
C,
1863 const CallEvent &
Call)
const {
1867 evalStrcpyCommon(
C,
Call,
1870 ConcatFnKind::strlcat,
1874void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1875 bool ReturnEnd,
bool IsBounded,
1876 ConcatFnKind appendK,
1877 bool returnPtr)
const {
1878 if (appendK == ConcatFnKind::none)
1879 CurrentFunctionDescription =
"string copy function";
1881 CurrentFunctionDescription =
"string concatenation function";
1884 const LocationContext *LCtx =
C.getLocationContext();
1887 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1888 SVal DstVal = state->getSVal(Dst.Expression, LCtx);
1889 state = checkNonNull(
C, state, Dst, DstVal);
1894 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1895 SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
1896 state = checkNonNull(
C, state, srcExpr, srcVal);
1901 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1902 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1905 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1906 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1912 SValBuilder &svalBuilder =
C.getSValBuilder();
1919 SVal amountCopied = UnknownVal();
1920 SVal maxLastElementIndex = UnknownVal();
1921 const char *boundWarning =
nullptr;
1925 SizeArgExpr SrcExprAsSizeDummy = {
1926 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1927 state = CheckOverlap(
1929 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1938 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1939 SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
1943 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1945 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1949 if (strLengthNL && lenValNL) {
1951 case ConcatFnKind::none:
1952 case ConcatFnKind::strcat: {
1957 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1959 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1960 .castAs<DefinedOrUnknownSVal>());
1962 if (stateSourceTooLong && !stateSourceNotTooLong) {
1965 state = stateSourceTooLong;
1966 amountCopied = lenVal;
1968 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1970 state = stateSourceNotTooLong;
1971 amountCopied = strLength;
1975 case ConcatFnKind::strlcat:
1976 if (!dstStrLengthNL)
1980 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
1981 *dstStrLengthNL, sizeTy);
1985 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1987 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
1994 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1997 std::tie(TrueState, FalseState) =
1998 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
2001 if (TrueState && !FalseState) {
2002 amountCopied = strLength;
2006 if (!TrueState && FalseState) {
2007 amountCopied = freeSpace;
2010 if (TrueState && FalseState)
2011 amountCopied = UnknownVal();
2018 case ConcatFnKind::strcat:
2024 if (dstStrLength.isUndef())
2027 if (dstStrLengthNL) {
2029 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2031 boundWarning =
"Size argument is greater than the free space in the "
2032 "destination buffer";
2035 case ConcatFnKind::none:
2036 case ConcatFnKind::strlcat:
2046 std::tie(StateZeroSize, StateNonZeroSize) =
2047 assumeZero(
C, state, *lenValNL, sizeTy);
2050 if (StateZeroSize && !StateNonZeroSize) {
2053 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
2055 if (appendK == ConcatFnKind::none) {
2057 StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
2062 state, BO_Add, strLength, dstStrLength, sizeTy);
2064 StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
2067 C.addTransition(StateZeroSize);
2075 maxLastElementIndex =
2076 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2077 boundWarning =
"Size argument is greater than the length of the "
2078 "destination buffer";
2085 amountCopied = strLength;
2093 SVal finalStrLength = UnknownVal();
2094 SVal strlRetVal = UnknownVal();
2096 if (appendK == ConcatFnKind::none && !returnPtr) {
2098 strlRetVal = strLength;
2104 if (appendK != ConcatFnKind::none) {
2107 if (dstStrLength.isUndef())
2110 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2111 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2112 *dstStrLengthNL, sizeTy);
2115 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2118 if (amountCopiedNL && dstStrLengthNL) {
2120 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2124 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2125 *dstStrLengthNL, sizeTy);
2134 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2135 assert(!finalStrLength.
isUndef());
2137 if (std::optional<NonLoc> finalStrLengthNL =
2138 finalStrLength.
getAs<NonLoc>()) {
2139 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2143 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2144 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2150 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2153 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2158 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2168 finalStrLength = amountCopied;
2176 Result = (ReturnEnd ? UnknownVal() : DstVal);
2178 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2189 if (std::optional<loc::MemRegionVal> dstRegVal =
2190 DstVal.
getAs<loc::MemRegionVal>()) {
2191 QualType ptrTy = Dst.Expression->getType();
2195 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2196 SVal maxLastElement =
2197 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2200 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2204 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2210 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2211 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2212 *knownStrLength, ptrTy);
2215 if (!boundWarning) {
2217 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2221 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2227 if (returnPtr && ReturnEnd)
2240 bool CouldAccessOutOfBound =
true;
2241 if (IsBounded && amountCopied.
isUnknown()) {
2242 auto CouldAccessOutOfBoundForSVal =
2243 [&](std::optional<NonLoc> Val) ->
bool {
2246 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2247 Dst.Expression->getType(), *Val,
2248 C.getASTContext().getSizeType());
2251 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2253 if (CouldAccessOutOfBound) {
2255 const Expr *LenExpr =
Call.getArgExpr(2);
2256 SVal LenVal = state->getSVal(LenExpr, LCtx);
2264 CouldAccessOutOfBound =
2265 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2276 if (CouldAccessOutOfBound)
2277 state = invalidateDestinationBufferBySize(
2278 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2279 amountCopied,
C.getASTContext().getSizeType());
2281 state = invalidateDestinationBufferNeverOverflows(
2282 C, state,
Call.getCFGElementRef(), *dstRegVal);
2286 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2289 if (IsBounded && (appendK == ConcatFnKind::none)) {
2294 if (amountCopied != strLength)
2295 finalStrLength = UnknownVal();
2297 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2305 if (ReturnEnd &&
Result.isUnknown()) {
2310 state = state->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2311 C.addTransition(state);
2314void CStringChecker::evalStrxfrm(CheckerContext &
C,
2315 const CallEvent &
Call)
const {
2317 CurrentFunctionDescription =
"locale transformation function";
2320 const LocationContext *LCtx =
C.getLocationContext();
2321 SValBuilder &SVB =
C.getSValBuilder();
2324 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2325 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2326 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2329 SVal SrcVal = State->getSVal(Source.Expression, LCtx);
2330 State = checkNonNull(
C, State, Source, SrcVal);
2335 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2343 auto BindReturnAndTransition = [&RetVal, &
Call, LCtx,
2346 State = State->BindExpr(
Call.getOriginExpr(), LCtx, RetVal);
2347 C.addTransition(State);
2352 SVal SizeVal = State->getSVal(
Size.Expression, LCtx);
2353 QualType SizeTy =
Size.Expression->getType();
2355 auto [StateZeroSize, StateSizeNonZero] =
2356 assumeZero(
C, State, SizeVal, SizeTy);
2359 if (!StateZeroSize && !StateSizeNonZero)
2360 return BindReturnAndTransition(State);
2363 if (StateZeroSize && !StateSizeNonZero)
2364 return BindReturnAndTransition(StateZeroSize);
2367 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, LCtx);
2368 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2369 if (!StateSizeNonZero)
2373 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2374 AccessKind::write, CK_Regular);
2375 if (!StateSizeNonZero)
2380 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2382 .
getAs<DefinedOrUnknownSVal>();
2383 if (!ComparisonVal) {
2385 StateSizeNonZero = invalidateDestinationBufferBySize(
2386 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2387 SizeVal,
Size.Expression->getType());
2388 return BindReturnAndTransition(StateSizeNonZero);
2391 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2395 StateSuccess = invalidateDestinationBufferBySize(
2396 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2397 SizeVal,
Size.Expression->getType());
2398 BindReturnAndTransition(StateSuccess);
2404 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2405 StateFailure = StateFailure->killBinding(*DestLoc);
2407 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, LCtx);
2410 BindReturnAndTransition(StateFailure);
2414void CStringChecker::evalStrcmp(CheckerContext &
C,
2415 const CallEvent &
Call)
const {
2417 evalStrcmpCommon(
C,
Call,
false,
false);
2420void CStringChecker::evalStrncmp(CheckerContext &
C,
2421 const CallEvent &
Call)
const {
2423 evalStrcmpCommon(
C,
Call,
true,
false);
2426void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2427 const CallEvent &
Call)
const {
2429 evalStrcmpCommon(
C,
Call,
false,
true);
2432void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2433 const CallEvent &
Call)
const {
2435 evalStrcmpCommon(
C,
Call,
true,
true);
2438void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2439 bool IsBounded,
bool IgnoreCase)
const {
2440 CurrentFunctionDescription =
"string comparison function";
2442 const LocationContext *LCtx =
C.getLocationContext();
2445 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2446 SVal LeftVal = state->getSVal(
Left.Expression, LCtx);
2447 state = checkNonNull(
C, state, Left, LeftVal);
2452 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2453 SVal RightVal = state->getSVal(
Right.Expression, LCtx);
2454 state = checkNonNull(
C, state, Right, RightVal);
2459 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2464 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2471 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2472 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2475 SValBuilder &svalBuilder =
C.getSValBuilder();
2476 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2478 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2484 StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2485 svalBuilder.makeZeroVal(
Call.getResultType()));
2486 C.addTransition(StSameBuf);
2493 assert(StNotSameBuf);
2494 state = StNotSameBuf;
2500 const StringLiteral *LeftStrLiteral =
2501 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2502 const StringLiteral *RightStrLiteral =
2503 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2504 bool canComputeResult =
false;
2505 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2507 if (LeftStrLiteral && RightStrLiteral) {
2508 StringRef LeftStrRef = LeftStrLiteral->
getString();
2509 StringRef RightStrRef = RightStrLiteral->
getString();
2513 const Expr *lenExpr =
Call.getArgExpr(2);
2514 SVal lenVal = state->getSVal(lenExpr, LCtx);
2517 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2519 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2520 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2521 canComputeResult =
true;
2525 canComputeResult =
true;
2528 if (canComputeResult) {
2530 size_t s1Term = LeftStrRef.find(
'\0');
2531 if (s1Term != StringRef::npos)
2532 LeftStrRef = LeftStrRef.substr(0, s1Term);
2534 size_t s2Term = RightStrRef.find(
'\0');
2535 if (s2Term != StringRef::npos)
2536 RightStrRef = RightStrRef.substr(0, s2Term);
2539 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2540 : LeftStrRef.compare(RightStrRef);
2544 if (compareRes == 0) {
2545 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2548 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2552 SVal compareWithZero =
2553 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2554 svalBuilder.getConditionType());
2555 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2556 state = state->assume(compareWithZeroVal,
true);
2561 state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2564 C.addTransition(state);
2567void CStringChecker::evalStrsep(CheckerContext &
C,
2568 const CallEvent &
Call)
const {
2571 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2573 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2574 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2578 CurrentFunctionDescription =
"strsep()";
2580 const LocationContext *LCtx =
C.getLocationContext();
2584 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2585 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2590 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2591 SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2592 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2596 SValBuilder &SVB =
C.getSValBuilder();
2598 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2600 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2605 State = invalidateDestinationBufferNeverOverflows(
2610 State = State->bindLoc(*SearchStrLoc,
2620 State = State->BindExpr(
Call.getOriginExpr(), LCtx,
Result);
2621 C.addTransition(State);
2625void CStringChecker::evalStdCopy(CheckerContext &
C,
2626 const CallEvent &
Call)
const {
2627 evalStdCopyCommon(
C,
Call);
2630void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2631 const CallEvent &
Call)
const {
2632 evalStdCopyCommon(
C,
Call);
2635void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2636 const CallEvent &
Call)
const {
2637 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2642 const LocationContext *LCtx =
C.getLocationContext();
2650 const Expr *Dst =
Call.getArgExpr(2);
2651 SVal DstVal = State->getSVal(Dst, LCtx);
2654 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2655 C, State,
Call.getCFGElementRef(), DstVal);
2657 SValBuilder &SVB =
C.getSValBuilder();
2660 State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2662 C.addTransition(State);
2665void CStringChecker::evalMemset(CheckerContext &
C,
2666 const CallEvent &
Call)
const {
2668 CurrentFunctionDescription =
"memory set function";
2670 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2671 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2672 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2677 const LocationContext *LCtx =
C.getLocationContext();
2678 SVal SizeVal =
C.getSVal(
Size.Expression);
2679 QualType SizeTy =
Size.Expression->getType();
2682 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2685 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2689 if (ZeroSize && !NonZeroSize) {
2690 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2691 C.addTransition(ZeroSize);
2697 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2701 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2708 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2709 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2712 State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2713 C.addTransition(State);
2716void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2717 CurrentFunctionDescription =
"memory clearance function";
2719 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2720 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2721 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2726 SVal SizeVal =
C.getSVal(
Size.Expression);
2727 QualType SizeTy =
Size.Expression->getType();
2730 std::tie(StateZeroSize, StateNonZeroSize) =
2731 assumeZero(
C, State, SizeVal, SizeTy);
2735 if (StateZeroSize && !StateNonZeroSize) {
2736 C.addTransition(StateZeroSize);
2741 SVal MemVal =
C.getSVal(Buffer.Expression);
2745 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2749 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2753 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
2754 Size.Expression,
C, State))
2757 C.addTransition(State);
2760void CStringChecker::evalSprintf(CheckerContext &
C,
2761 const CallEvent &
Call)
const {
2762 CurrentFunctionDescription =
"'sprintf'";
2763 evalSprintfCommon(
C,
Call,
false);
2766void CStringChecker::evalSnprintf(CheckerContext &
C,
2767 const CallEvent &
Call)
const {
2768 CurrentFunctionDescription =
"'snprintf'";
2769 evalSprintfCommon(
C,
Call,
true);
2772void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
2773 bool IsBounded)
const {
2776 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2778 const auto NumParams =
Call.parameters().size();
2779 if (CE->getNumArgs() < NumParams) {
2784 const auto AllArguments =
2785 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2786 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2788 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2790 if (
const QualType
type = ArgExpr->getType();
2791 !
type->isAnyPointerType() ||
2792 !
type->getPointeeType()->isAnyCharacterType())
2794 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
2797 SizeArgExpr SrcExprAsSizeDummy = {
2798 {Source.Expression, Source.ArgumentIndex}};
2799 State = CheckOverlap(
2801 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2807 C.addTransition(State);
2814CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2815 CheckerContext &
C)
const {
2816 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2820 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
2825 return &CStringChecker::evalStdCopy;
2827 return &CStringChecker::evalStdCopyBackward;
2833 for (
auto I : CE->arguments()) {
2834 QualType T = I->getType();
2839 const FnCheck *Callback = Callbacks.lookup(
Call);
2846bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
2847 FnCheck Callback = identifyCall(
Call,
C);
2855 Callback(
this,
C,
Call);
2863 return C.isDifferent();
2866void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
2870 for (
const auto *I : DS->
decls()) {
2871 const VarDecl *D = dyn_cast<VarDecl>(I);
2885 Loc VarLoc = state->getLValue(D,
C.getLocationContext());
2890 SVal StrVal =
C.getSVal(
Init);
2891 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2892 DefinedOrUnknownSVal strLength =
2893 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
2895 state = state->set<CStringLength>(MR, strLength);
2898 C.addTransition(state);
2904 ArrayRef<const MemRegion *> ExplicitRegions,
2905 ArrayRef<const MemRegion *> Regions,
2906 const LocationContext *LCtx,
2907 const CallEvent *
Call)
const {
2908 CStringLengthTy Entries = state->get<CStringLength>();
2909 if (Entries.isEmpty())
2912 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2913 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2916 for (
const MemRegion *MR : Regions) {
2917 Invalidated.insert(MR);
2919 SuperRegions.insert(MR);
2920 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2921 MR = SR->getSuperRegion();
2922 SuperRegions.insert(MR);
2926 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2929 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2931 if (SuperRegions.count(MR)) {
2932 Entries = F.remove(Entries, MR);
2937 const MemRegion *Super = MR;
2938 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2939 Super = SR->getSuperRegion();
2940 if (Invalidated.count(Super)) {
2941 Entries = F.remove(Entries, MR);
2947 return state->set<CStringLength>(Entries);
2951 SymbolReaper &SR)
const {
2953 CStringLengthTy Entries = state->get<CStringLength>();
2955 for (SVal Len : llvm::make_second_range(Entries)) {
2961void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2962 CheckerContext &
C)
const {
2964 CStringLengthTy Entries = state->get<CStringLength>();
2965 if (Entries.isEmpty())
2968 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2969 for (
auto [Reg, Len] : Entries) {
2970 if (
SymbolRef Sym = Len.getAsSymbol()) {
2972 Entries = F.remove(Entries, Reg);
2976 state = state->set<CStringLength>(Entries);
2977 C.addTransition(state);
2980void ento::registerCStringModeling(CheckerManager &Mgr) {
2987bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
2991#define REGISTER_CHECKER(NAME) \
2992 void ento::registerCString##NAME(CheckerManager &Mgr) { \
2993 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
2996 bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \
3006#undef REGISTER_CHECKER
static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx)
#define REGISTER_CHECKER(name)
Result
Implement __builtin_bit_cast and related operations.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getBaseElementType(const ArrayType *VAT) const
Return the innermost element type of an array type.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedCharTy
QualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
LangAS getAddressSpace() const
Return the address space of this type.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
unsigned getLength() const
StringRef getString() const
bool isPointerType() const
CanQualType getCanonicalTypeUnqualified() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
bool isAnyPointerType() const
const Expr * getInit() const
APSIntPtr getMaxValue(const llvm::APSInt &v)
std::optional< APSIntPtr > evalAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt &V1, const llvm::APSInt &V2)
bool matches(const CallEvent &Call) const
Returns true if the CallEvent is a call to a function that matches the CallDescription.
Checker families (where a single backend class implements multiple related frontends) should derive f...
CHECKER * getChecker(AT &&...Args)
If the the singleton instance of a checker class is not yet constructed, then construct it (with the ...
ElementRegion is used to represent both array elements and casts.
QualType getValueType() const override
MemRegion - The root abstract class for all memory regions.
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
SValBuilder & getSValBuilder()
@ TK_PreserveContents
Tells that a region's contents is not changed.
@ TK_DoNotInvalidateSuperRegion
@ TK_SuppressEscape
Suppress pointer-escaping of a region.
void setTrait(SymbolRef Sym, InvalidationKinds IK)
bool hasSymbolicOffset() const
const MemRegion * getRegion() const
It might return null.
int64_t getOffset() const
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
BasicValueFactory & getBasicValueFactory()
virtual SVal evalBinOpLN(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with a memory location and non-location opera...
DefinedSVal getMetadataSymbolVal(const void *symbolTag, const MemRegion *region, const Expr *expr, QualType type, const LocationContext *LCtx, unsigned count)
ProgramStateManager & getStateManager()
virtual SVal evalBinOpLL(ProgramStateRef state, BinaryOperator::Opcode op, Loc lhs, Loc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two memory location operands.
ASTContext & getContext()
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
QualType getArrayIndexType() const
loc::MemRegionVal makeLoc(SymbolRef sym)
virtual SVal evalBinOpNN(ProgramStateRef state, BinaryOperator::Opcode op, NonLoc lhs, NonLoc rhs, QualType resultTy)=0
Create a new value which represents a binary expression with two non- location operands.
SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy)
Cast a given SVal to another SVal using given QualType's.
QualType getConditionType() const
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, ConstCFGElementRef elem, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
NonLoc makeZeroArrayIndex()
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
std::optional< T > getAs() const
Convert to the specified SVal type, returning std::nullopt if this SVal is not of the desired type.
const MemRegion * getAsRegion() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
LLVM_ATTRIBUTE_RETURNS_NONNULL const StringLiteral * getStringLiteral() const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
llvm::iterator_range< symbol_iterator > symbols() const
bool isDead(SymbolRef sym)
Returns whether or not a symbol has been confirmed dead.
void markInUse(SymbolRef sym)
Marks a symbol as important to a checker.
__inline void unsigned int _2
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
bool trackExpressionValue(const ExplodedNode *N, const Expr *E, PathSensitiveBugReport &R, TrackingOptions Opts={})
Attempts to add visitors to track expression value back to its point of origin.
const char *const UnixAPI
llvm::DenseSet< SymbolRef > InvalidatedSymbols
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB)
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
CFGBlock::ConstCFGElementRef ConstCFGElementRef
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
U cast(CodeGen::Address addr)
int const char * function