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;
111 ArrayRef<const MemRegion *> ExplicitRegions,
112 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
113 const CallEvent *
Call)
const;
115 using FnCheck =
std::function<void(
const CStringChecker *, CheckerContext &,
118 CallDescriptionMap<FnCheck> Callbacks = {
119 {{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
120 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
121 {{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
122 std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
123 {{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
124 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
125 {{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
126 std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
127 {{CDM::CLibrary, {
"memcmp"}, 3},
128 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
129 {{CDM::CLibrary, {
"wmemcmp"}, 3},
130 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
131 {{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
132 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
133 {{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
134 std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
135 {{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
136 &CStringChecker::evalMemset},
137 {{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
139 {{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
140 &CStringChecker::evalStrcpy},
141 {{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
142 &CStringChecker::evalStrncpy},
143 {{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
144 &CStringChecker::evalStpcpy},
145 {{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
146 &CStringChecker::evalStrlcpy},
147 {{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
148 &CStringChecker::evalStrcat},
149 {{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
150 &CStringChecker::evalStrncat},
151 {{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
152 &CStringChecker::evalStrlcat},
153 {{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
154 &CStringChecker::evalstrLength},
155 {{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
156 {{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
157 &CStringChecker::evalstrnLength},
158 {{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
159 {{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
160 {{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
161 {{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
162 {{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
163 {{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
164 {{CDM::CLibrary, {
"strxfrm"}, 3}, &CStringChecker::evalStrxfrm},
165 {{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
166 {{CDM::CLibrary, {
"bcmp"}, 3},
167 std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
168 {{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
169 {{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
170 &CStringChecker::evalBzero},
178 {{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
179 &CStringChecker::evalSprintf},
180 {{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
181 &CStringChecker::evalSnprintf},
185 CallDescription StdCopy{CDM::SimpleFunc, {
"std",
"copy"}, 3},
186 StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
188 FnCheck identifyCall(
const CallEvent &
Call, CheckerContext &
C)
const;
189 void evalMemcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
190 void evalMempcpy(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
191 void evalMemmove(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
192 void evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const;
193 void evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
195 DestinationArgExpr Dest, SourceArgExpr Source,
196 bool Restricted,
bool IsMempcpy, CharKind CK)
const;
198 void evalMemcmp(CheckerContext &
C,
const CallEvent &
Call, CharKind CK)
const;
200 void evalstrLength(CheckerContext &
C,
const CallEvent &
Call)
const;
201 void evalstrnLength(CheckerContext &
C,
const CallEvent &
Call)
const;
202 void evalstrLengthCommon(CheckerContext &
C,
const CallEvent &
Call,
203 bool IsStrnlen =
false)
const;
205 void evalStrcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
206 void evalStrncpy(CheckerContext &
C,
const CallEvent &
Call)
const;
207 void evalStpcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
208 void evalStrlcpy(CheckerContext &
C,
const CallEvent &
Call)
const;
209 void evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
210 bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
211 bool returnPtr =
true)
const;
213 void evalStrxfrm(CheckerContext &
C,
const CallEvent &
Call)
const;
215 void evalStrcat(CheckerContext &
C,
const CallEvent &
Call)
const;
216 void evalStrncat(CheckerContext &
C,
const CallEvent &
Call)
const;
217 void evalStrlcat(CheckerContext &
C,
const CallEvent &
Call)
const;
219 void evalStrcmp(CheckerContext &
C,
const CallEvent &
Call)
const;
220 void evalStrncmp(CheckerContext &
C,
const CallEvent &
Call)
const;
221 void evalStrcasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
222 void evalStrncasecmp(CheckerContext &
C,
const CallEvent &
Call)
const;
223 void evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
224 bool IsBounded =
false,
bool IgnoreCase =
false)
const;
226 void evalStrsep(CheckerContext &
C,
const CallEvent &
Call)
const;
228 void evalStdCopy(CheckerContext &
C,
const CallEvent &
Call)
const;
229 void evalStdCopyBackward(CheckerContext &
C,
const CallEvent &
Call)
const;
230 void evalStdCopyCommon(CheckerContext &
C,
const CallEvent &
Call)
const;
231 void evalMemset(CheckerContext &
C,
const CallEvent &
Call)
const;
232 void evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const;
234 void evalSprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
235 void evalSnprintf(CheckerContext &
C,
const CallEvent &
Call)
const;
236 void evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
237 bool IsBounded)
const;
240 std::pair<ProgramStateRef , ProgramStateRef >
241 static assumeZero(CheckerContext &
C,
247 static SVal getCStringLengthForRegion(CheckerContext &
C,
252 static const StringLiteral *getStringLiteralFromRegion(
const MemRegion *MR);
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,
438 SVal BufVal =
C.getSVal(Buffer.Expression);
439 const auto *ER = dyn_cast_or_null<ElementRegion>(BufVal.
getAsRegion());
443 const auto *SuperR = ER->getSuperRegion()->getAs<TypedValueRegion>();
449 if (!SuperR->getValueType()->isArrayType())
452 SValBuilder &SVB =
C.getSValBuilder();
457 std::optional<Loc> FirstElementVal =
459 if (!FirstElementVal)
464 State->getSVal(*FirstElementVal).isUndef()) {
465 llvm::SmallString<258> Buf;
466 llvm::raw_svector_ostream
OS(Buf);
467 OS <<
"The first element of the ";
469 OS <<
" argument is undefined";
470 emitUninitializedReadBug(
C, State, Buffer.Expression,
471 FirstElementVal->getAsRegion(),
OS.str());
502 std::optional<NonLoc> Offset =
512 SVal LastIdx = SVB.
evalBinOpNN(State, BO_Sub, *Offset, One, IdxTy);
514 SVal LastElementVal = State->getLValue(ElemTy, LastIdx, BufVal);
519 State->getSVal(LastElementVal.
castAs<Loc>()).isUndef()) {
520 const llvm::APSInt *IdxInt = LastIdx.getAsInteger();
527 llvm::SmallString<258> Buf;
528 llvm::raw_svector_ostream
OS(Buf);
529 OS <<
"The last accessed element (at index ";
530 OS << IdxInt->getExtValue();
533 OS <<
" argument is undefined";
534 emitUninitializedReadBug(
C, State, Buffer.Expression,
546 AnyArgExpr Buffer, SVal Element,
559 const auto *ER = dyn_cast<ElementRegion>(R);
564 std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
570 DefinedOrUnknownSVal
Size =
573 auto [StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
574 if (StOutBound && !StInBound) {
591 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
592 emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
603 AnyArgExpr Buffer, SizeArgExpr Size,
604 AccessKind Access, CharKind CK)
const {
609 SValBuilder &svalBuilder =
C.getSValBuilder();
612 QualType SizeTy =
Size.Expression->getType();
613 QualType PtrTy = getCharPtrType(Ctx, CK);
616 SVal BufVal =
C.getSVal(Buffer.Expression);
617 State = checkNonNull(
C, State, Buffer, BufVal);
625 State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
633 SVal LengthVal =
C.getSVal(
Size.Expression);
634 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
640 SVal Offset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
641 if (Offset.isUnknown())
643 NonLoc LastOffset = Offset.
castAs<NonLoc>();
646 if (std::optional<Loc> BufLoc = BufStart.
getAs<Loc>()) {
649 svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
650 State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
651 if (Access == AccessKind::read)
652 State = checkInit(
C, State, Buffer, BufStart, *Length);
665 SizeArgExpr Size, AnyArgExpr
First,
678 if (!
First.Expression->getType()->isAnyPointerType() ||
683 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
688 const StackFrame *SF =
C.getStackFrame();
689 SVal firstVal = state->getSVal(
First.Expression, SF);
690 SVal secondVal = state->getSVal(Second.Expression, SF);
692 std::optional<Loc> firstLoc = firstVal.
getAs<Loc>();
696 std::optional<Loc> secondLoc = secondVal.
getAs<Loc>();
701 SValBuilder &svalBuilder =
C.getSValBuilder();
702 std::tie(stateTrue, stateFalse) =
703 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
705 if (stateTrue && !stateFalse) {
708 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
733 svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
734 std::optional<DefinedOrUnknownSVal> reverseTest =
735 reverse.
getAs<DefinedOrUnknownSVal>();
739 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
746 std::swap(firstLoc, secondLoc);
749 std::swap(
First, Second);
754 SVal LengthVal = state->getSVal(
Size.Expression, SF);
755 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
762 QualType CharPtrTy = getCharPtrType(Ctx, CK);
764 svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
765 std::optional<Loc> FirstStartLoc = FirstStart.
getAs<Loc>();
770 SVal FirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
772 std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<Loc>();
778 svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
779 std::optional<DefinedOrUnknownSVal> OverlapTest =
780 Overlap.
getAs<DefinedOrUnknownSVal>();
784 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
786 if (stateTrue && !stateFalse) {
788 emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
808void CStringChecker::emitOverlapBug(CheckerContext &
C,
ProgramStateRef state,
810 const Stmt *Second)
const {
812 "Can't emit from a checker that is not enabled!");
813 ExplodedNode *N =
C.generateErrorNode(state);
818 auto report = std::make_unique<PathSensitiveBugReport>(
819 BufferOverlap,
"Arguments must not be overlapping buffers", N);
820 report->addRange(
First->getSourceRange());
823 C.emitReport(std::move(report));
826void CStringChecker::emitNullArgBug(CheckerContext &
C,
ProgramStateRef State,
827 const Stmt *S, StringRef WarningMsg)
const {
829 "Can't emit from a checker that is not enabled!");
830 if (ExplodedNode *N =
C.generateErrorNode(State)) {
832 std::make_unique<PathSensitiveBugReport>(NullArg, WarningMsg, N);
834 if (
const auto *Ex = dyn_cast<Expr>(S))
836 C.emitReport(std::move(
Report));
840void CStringChecker::emitUninitializedReadBug(CheckerContext &
C,
842 const Expr *E,
const MemRegion *R,
843 StringRef Msg)
const {
845 "Can't emit from a checker that is not enabled!");
846 if (ExplodedNode *N =
C.generateErrorNode(State)) {
848 std::make_unique<PathSensitiveBugReport>(UninitializedRead, Msg, N);
849 Report->addNote(
"Other elements might also be undefined",
853 Report->addVisitor<NoStoreFuncVisitor>(
R->castAs<SubRegion>());
854 C.emitReport(std::move(
Report));
858void CStringChecker::emitOutOfBoundsBug(CheckerContext &
C,
860 StringRef WarningMsg)
const {
862 "Can't emit from a checker that is not enabled!");
863 if (ExplodedNode *N =
C.generateErrorNode(State)) {
868 std::make_unique<PathSensitiveBugReport>(OutOfBounds, WarningMsg, N);
870 C.emitReport(std::move(
Report));
874void CStringChecker::emitNotCStringBug(CheckerContext &
C,
ProgramStateRef State,
876 StringRef WarningMsg)
const {
878 "Can't emit from a checker that is not enabled!");
879 if (ExplodedNode *N =
C.generateNonFatalErrorNode(State)) {
881 std::make_unique<PathSensitiveBugReport>(NotNullTerm, WarningMsg, N);
884 C.emitReport(std::move(
Report));
891 NonLoc right)
const {
896 SValBuilder &svalBuilder =
C.getSValBuilder();
900 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
901 NonLoc maxVal = svalBuilder.
makeIntVal(maxValInt);
905 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
910 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
915 if (std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<NonLoc>()) {
918 SVal willOverflow = svalBuilder.
evalBinOpNN(state, BO_GT, left,
919 *maxMinusRightNL, cmpTy);
921 auto [StateOverflow, StateOkay] =
922 state->assume(willOverflow.
castAs<DefinedOrUnknownSVal>());
924 if (StateOverflow && !StateOkay) {
930 C.addSink(StateOverflow);
945 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
950 case MemRegion::StringRegionKind:
955 case MemRegion::SymbolicRegionKind:
956 case MemRegion::AllocaRegionKind:
957 case MemRegion::NonParamVarRegionKind:
958 case MemRegion::ParamVarRegionKind:
959 case MemRegion::FieldRegionKind:
960 case MemRegion::ObjCIvarRegionKind:
964 case MemRegion::ElementRegionKind:
978 return state->remove<CStringLength>(MR);
980 return state->set<CStringLength>(MR, strLength);
983SVal CStringChecker::getCStringLengthForRegion(CheckerContext &
C,
990 const SVal *Recorded = state->get<CStringLength>(MR);
996 SValBuilder &svalBuilder =
C.getSValBuilder();
1000 C.getStackFrame(),
C.blockCount());
1002 if (!hypothetical) {
1003 if (std::optional<NonLoc> strLn = strLength.
getAs<NonLoc>()) {
1006 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1007 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
1008 std::optional<APSIntPtr> maxLengthInt =
1010 NonLoc maxLength = svalBuilder.
makeIntVal(*maxLengthInt);
1011 SVal evalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1013 state = state->assume(evalLength.
castAs<DefinedOrUnknownSVal>(),
true);
1015 state = state->set<CStringLength>(MR, strLength);
1021const StringLiteral *
1022CStringChecker::getStringLiteralFromRegion(
const MemRegion *MR) {
1024 case MemRegion::StringRegionKind:
1026 case MemRegion::NonParamVarRegionKind:
1028 Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage())
1029 return dyn_cast_or_null<StringLiteral>(
Decl->getInit());
1036SVal CStringChecker::getCStringLength(CheckerContext &
C,
ProgramStateRef &state,
1037 const Expr *Ex, SVal Buf,
1038 bool hypothetical)
const {
1044 if (std::optional<loc::GotoLabel> Label = Buf.
getAs<loc::GotoLabel>()) {
1046 SmallString<120> buf;
1047 llvm::raw_svector_ostream os(buf);
1048 assert(CurrentFunctionDescription);
1049 os <<
"Argument to " << CurrentFunctionDescription
1050 <<
" is the address of the label '" << Label->getLabel()->getName()
1051 <<
"', which is not a null-terminated string";
1053 emitNotCStringBug(
C, state, Ex, os.str());
1055 return UndefinedVal();
1059 return UnknownVal();
1066 if (
const StringLiteral *StrLit = getStringLiteralFromRegion(MR)) {
1072 SValBuilder &SVB =
C.getSValBuilder();
1077 case MemRegion::StringRegionKind:
1078 case MemRegion::NonParamVarRegionKind:
1079 case MemRegion::SymbolicRegionKind:
1080 case MemRegion::AllocaRegionKind:
1081 case MemRegion::ParamVarRegionKind:
1082 case MemRegion::FieldRegionKind:
1083 case MemRegion::ObjCIvarRegionKind:
1084 return getCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1085 case MemRegion::CompoundLiteralRegionKind:
1087 return UnknownVal();
1088 case MemRegion::ElementRegionKind: {
1093 const SubRegion *SuperReg =
1095 const StringLiteral *StrLit = getStringLiteralFromRegion(SuperReg);
1097 return UnknownVal();
1098 SValBuilder &SVB =
C.getSValBuilder();
1103 if (state->assume(SVB.
evalBinOpNN(state, BO_LE, Idx, LengthVal,
1105 .
castAs<DefinedOrUnknownSVal>(),
1107 return SVB.
evalBinOp(state, BO_Sub, LengthVal, Idx, SizeTy);
1108 return UnknownVal();
1115 SmallString<120> buf;
1116 llvm::raw_svector_ostream os(buf);
1118 assert(CurrentFunctionDescription);
1119 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
1121 if (SummarizeRegion(os,
C.getASTContext(), MR))
1122 os <<
", which is not a null-terminated string";
1124 os <<
"not a null-terminated string";
1126 emitNotCStringBug(
C, state, Ex, os.str());
1128 return UndefinedVal();
1132const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &
C,
1145 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
1153bool CStringChecker::isFirstBufInBound(CheckerContext &
C,
ProgramStateRef State,
1154 SVal BufVal, QualType BufTy,
1155 SVal LengthVal, QualType LengthTy) {
1164 SValBuilder &SB =
C.getSValBuilder();
1165 ASTContext &Ctx =
C.getASTContext();
1169 std::optional<NonLoc> Length = LengthVal.
getAs<NonLoc>();
1175 SVal Offset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1176 if (Offset.isUnknown())
1178 NonLoc LastOffset = Offset.
castAs<NonLoc>();
1181 SVal BufStart = SB.
evalCast(BufVal, PtrTy, BufTy);
1182 std::optional<Loc> BufLoc = BufStart.
getAs<Loc>();
1186 SVal BufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1193 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
1199 C.getASTContext().CharTy &&
1200 "isFirstBufInBound should only be called with char* ElementRegions");
1207 DefinedOrUnknownSVal Idx = ER->
getIndex().
castAs<DefinedOrUnknownSVal>();
1211 return static_cast<bool>(StInBound);
1217 auto InvalidationTraitOperations =
1218 [&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1219 SizeTy](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1222 if (MemRegion::FieldRegionKind ==
R->getKind() &&
1223 isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1231 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1235CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1237 auto InvalidationTraitOperations = [](RegionAndSymbolInvalidationTraits &,
1238 const MemRegion *
R) {
1242 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1245ProgramStateRef CStringChecker::invalidateDestinationBufferNeverOverflows(
1247 auto InvalidationTraitOperations =
1248 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1249 if (MemRegion::FieldRegionKind ==
R->getKind())
1256 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1263 auto InvalidationTraitOperations =
1264 [](RegionAndSymbolInvalidationTraits &ITraits,
const MemRegion *
R) {
1273 return invalidateBufferAux(
C, S, Elem, BufV, InvalidationTraitOperations);
1278 llvm::function_ref<
bool(RegionAndSymbolInvalidationTraits &,
1280 InvalidationTraitOperations) {
1281 std::optional<Loc> L =
V.getAs<Loc>();
1288 if (std::optional<loc::MemRegionVal> MR = L->getAs<loc::MemRegionVal>()) {
1289 const MemRegion *
R = MR->getRegion()->
StripCasts();
1293 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
1299 const StackFrame *SF =
C.getPredecessor()->getStackFrame();
1300 RegionAndSymbolInvalidationTraits ITraits;
1301 bool CausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1303 return State->invalidateRegions(R, Elem,
C.blockCount(), SF,
1304 CausesPointerEscape,
nullptr,
nullptr,
1311 return State->killBinding(*L);
1314bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx,
1315 const MemRegion *MR) {
1317 case MemRegion::FunctionCodeRegionKind: {
1319 os <<
"the address of the function '" << *FD <<
'\'';
1321 os <<
"the address of a function";
1324 case MemRegion::BlockCodeRegionKind:
1327 case MemRegion::BlockDataRegionKind:
1330 case MemRegion::CXXThisRegionKind:
1331 case MemRegion::CXXTempObjectRegionKind:
1332 os <<
"a C++ temp object of type "
1335 case MemRegion::NonParamVarRegionKind:
1338 case MemRegion::ParamVarRegionKind:
1341 case MemRegion::FieldRegionKind:
1344 case MemRegion::ObjCIvarRegionKind:
1345 os <<
"an instance variable of type "
1354 SVal CharVal,
const Expr *Size,
1356 SVal MemVal =
C.getSVal(DstBuffer);
1357 SVal SizeVal =
C.getSVal(Size);
1367 const MemRegion *BR = Offset.
getRegion();
1369 std::optional<NonLoc> SizeNL = SizeVal.
getAs<NonLoc>();
1373 SValBuilder &svalBuilder =
C.getSValBuilder();
1374 ASTContext &Ctx =
C.getASTContext();
1384 std::tie(StateWholeReg, StateNotWholeReg) =
1385 State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1392 std::tie(StateNullChar, StateNonNullChar) =
1395 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1396 !StateNonNullChar) {
1404 State->bindDefaultZero(svalBuilder.
makeLoc(BR),
C.getStackFrame());
1408 State = invalidateDestinationBufferBySize(
1409 C, State, DstBuffer, Elem, MemVal, SizeVal,
Size->getType());
1412 if (StateNullChar && !StateNonNullChar) {
1415 State = setCStringLength(State, MR,
1417 }
else if (!StateNullChar && StateNonNullChar) {
1419 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1420 C.getStackFrame(),
C.blockCount());
1424 SVal NewStrLenGESize = svalBuilder.
evalBinOp(
1427 State = setCStringLength(
1428 State->assume(NewStrLenGESize.
castAs<DefinedOrUnknownSVal>(),
true),
1434 State = invalidateDestinationBufferBySize(
C, State, DstBuffer, Elem, MemVal,
1435 SizeVal,
Size->getType());
1444void CStringChecker::evalCopyCommon(CheckerContext &
C,
const CallEvent &
Call,
1446 DestinationArgExpr Dest,
1447 SourceArgExpr Source,
bool Restricted,
1448 bool IsMempcpy, CharKind CK)
const {
1449 CurrentFunctionDescription =
"memory copy function";
1452 const StackFrame *SF =
C.getStackFrame();
1453 SVal sizeVal = state->getSVal(
Size.Expression, SF);
1454 QualType sizeTy =
Size.Expression->getType();
1457 std::tie(stateZeroSize, stateNonZeroSize) =
1458 assumeZero(
C, state, sizeVal, sizeTy);
1461 SVal destVal = state->getSVal(Dest.Expression, SF);
1465 if (stateZeroSize && !stateNonZeroSize) {
1466 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), SF, destVal);
1467 C.addTransition(stateZeroSize);
1472 if (stateNonZeroSize) {
1476 state = stateNonZeroSize;
1480 state = checkNonNull(
C, state, Dest, destVal);
1485 SVal srcVal = state->getSVal(Source.Expression, SF);
1489 state = checkNonNull(
C, state, Source, srcVal);
1494 state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1495 state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1498 state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1507 SValBuilder &SvalBuilder =
C.getSValBuilder();
1509 QualType CharPtrTy = getCharPtrType(Ctx, CK);
1510 SVal DestRegCharVal =
1511 SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1512 SVal lastElement =
C.getSValBuilder().evalBinOp(
1513 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1517 lastElement =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1520 state = state->BindExpr(
Call.getOriginExpr(), SF, lastElement);
1524 state = state->BindExpr(
Call.getOriginExpr(), SF, destVal);
1533 state = invalidateDestinationBufferBySize(
1534 C, state, Dest.Expression,
Call.getCFGElementRef(),
1535 C.getSVal(Dest.Expression), sizeVal,
Size.Expression->getType());
1539 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(),
1540 C.getSVal(Source.Expression));
1542 C.addTransition(state);
1546void CStringChecker::evalMemcpy(CheckerContext &
C,
const CallEvent &
Call,
1547 CharKind CK)
const {
1550 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1551 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1552 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1556 constexpr bool IsRestricted =
true;
1557 constexpr bool IsMempcpy =
false;
1558 evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1561void CStringChecker::evalMempcpy(CheckerContext &
C,
const CallEvent &
Call,
1562 CharKind CK)
const {
1565 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1566 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1567 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1569 constexpr bool IsRestricted =
true;
1570 constexpr bool IsMempcpy =
true;
1571 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1575void CStringChecker::evalMemmove(CheckerContext &
C,
const CallEvent &
Call,
1576 CharKind CK)
const {
1579 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1580 SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1581 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1583 constexpr bool IsRestricted =
false;
1584 constexpr bool IsMempcpy =
false;
1585 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1589void CStringChecker::evalBcopy(CheckerContext &
C,
const CallEvent &
Call)
const {
1591 SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1592 DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1593 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1595 constexpr bool IsRestricted =
false;
1596 constexpr bool IsMempcpy =
false;
1597 evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1598 IsMempcpy, CharKind::Regular);
1601void CStringChecker::evalMemcmp(CheckerContext &
C,
const CallEvent &
Call,
1602 CharKind CK)
const {
1604 CurrentFunctionDescription =
"memory comparison function";
1606 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
1607 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
1608 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
1611 SValBuilder &Builder =
C.getSValBuilder();
1612 const StackFrame *SF =
C.getStackFrame();
1615 SVal sizeVal = State->getSVal(
Size.Expression, SF);
1616 QualType sizeTy =
Size.Expression->getType();
1619 std::tie(stateZeroSize, stateNonZeroSize) =
1620 assumeZero(
C, State, sizeVal, sizeTy);
1624 if (stateZeroSize) {
1625 State = stateZeroSize;
1626 State = State->BindExpr(
Call.getOriginExpr(), SF,
1627 Builder.makeZeroVal(
Call.getResultType()));
1628 C.addTransition(State);
1632 if (stateNonZeroSize) {
1633 State = stateNonZeroSize;
1637 DefinedOrUnknownSVal LV =
1638 State->getSVal(
Left.Expression, SF).castAs<DefinedOrUnknownSVal>();
1639 DefinedOrUnknownSVal RV =
1640 State->getSVal(
Right.Expression, SF).castAs<DefinedOrUnknownSVal>();
1644 std::tie(SameBuffer, NotSameBuffer) =
1645 State->assume(Builder.evalEQ(State, LV, RV));
1649 if (SameBuffer && !NotSameBuffer) {
1651 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1653 State = SameBuffer->BindExpr(
Call.getOriginExpr(), SF,
1654 Builder.makeZeroVal(
Call.getResultType()));
1655 C.addTransition(State);
1662 assert(NotSameBuffer);
1663 State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1664 State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1667 SVal CmpV = Builder.conjureSymbolVal(
Call,
C.blockCount());
1668 State = State->BindExpr(
Call.getOriginExpr(), SF, CmpV);
1669 C.addTransition(State);
1674void CStringChecker::evalstrLength(CheckerContext &
C,
1675 const CallEvent &
Call)
const {
1677 evalstrLengthCommon(
C,
Call,
false);
1680void CStringChecker::evalstrnLength(CheckerContext &
C,
1681 const CallEvent &
Call)
const {
1683 evalstrLengthCommon(
C,
Call,
true);
1686void CStringChecker::evalstrLengthCommon(CheckerContext &
C,
1687 const CallEvent &
Call,
1688 bool IsStrnlen)
const {
1689 CurrentFunctionDescription =
"string length function";
1691 const StackFrame *SF =
C.getStackFrame();
1694 const Expr *maxlenExpr =
Call.getArgExpr(1);
1695 SVal maxlenVal = state->getSVal(maxlenExpr, SF);
1698 std::tie(stateZeroSize, stateNonZeroSize) =
1699 assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1703 if (stateZeroSize) {
1704 SVal zero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1705 stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), SF, zero);
1706 C.addTransition(stateZeroSize);
1710 if (!stateNonZeroSize)
1714 state = stateNonZeroSize;
1718 AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1719 SVal ArgVal = state->getSVal(Arg.Expression, SF);
1720 state = checkNonNull(
C, state, Arg, ArgVal);
1725 SVal strLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1732 DefinedOrUnknownSVal result = UnknownVal();
1737 QualType cmpTy =
C.getSValBuilder().getConditionType();
1741 const Expr *maxlenExpr =
Call.getArgExpr(1);
1742 SVal maxlenVal = state->getSVal(maxlenExpr, SF);
1744 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1745 std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<NonLoc>();
1747 if (strLengthNL && maxlenValNL) {
1751 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1753 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1754 .castAs<DefinedOrUnknownSVal>());
1756 if (stateStringTooLong && !stateStringNotTooLong) {
1758 result = *maxlenValNL;
1759 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1761 result = *strLengthNL;
1770 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1771 NonLoc resultNL = result.
castAs<NonLoc>();
1774 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1775 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1776 .castAs<DefinedOrUnknownSVal>(),
true);
1780 state = state->assume(
C.getSValBuilder().evalBinOpNN(
1781 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1782 .castAs<DefinedOrUnknownSVal>(),
true);
1788 result = strLength.
castAs<DefinedOrUnknownSVal>();
1793 result =
C.getSValBuilder().conjureSymbolVal(
Call,
C.blockCount());
1798 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1799 state = state->BindExpr(
Call.getOriginExpr(), SF, result);
1800 C.addTransition(state);
1803void CStringChecker::evalStrcpy(CheckerContext &
C,
1804 const CallEvent &
Call)
const {
1806 evalStrcpyCommon(
C,
Call,
1809 ConcatFnKind::none);
1812void CStringChecker::evalStrncpy(CheckerContext &
C,
1813 const CallEvent &
Call)
const {
1815 evalStrcpyCommon(
C,
Call,
1818 ConcatFnKind::none);
1821void CStringChecker::evalStpcpy(CheckerContext &
C,
1822 const CallEvent &
Call)
const {
1824 evalStrcpyCommon(
C,
Call,
1827 ConcatFnKind::none);
1830void CStringChecker::evalStrlcpy(CheckerContext &
C,
1831 const CallEvent &
Call)
const {
1833 evalStrcpyCommon(
C,
Call,
1840void CStringChecker::evalStrcat(CheckerContext &
C,
1841 const CallEvent &
Call)
const {
1843 evalStrcpyCommon(
C,
Call,
1846 ConcatFnKind::strcat);
1849void CStringChecker::evalStrncat(CheckerContext &
C,
1850 const CallEvent &
Call)
const {
1852 evalStrcpyCommon(
C,
Call,
1855 ConcatFnKind::strcat);
1858void CStringChecker::evalStrlcat(CheckerContext &
C,
1859 const CallEvent &
Call)
const {
1863 evalStrcpyCommon(
C,
Call,
1866 ConcatFnKind::strlcat,
1870void CStringChecker::evalStrcpyCommon(CheckerContext &
C,
const CallEvent &
Call,
1871 bool ReturnEnd,
bool IsBounded,
1872 ConcatFnKind appendK,
1873 bool returnPtr)
const {
1874 if (appendK == ConcatFnKind::none)
1875 CurrentFunctionDescription =
"string copy function";
1877 CurrentFunctionDescription =
"string concatenation function";
1880 const StackFrame *SF =
C.getStackFrame();
1883 DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1884 SVal DstVal = state->getSVal(Dst.Expression, SF);
1885 state = checkNonNull(
C, state, Dst, DstVal);
1890 SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1891 SVal srcVal = state->getSVal(srcExpr.Expression, SF);
1892 state = checkNonNull(
C, state, srcExpr, srcVal);
1897 SVal strLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1898 std::optional<NonLoc> strLengthNL = strLength.
getAs<NonLoc>();
1901 SVal dstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1902 std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>();
1908 SValBuilder &svalBuilder =
C.getSValBuilder();
1915 SVal amountCopied = UnknownVal();
1916 SVal maxLastElementIndex = UnknownVal();
1917 const char *boundWarning =
nullptr;
1921 SizeArgExpr SrcExprAsSizeDummy = {
1922 {srcExpr.Expression, srcExpr.ArgumentIndex}};
1923 state = CheckOverlap(
1925 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1934 SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1935 SVal lenVal = state->getSVal(lenExpr.Expression, SF);
1939 svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1941 std::optional<NonLoc> lenValNL = lenVal.
getAs<NonLoc>();
1945 if (strLengthNL && lenValNL) {
1947 case ConcatFnKind::none:
1948 case ConcatFnKind::strcat: {
1953 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1955 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1956 .castAs<DefinedOrUnknownSVal>());
1958 if (stateSourceTooLong && !stateSourceNotTooLong) {
1961 state = stateSourceTooLong;
1962 amountCopied = lenVal;
1964 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1966 state = stateSourceNotTooLong;
1967 amountCopied = strLength;
1971 case ConcatFnKind::strlcat:
1972 if (!dstStrLengthNL)
1976 SVal freeSpace = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
1977 *dstStrLengthNL, sizeTy);
1981 svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1983 std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<NonLoc>();
1990 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1993 std::tie(TrueState, FalseState) =
1994 state->assume(hasEnoughSpace.
castAs<DefinedOrUnknownSVal>());
1997 if (TrueState && !FalseState) {
1998 amountCopied = strLength;
2002 if (!TrueState && FalseState) {
2003 amountCopied = freeSpace;
2006 if (TrueState && FalseState)
2007 amountCopied = UnknownVal();
2014 case ConcatFnKind::strcat:
2020 if (dstStrLength.isUndef())
2023 if (dstStrLengthNL) {
2025 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2027 boundWarning =
"Size argument is greater than the free space in the "
2028 "destination buffer";
2031 case ConcatFnKind::none:
2032 case ConcatFnKind::strlcat:
2042 std::tie(StateZeroSize, StateNonZeroSize) =
2043 assumeZero(
C, state, *lenValNL, sizeTy);
2046 if (StateZeroSize && !StateNonZeroSize) {
2049 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, DstVal);
2051 if (appendK == ConcatFnKind::none) {
2054 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, strLength);
2058 state, BO_Add, strLength, dstStrLength, sizeTy);
2060 StateZeroSize->BindExpr(
Call.getOriginExpr(), SF, retSize);
2063 C.addTransition(StateZeroSize);
2071 maxLastElementIndex =
2072 svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2073 boundWarning =
"Size argument is greater than the length of the "
2074 "destination buffer";
2081 amountCopied = strLength;
2089 SVal finalStrLength = UnknownVal();
2090 SVal strlRetVal = UnknownVal();
2092 if (appendK == ConcatFnKind::none && !returnPtr) {
2094 strlRetVal = strLength;
2100 if (appendK != ConcatFnKind::none) {
2103 if (dstStrLength.isUndef())
2106 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2107 strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2108 *dstStrLengthNL, sizeTy);
2111 std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<NonLoc>();
2114 if (amountCopiedNL && dstStrLengthNL) {
2116 state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2120 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2121 *dstStrLengthNL, sizeTy);
2130 getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2131 assert(!finalStrLength.
isUndef());
2133 if (std::optional<NonLoc> finalStrLengthNL =
2134 finalStrLength.
getAs<NonLoc>()) {
2135 if (amountCopiedNL && appendK == ConcatFnKind::none) {
2139 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2140 state = state->assume(sourceInResult.
castAs<DefinedOrUnknownSVal>(),
2146 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
2149 SVal destInResult = svalBuilder.
evalBinOpNN(state, BO_GE,
2154 state->assume(destInResult.
castAs<DefinedOrUnknownSVal>(),
true);
2164 finalStrLength = amountCopied;
2172 Result = (ReturnEnd ? UnknownVal() : DstVal);
2174 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2185 if (std::optional<loc::MemRegionVal> dstRegVal =
2186 DstVal.
getAs<loc::MemRegionVal>()) {
2187 QualType ptrTy = Dst.Expression->getType();
2191 if (std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<NonLoc>()) {
2192 SVal maxLastElement =
2193 svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2196 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2200 state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2206 if (std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<NonLoc>()) {
2207 SVal lastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2208 *knownStrLength, ptrTy);
2211 if (!boundWarning) {
2213 state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2217 state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2223 if (returnPtr && ReturnEnd)
2236 bool CouldAccessOutOfBound =
true;
2237 if (IsBounded && amountCopied.
isUnknown()) {
2238 auto CouldAccessOutOfBoundForSVal =
2239 [&](std::optional<NonLoc> Val) ->
bool {
2242 return !isFirstBufInBound(
C, state,
C.getSVal(Dst.Expression),
2243 Dst.Expression->getType(), *Val,
2244 C.getASTContext().getSizeType());
2247 CouldAccessOutOfBound = CouldAccessOutOfBoundForSVal(strLengthNL);
2249 if (CouldAccessOutOfBound) {
2251 const Expr *LenExpr =
Call.getArgExpr(2);
2252 SVal LenVal = state->getSVal(LenExpr, SF);
2260 CouldAccessOutOfBound =
2261 CouldAccessOutOfBoundForSVal(LenVal.
getAs<NonLoc>());
2272 if (CouldAccessOutOfBound)
2273 state = invalidateDestinationBufferBySize(
2274 C, state, Dst.Expression,
Call.getCFGElementRef(), *dstRegVal,
2275 amountCopied,
C.getASTContext().getSizeType());
2277 state = invalidateDestinationBufferNeverOverflows(
2278 C, state,
Call.getCFGElementRef(), *dstRegVal);
2282 state = invalidateSourceBuffer(
C, state,
Call.getCFGElementRef(), srcVal);
2285 if (IsBounded && (appendK == ConcatFnKind::none)) {
2290 if (amountCopied != strLength)
2291 finalStrLength = UnknownVal();
2293 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2301 if (ReturnEnd &&
Result.isUnknown()) {
2306 state = state->BindExpr(
Call.getOriginExpr(), SF,
Result);
2307 C.addTransition(state);
2310void CStringChecker::evalStrxfrm(CheckerContext &
C,
2311 const CallEvent &
Call)
const {
2313 CurrentFunctionDescription =
"locale transformation function";
2316 const StackFrame *SF =
C.getStackFrame();
2317 SValBuilder &SVB =
C.getSValBuilder();
2320 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2321 SourceArgExpr Source = {{
Call.getArgExpr(1), 1}};
2322 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2325 SVal SrcVal = State->getSVal(Source.Expression, SF);
2326 State = checkNonNull(
C, State, Source, SrcVal);
2331 State = CheckOverlap(
C, State, Size, Dest, Source, CK_Regular);
2339 auto BindReturnAndTransition = [&RetVal, &
Call, SF,
2342 State = State->BindExpr(
Call.getOriginExpr(), SF, RetVal);
2343 C.addTransition(State);
2348 SVal SizeVal = State->getSVal(
Size.Expression, SF);
2349 QualType SizeTy =
Size.Expression->getType();
2351 auto [StateZeroSize, StateSizeNonZero] =
2352 assumeZero(
C, State, SizeVal, SizeTy);
2355 if (!StateZeroSize && !StateSizeNonZero)
2356 return BindReturnAndTransition(State);
2359 if (StateZeroSize && !StateSizeNonZero)
2360 return BindReturnAndTransition(StateZeroSize);
2363 SVal DestVal = StateSizeNonZero->getSVal(Dest.Expression, SF);
2364 StateSizeNonZero = checkNonNull(
C, StateSizeNonZero, Dest, DestVal);
2365 if (!StateSizeNonZero)
2369 StateSizeNonZero = CheckBufferAccess(
C, StateSizeNonZero, Dest, Size,
2370 AccessKind::write, CK_Regular);
2371 if (!StateSizeNonZero)
2376 auto ComparisonVal = SVB.
evalBinOp(StateSizeNonZero, BO_LT, RetVal, SizeVal,
2378 .
getAs<DefinedOrUnknownSVal>();
2379 if (!ComparisonVal) {
2381 StateSizeNonZero = invalidateDestinationBufferBySize(
2382 C, StateSizeNonZero, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2383 SizeVal,
Size.Expression->getType());
2384 return BindReturnAndTransition(StateSizeNonZero);
2387 auto [StateSuccess, StateFailure] = StateSizeNonZero->assume(*ComparisonVal);
2391 StateSuccess = invalidateDestinationBufferBySize(
2392 C, StateSuccess, Dest.Expression,
Call.getCFGElementRef(), DestVal,
2393 SizeVal,
Size.Expression->getType());
2394 BindReturnAndTransition(StateSuccess);
2400 if (
auto DestLoc = DestVal.
getAs<loc::MemRegionVal>()) {
2401 StateFailure = StateFailure->killBinding(*DestLoc);
2403 StateFailure->bindDefaultInitial(*DestLoc, UndefinedVal{}, SF);
2406 BindReturnAndTransition(StateFailure);
2410void CStringChecker::evalStrcmp(CheckerContext &
C,
2411 const CallEvent &
Call)
const {
2413 evalStrcmpCommon(
C,
Call,
false,
false);
2416void CStringChecker::evalStrncmp(CheckerContext &
C,
2417 const CallEvent &
Call)
const {
2419 evalStrcmpCommon(
C,
Call,
true,
false);
2422void CStringChecker::evalStrcasecmp(CheckerContext &
C,
2423 const CallEvent &
Call)
const {
2425 evalStrcmpCommon(
C,
Call,
false,
true);
2428void CStringChecker::evalStrncasecmp(CheckerContext &
C,
2429 const CallEvent &
Call)
const {
2431 evalStrcmpCommon(
C,
Call,
true,
true);
2434void CStringChecker::evalStrcmpCommon(CheckerContext &
C,
const CallEvent &
Call,
2435 bool IsBounded,
bool IgnoreCase)
const {
2436 CurrentFunctionDescription =
"string comparison function";
2438 const StackFrame *SF =
C.getStackFrame();
2441 AnyArgExpr
Left = {
Call.getArgExpr(0), 0};
2442 SVal LeftVal = state->getSVal(
Left.Expression, SF);
2443 state = checkNonNull(
C, state, Left, LeftVal);
2448 AnyArgExpr
Right = {
Call.getArgExpr(1), 1};
2449 SVal RightVal = state->getSVal(
Right.Expression, SF);
2450 state = checkNonNull(
C, state, Right, RightVal);
2455 SVal LeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2460 SVal RightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2467 DefinedOrUnknownSVal LV = LeftVal.
castAs<DefinedOrUnknownSVal>();
2468 DefinedOrUnknownSVal RV = RightVal.
castAs<DefinedOrUnknownSVal>();
2471 SValBuilder &svalBuilder =
C.getSValBuilder();
2472 DefinedOrUnknownSVal SameBuf = svalBuilder.
evalEQ(state, LV, RV);
2474 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2480 StSameBuf->BindExpr(
Call.getOriginExpr(), SF,
2481 svalBuilder.makeZeroVal(
Call.getResultType()));
2482 C.addTransition(StSameBuf);
2489 assert(StNotSameBuf);
2490 state = StNotSameBuf;
2496 const StringLiteral *LeftStrLiteral =
2497 getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2498 const StringLiteral *RightStrLiteral =
2499 getCStringLiteral(
C, state,
Right.Expression, RightVal);
2500 bool canComputeResult =
false;
2501 SVal resultVal = svalBuilder.conjureSymbolVal(
Call,
C.blockCount());
2503 if (LeftStrLiteral && RightStrLiteral) {
2504 StringRef LeftStrRef = LeftStrLiteral->
getString();
2505 StringRef RightStrRef = RightStrLiteral->
getString();
2509 const Expr *lenExpr =
Call.getArgExpr(2);
2510 SVal lenVal = state->getSVal(lenExpr, SF);
2513 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2515 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2516 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2517 canComputeResult =
true;
2521 canComputeResult =
true;
2524 if (canComputeResult) {
2526 size_t s1Term = LeftStrRef.find(
'\0');
2527 if (s1Term != StringRef::npos)
2528 LeftStrRef = LeftStrRef.substr(0, s1Term);
2530 size_t s2Term = RightStrRef.find(
'\0');
2531 if (s2Term != StringRef::npos)
2532 RightStrRef = RightStrRef.substr(0, s2Term);
2535 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2536 : LeftStrRef.compare(RightStrRef);
2540 if (compareRes == 0) {
2541 resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2544 DefinedSVal zeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2548 SVal compareWithZero =
2549 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2550 svalBuilder.getConditionType());
2551 DefinedSVal compareWithZeroVal = compareWithZero.
castAs<DefinedSVal>();
2552 state = state->assume(compareWithZeroVal,
true);
2557 state = state->BindExpr(
Call.getOriginExpr(), SF, resultVal);
2560 C.addTransition(state);
2563void CStringChecker::evalStrsep(CheckerContext &
C,
2564 const CallEvent &
Call)
const {
2567 SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2569 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2570 if (CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2574 CurrentFunctionDescription =
"strsep()";
2576 const StackFrame *SF =
C.getStackFrame();
2580 SVal SearchStrVal = State->getSVal(SearchStrPtr.Expression, SF);
2581 State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2586 AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2587 SVal DelimStrVal = State->getSVal(DelimStr.Expression, SF);
2588 State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2592 SValBuilder &SVB =
C.getSValBuilder();
2594 if (std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<Loc>()) {
2596 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2601 State = invalidateDestinationBufferNeverOverflows(
2606 State = State->bindLoc(*SearchStrLoc,
2616 State = State->BindExpr(
Call.getOriginExpr(), SF,
Result);
2617 C.addTransition(State);
2621void CStringChecker::evalStdCopy(CheckerContext &
C,
2622 const CallEvent &
Call)
const {
2623 evalStdCopyCommon(
C,
Call);
2626void CStringChecker::evalStdCopyBackward(CheckerContext &
C,
2627 const CallEvent &
Call)
const {
2628 evalStdCopyCommon(
C,
Call);
2631void CStringChecker::evalStdCopyCommon(CheckerContext &
C,
2632 const CallEvent &
Call)
const {
2633 if (!
Call.getArgExpr(2)->getType()->isPointerType())
2638 const StackFrame *SF =
C.getStackFrame();
2646 const Expr *Dst =
Call.getArgExpr(2);
2647 SVal DstVal = State->getSVal(Dst, SF);
2650 State = invalidateDestinationBufferAlwaysEscapeSuperRegion(
2651 C, State,
Call.getCFGElementRef(), DstVal);
2653 SValBuilder &SVB =
C.getSValBuilder();
2656 State = State->BindExpr(
Call.getOriginExpr(), SF, ResultVal);
2658 C.addTransition(State);
2661void CStringChecker::evalMemset(CheckerContext &
C,
2662 const CallEvent &
Call)
const {
2664 CurrentFunctionDescription =
"memory set function";
2666 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2667 AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2668 SizeArgExpr
Size = {{
Call.getArgExpr(2), 2}};
2673 const StackFrame *SF =
C.getStackFrame();
2674 SVal SizeVal =
C.getSVal(
Size.Expression);
2675 QualType SizeTy =
Size.Expression->getType();
2678 std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2681 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2685 if (ZeroSize && !NonZeroSize) {
2686 ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), SF, BufferPtrVal);
2687 C.addTransition(ZeroSize);
2693 State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2697 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2704 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
2705 C.getSVal(CharE.Expression),
Size.Expression,
C, State))
2708 State = State->BindExpr(
Call.getOriginExpr(), SF, BufferPtrVal);
2709 C.addTransition(State);
2712void CStringChecker::evalBzero(CheckerContext &
C,
const CallEvent &
Call)
const {
2713 CurrentFunctionDescription =
"memory clearance function";
2715 DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2716 SizeArgExpr
Size = {{
Call.getArgExpr(1), 1}};
2717 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2722 SVal SizeVal =
C.getSVal(
Size.Expression);
2723 QualType SizeTy =
Size.Expression->getType();
2726 std::tie(StateZeroSize, StateNonZeroSize) =
2727 assumeZero(
C, State, SizeVal, SizeTy);
2731 if (StateZeroSize && !StateNonZeroSize) {
2732 C.addTransition(StateZeroSize);
2737 SVal MemVal =
C.getSVal(Buffer.Expression);
2741 State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2745 State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2749 if (!memsetAux(Buffer.Expression,
Call.getCFGElementRef(),
Zero,
2750 Size.Expression,
C, State))
2753 C.addTransition(State);
2756void CStringChecker::evalSprintf(CheckerContext &
C,
2757 const CallEvent &
Call)
const {
2758 CurrentFunctionDescription =
"'sprintf'";
2759 evalSprintfCommon(
C,
Call,
false);
2762void CStringChecker::evalSnprintf(CheckerContext &
C,
2763 const CallEvent &
Call)
const {
2764 CurrentFunctionDescription =
"'snprintf'";
2765 evalSprintfCommon(
C,
Call,
true);
2768void CStringChecker::evalSprintfCommon(CheckerContext &
C,
const CallEvent &
Call,
2769 bool IsBounded)
const {
2772 DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2774 const auto NumParams =
Call.parameters().size();
2775 if (CE->getNumArgs() < NumParams) {
2780 const auto AllArguments =
2781 llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2782 const auto VariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2784 for (
const auto &[ArgIdx, ArgExpr] : VariadicArguments) {
2786 if (
const QualType
type = ArgExpr->getType();
2787 !
type->isAnyPointerType() ||
2788 !
type->getPointeeType()->isAnyCharacterType())
2790 SourceArgExpr Source = {{ArgExpr, unsigned(ArgIdx)}};
2793 SizeArgExpr SrcExprAsSizeDummy = {
2794 {Source.Expression, Source.ArgumentIndex}};
2795 State = CheckOverlap(
2797 (IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2803 C.addTransition(State);
2810CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &
Call,
2811 CheckerContext &
C)
const {
2812 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2816 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(
Call.getDecl());
2821 return &CStringChecker::evalStdCopy;
2823 return &CStringChecker::evalStdCopyBackward;
2829 for (
auto I : CE->arguments()) {
2830 QualType T = I->getType();
2835 const FnCheck *Callback = Callbacks.lookup(
Call);
2842bool CStringChecker::evalCall(
const CallEvent &
Call, CheckerContext &
C)
const {
2843 FnCheck Callback = identifyCall(
Call,
C);
2851 Callback(
this,
C,
Call);
2859 return C.isDifferent();
2862void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &
C)
const {
2866 for (
const auto *I : DS->
decls()) {
2867 const VarDecl *D = dyn_cast<VarDecl>(I);
2881 Loc VarLoc = state->getLValue(D,
C.getStackFrame());
2886 SVal StrVal =
C.getSVal(
Init);
2887 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2888 DefinedOrUnknownSVal strLength =
2889 getCStringLength(
C, state,
Init, StrVal).
castAs<DefinedOrUnknownSVal>();
2891 state = state->set<CStringLength>(MR, strLength);
2894 C.addTransition(state);
2899 ArrayRef<const MemRegion *> ExplicitRegions,
2900 ArrayRef<const MemRegion *> Regions,
const StackFrame *SF,
2901 const CallEvent *
Call)
const {
2902 CStringLengthTy Entries = state->get<CStringLength>();
2903 if (Entries.isEmpty())
2906 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2907 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2910 for (
const MemRegion *MR : Regions) {
2911 Invalidated.insert(MR);
2913 SuperRegions.insert(MR);
2914 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2915 MR = SR->getSuperRegion();
2916 SuperRegions.insert(MR);
2920 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2923 for (
const MemRegion *MR : llvm::make_first_range(Entries)) {
2925 if (SuperRegions.count(MR)) {
2926 Entries = F.remove(Entries, MR);
2931 const MemRegion *Super = MR;
2932 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2933 Super = SR->getSuperRegion();
2934 if (Invalidated.count(Super)) {
2935 Entries = F.remove(Entries, MR);
2941 return state->set<CStringLength>(Entries);
2945 SymbolReaper &SR)
const {
2947 CStringLengthTy Entries = state->get<CStringLength>();
2949 for (SVal Len : llvm::make_second_range(Entries)) {
2955void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2956 CheckerContext &
C)
const {
2958 CStringLengthTy Entries = state->get<CStringLength>();
2959 if (Entries.isEmpty())
2962 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2963 for (
auto [Reg, Len] : Entries) {
2964 if (
SymbolRef Sym = Len.getAsSymbol()) {
2966 Entries = F.remove(Entries, Reg);
2970 state = state->set<CStringLength>(Entries);
2971 C.addTransition(state);
2974void ento::registerCStringModeling(CheckerManager &Mgr) {
2981bool ento::shouldRegisterCStringModeling(
const CheckerManager &) {
2985#define REGISTER_CHECKER(NAME) \
2986 void ento::registerCString##NAME(CheckerManager &Mgr) { \
2987 Mgr.getChecker<CStringChecker>()->NAME.enable(Mgr); \
2990 bool ento::shouldRegisterCString##NAME(const CheckerManager &) { \
3000#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...
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)
NonLoc makeZeroArrayIndex()
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
DefinedSVal getMetadataSymbolVal(const void *symbolTag, const MemRegion *region, const Expr *expr, QualType type, const StackFrame *SF, unsigned count)
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, ConstCFGElementRef elem, const StackFrame *SF, unsigned count)
Create a new symbol with a unique 'name'.
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