;
40using namespacestd::placeholders;
45 unsignedArgumentIndex;
47structSourceArgExpr : AnyArgExpr {};
48structDestinationArgExpr : AnyArgExpr {};
49structSizeArgExpr : AnyArgExpr {};
52enum classAccessKind { write, read };
54staticErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
57llvm::raw_svector_ostream Os(Message);
61<< &FunctionDescription.data()[1];
63 if(Access == AccessKind::write) {
64Os <<
" overflows the destination buffer";
66Os <<
" accesses out-of-bound array element";
72enum classConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
74enum classCharKind { Regular = 0,
Wide};
75constexprCharKind CK_Regular = CharKind::Regular;
76constexprCharKind CK_Wide = CharKind::Wide;
83classCStringChecker :
public Checker< eval::Call,
84check::PreStmt<DeclStmt>,
89 mutablestd::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
90BT_NotCString, BT_AdditionOverflow, BT_UninitRead;
92 mutable const char*CurrentFunctionDescription =
nullptr;
97 structCStringChecksFilter {
98 boolCheckCStringNullArg =
false;
99 boolCheckCStringOutOfBounds =
false;
100 boolCheckCStringBufferOverlap =
false;
101 boolCheckCStringNotNullTerm =
false;
102 boolCheckCStringUninitializedRead =
false;
111CStringChecksFilter
Filter;
113 static void*getTag() {
static inttag;
return&tag; }
128 usingFnCheck = std::function<void(
constCStringChecker *,
CheckerContext&,
132{{CDM::CLibraryMaybeHardened, {
"memcpy"}, 3},
133std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Regular)},
134{{CDM::CLibraryMaybeHardened, {
"wmemcpy"}, 3},
135std::bind(&CStringChecker::evalMemcpy, _1,
_2, _3, CK_Wide)},
136{{CDM::CLibraryMaybeHardened, {
"mempcpy"}, 3},
137std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Regular)},
138{{CDM::CLibraryMaybeHardened, {
"wmempcpy"}, 3},
139std::bind(&CStringChecker::evalMempcpy, _1,
_2, _3, CK_Wide)},
140{{CDM::CLibrary, {
"memcmp"}, 3},
141std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
142{{CDM::CLibrary, {
"wmemcmp"}, 3},
143std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Wide)},
144{{CDM::CLibraryMaybeHardened, {
"memmove"}, 3},
145std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Regular)},
146{{CDM::CLibraryMaybeHardened, {
"wmemmove"}, 3},
147std::bind(&CStringChecker::evalMemmove, _1,
_2, _3, CK_Wide)},
148{{CDM::CLibraryMaybeHardened, {
"memset"}, 3},
149&CStringChecker::evalMemset},
150{{CDM::CLibrary, {
"explicit_memset"}, 3}, &CStringChecker::evalMemset},
152{{CDM::CLibraryMaybeHardened, {
"strcpy"}, 2},
153&CStringChecker::evalStrcpy},
154{{CDM::CLibraryMaybeHardened, {
"strncpy"}, 3},
155&CStringChecker::evalStrncpy},
156{{CDM::CLibraryMaybeHardened, {
"stpcpy"}, 2},
157&CStringChecker::evalStpcpy},
158{{CDM::CLibraryMaybeHardened, {
"strlcpy"}, 3},
159&CStringChecker::evalStrlcpy},
160{{CDM::CLibraryMaybeHardened, {
"strcat"}, 2},
161&CStringChecker::evalStrcat},
162{{CDM::CLibraryMaybeHardened, {
"strncat"}, 3},
163&CStringChecker::evalStrncat},
164{{CDM::CLibraryMaybeHardened, {
"strlcat"}, 3},
165&CStringChecker::evalStrlcat},
166{{CDM::CLibraryMaybeHardened, {
"strlen"}, 1},
167&CStringChecker::evalstrLength},
168{{CDM::CLibrary, {
"wcslen"}, 1}, &CStringChecker::evalstrLength},
169{{CDM::CLibraryMaybeHardened, {
"strnlen"}, 2},
170&CStringChecker::evalstrnLength},
171{{CDM::CLibrary, {
"wcsnlen"}, 2}, &CStringChecker::evalstrnLength},
172{{CDM::CLibrary, {
"strcmp"}, 2}, &CStringChecker::evalStrcmp},
173{{CDM::CLibrary, {
"strncmp"}, 3}, &CStringChecker::evalStrncmp},
174{{CDM::CLibrary, {
"strcasecmp"}, 2}, &CStringChecker::evalStrcasecmp},
175{{CDM::CLibrary, {
"strncasecmp"}, 3}, &CStringChecker::evalStrncasecmp},
176{{CDM::CLibrary, {
"strsep"}, 2}, &CStringChecker::evalStrsep},
177{{CDM::CLibrary, {
"bcopy"}, 3}, &CStringChecker::evalBcopy},
178{{CDM::CLibrary, {
"bcmp"}, 3},
179std::bind(&CStringChecker::evalMemcmp, _1,
_2, _3, CK_Regular)},
180{{CDM::CLibrary, {
"bzero"}, 2}, &CStringChecker::evalBzero},
181{{CDM::CLibraryMaybeHardened, {
"explicit_bzero"}, 2},
182&CStringChecker::evalBzero},
190{{CDM::CLibraryMaybeHardened, {
"sprintf"}, std::nullopt, 2},
191&CStringChecker::evalSprintf},
192{{CDM::CLibraryMaybeHardened, {
"snprintf"}, std::nullopt, 3},
193&CStringChecker::evalSnprintf},
198StdCopyBackward{CDM::SimpleFunc, {
"std",
"copy_backward"}, 3};
207DestinationArgExpr Dest, SourceArgExpr Source,
208 boolRestricted,
boolIsMempcpy, CharKind CK)
const;
215 boolIsStrnlen =
false)
const;
222 boolReturnEnd,
boolIsBounded, ConcatFnKind appendK,
223 boolreturnPtr =
true)
const;
234 boolIsBounded =
false,
boolIgnoreCase =
false)
const;
247 boolIsBounded)
const;
250std::pair<ProgramStateRef , ProgramStateRef >
266 boolhypothetical =
false)
const;
285 static ProgramStateRefinvalidateDestinationBufferAlwaysEscapeSuperRegion(
300InvalidationTraitOperations);
302 static boolSummarizeRegion(raw_ostream &os,
ASTContext&Ctx,
305 static boolmemsetAux(
const Expr*DstBuffer,
SValCharE,
311AnyArgExpr Arg,
SVall)
const;
315AnyArgExpr Buffer,
SValElement,
SValSize)
const;
317AnyArgExpr Buffer,
SValElement,
319CharKind CK = CharKind::Regular)
const;
321AnyArgExpr Buffer, SizeArgExpr Size,
323CharKind CK = CharKind::Regular)
const;
325SizeArgExpr Size, AnyArgExpr
First,
327CharKind CK = CharKind::Regular)
const;
331 const Stmt*Second)
const;
334StringRef WarningMsg)
const;
336 const Stmt*S, StringRef WarningMsg)
const;
338 const Stmt*S, StringRef WarningMsg)
const;
342StringRef Msg)
const;
364std::pair<ProgramStateRef, ProgramStateRef>
367std::optional<DefinedSVal> val =
V.getAs<
DefinedSVal>();
369 returnstd::pair<ProgramStateRef, ProgramStateRef>(State, State);
373 returnState->assume(svalBuilder.
evalEQ(State, *val, zero));
378AnyArgExpr Arg,
SVall)
const{
384std::tie(stateNull, stateNonNull) =
385assumeZero(
C, State, l, Arg.Expression->getType());
387 if(stateNull && !stateNonNull) {
388 if(
Filter.CheckCStringNullArg) {
390llvm::raw_svector_ostream OS(buf);
391assert(CurrentFunctionDescription);
392OS <<
"Null pointer passed as "<< (Arg.ArgumentIndex + 1)
393<< llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to " 394<< CurrentFunctionDescription;
396emitNullArgBug(
C, stateNull, Arg.Expression, OS.str());
402assert(stateNonNull);
408 SValBuilder&SVB = State->getStateManager().getSValBuilder();
411 if(CK == CharKind::Regular) {
427 if(Offset.isUnknown())
429 returnOffset.castAs<
NonLoc>();
434Os << Idx << llvm::getOrdinalSuffix(Idx);
439AnyArgExpr Buffer,
SValElement,
446 const MemRegion*R = Element.getAsRegion();
447 const auto*ER = dyn_cast_or_null<ElementRegion>(R);
457 if(!SuperR->getValueType()->isArrayType())
466std::optional<Loc> FirstElementVal =
468 if(!FirstElementVal)
472 if(
Filter.CheckCStringUninitializedRead &&
473State->getSVal(*FirstElementVal).isUndef()) {
475llvm::raw_svector_ostream OS(Buf);
476OS <<
"The first element of the ";
478OS <<
" argument is undefined";
479emitUninitializedReadBug(
C, State, Buffer.Expression,
480FirstElementVal->getAsRegion(), OS.str());
511std::optional<NonLoc> Offset =
523 SValLastElementVal =
525 if(!isa<Loc>(LastElementVal))
528 if(
Filter.CheckCStringUninitializedRead &&
529State->getSVal(LastElementVal.
castAs<
Loc>()).isUndef()) {
530 constllvm::APSInt *IdxInt = LastIdx.getAsInteger();
538llvm::raw_svector_ostream OS(Buf);
539OS <<
"The last accessed element (at index ";
540OS << IdxInt->getExtValue();
543OS <<
" argument is undefined";
544emitUninitializedReadBug(
C, State, Buffer.Expression,
554AnyArgExpr Buffer,
SValElement,
563 const MemRegion*R = Element.getAsRegion();
567 const auto*ER = dyn_cast<ElementRegion>(R);
572std::optional<NonLoc> Idx =
getIndex(state, ER, CK);
577 const auto*superReg = cast<SubRegion>(ER->getSuperRegion());
581 auto[StInBound, StOutBound] = state->assumeInBoundDual(*Idx, Size);
582 if(StOutBound && !StInBound) {
586 if(!
Filter.CheckCStringOutOfBounds)
590ErrorMessage Message =
591createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
592emitOutOfBoundsBug(
C, StOutBound, Buffer.Expression, Message);
603AnyArgExpr Buffer, SizeArgExpr Size,
604AccessKind Access, CharKind CK)
const{
613 QualTypePtrTy = getCharPtrType(Ctx, CK);
616 SValBufVal =
C.getSVal(Buffer.Expression);
617State = checkNonNull(
C, State, Buffer, BufVal);
622 if(!
Filter.CheckCStringOutOfBounds)
626svalBuilder.
evalCast(BufVal, PtrTy, Buffer.Expression->getType());
629State = CheckLocation(
C, State, Buffer, BufStart, Access, CK);
637 SValLengthVal =
C.getSVal(
Size.Expression);
638std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
644 SValOffset = svalBuilder.
evalBinOpNN(State, BO_Sub, *Length, One, SizeTy);
645 if(Offset.isUnknown())
650 if(std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>()) {
653svalBuilder.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
654State = CheckLocation(
C, State, Buffer, BufEnd, Access, CK);
655 if(Access == AccessKind::read)
656State = checkInit(
C, State, Buffer, BufEnd, *Length);
669SizeArgExpr Size, AnyArgExpr
First,
672 if(!
Filter.CheckCStringBufferOverlap)
686 if(
First.Expression->getType()->getPointeeType().getAddressSpace() !=
687Second.Expression->getType()->getPointeeType().getAddressSpace())
692 SValfirstVal = state->getSVal(
First.Expression, LCtx);
693 SValsecondVal = state->getSVal(Second.Expression, LCtx);
695std::optional<Loc> firstLoc = firstVal.
getAs<
Loc>();
699std::optional<Loc> secondLoc = secondVal.
getAs<
Loc>();
705std::tie(stateTrue, stateFalse) =
706state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
708 if(stateTrue && !stateFalse) {
710emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
721svalBuilder.
evalBinOpLL(state, BO_GT, *firstLoc, *secondLoc, cmpTy);
722std::optional<DefinedOrUnknownSVal> reverseTest =
727std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
734std::swap(firstLoc, secondLoc);
737std::swap(
First, Second);
742 SValLengthVal = state->getSVal(
Size.Expression, LCtx);
743std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
750 QualTypeCharPtrTy = getCharPtrType(Ctx, CK);
752svalBuilder.
evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
753std::optional<Loc> FirstStartLoc = FirstStart.
getAs<
Loc>();
758 SValFirstEnd = svalBuilder.
evalBinOpLN(state, BO_Add, *FirstStartLoc,
760std::optional<Loc> FirstEndLoc = FirstEnd.
getAs<
Loc>();
766svalBuilder.
evalBinOpLL(state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
767std::optional<DefinedOrUnknownSVal> OverlapTest =
772std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
774 if(stateTrue && !stateFalse) {
776emitOverlapBug(
C, stateTrue,
First.Expression, Second.Expression);
792BT_Overlap.reset(
new BugType(
Filter.CheckNameCStringBufferOverlap,
796 autoreport = std::make_unique<PathSensitiveBugReport>(
797*BT_Overlap,
"Arguments must not be overlapping buffers", N);
798report->addRange(
First->getSourceRange());
801 C.emitReport(std::move(report));
805 const Stmt*S, StringRef WarningMsg)
const{
815std::make_unique<PathSensitiveBugReport>(*BT_Null, WarningMsg, N);
816 Report->addRange(S->getSourceRange());
817 if(
const auto*Ex = dyn_cast<Expr>(S))
819 C.emitReport(std::move(
Report));
826StringRef Msg)
const{
829BT_UninitRead.reset(
new BugType(
Filter.CheckNameCStringUninitializedRead,
830 "Accessing unitialized/garbage values"));
833std::make_unique<PathSensitiveBugReport>(*BT_UninitRead, Msg, N);
834 Report->addNote(
"Other elements might also be undefined",
839 C.emitReport(std::move(
Report));
845StringRef WarningMsg)
const{
848BT_Bounds.reset(
new BugType(
Filter.CheckCStringOutOfBounds
849?
Filter.CheckNameCStringOutOfBounds
850:
Filter.CheckNameCStringNullArg,
851 "Out-of-bound array access"));
857std::make_unique<PathSensitiveBugReport>(*BT_Bounds, WarningMsg, N);
858 Report->addRange(S->getSourceRange());
859 C.emitReport(std::move(
Report));
865StringRef WarningMsg)
const{
866 if(
ExplodedNode*N =
C.generateNonFatalErrorNode(State)) {
867 if(!BT_NotCString) {
875std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
877 Report->addRange(S->getSourceRange());
878 C.emitReport(std::move(
Report));
885 if(!BT_AdditionOverflow) {
889BT_AdditionOverflow.reset(
896 const char*WarningMsg =
897 "This expression will create a string whose length is too big to " 898 "be represented as a size_t";
900 auto Report= std::make_unique<PathSensitiveBugReport>(*BT_AdditionOverflow,
902 C.emitReport(std::move(
Report));
911 if(!
Filter.CheckCStringOutOfBounds)
922 constllvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
926 if(isa<nonloc::ConcreteInt>(right)) {
927maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
932maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
937 if(std::optional<NonLoc> maxMinusRightNL = maxMinusRight.
getAs<
NonLoc>()) {
941*maxMinusRightNL, cmpTy);
944std::tie(stateOverflow, stateOkay) =
947 if(stateOverflow && !stateOkay) {
949emitAdditionOverflowBug(
C, stateOverflow);
964assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
969 caseMemRegion::StringRegionKind:
974 caseMemRegion::SymbolicRegionKind:
975 caseMemRegion::AllocaRegionKind:
976 caseMemRegion::NonParamVarRegionKind:
977 caseMemRegion::ParamVarRegionKind:
978 caseMemRegion::FieldRegionKind:
979 caseMemRegion::ObjCIvarRegionKind:
983 caseMemRegion::ElementRegionKind:
997 returnstate->remove<CStringLength>(MR);
999 returnstate->set<CStringLength>(MR, strLength);
1006 boolhypothetical) {
1007 if(!hypothetical) {
1009 const SVal*Recorded = state->get<CStringLength>(MR);
1019 C.getLocationContext(),
1022 if(!hypothetical) {
1023 if(std::optional<NonLoc> strLn = strLength.
getAs<
NonLoc>()) {
1026 constllvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
1028std::optional<APSIntPtr> maxLengthInt =
1029BVF.
evalAPSInt(BO_Div, maxValInt, fourInt);
1031 SValevalLength = svalBuilder.
evalBinOpNN(state, BO_LE, *strLn, maxLength,
1035state = state->set<CStringLength>(MR, strLength);
1043 boolhypothetical)
const{
1050 if(
Filter.CheckCStringNotNullTerm) {
1052llvm::raw_svector_ostream os(buf);
1053assert(CurrentFunctionDescription);
1054os <<
"Argument to "<< CurrentFunctionDescription
1055<<
" is the address of the label '"<<
Label->getLabel()->getName()
1056<<
"', which is not a null-terminated string";
1058emitNotCStringBug(
C, state, Ex, os.str());
1072 caseMemRegion::StringRegionKind: {
1077 const StringLiteral*strLit = cast<StringRegion>(MR)->getStringLiteral();
1080 caseMemRegion::NonParamVarRegionKind: {
1083 const VarDecl*
Decl= cast<NonParamVarRegion>(MR)->getDecl();
1084 if(
Decl->getType().isConstQualified() &&
Decl->hasGlobalStorage()) {
1086 if(
auto*StrLit = dyn_cast<StringLiteral>(
Init)) {
1089 returnSvalBuilder.
makeIntVal(StrLit->getLength(), SizeTy);
1095 caseMemRegion::SymbolicRegionKind:
1096 caseMemRegion::AllocaRegionKind:
1097 caseMemRegion::ParamVarRegionKind:
1098 caseMemRegion::FieldRegionKind:
1099 caseMemRegion::ObjCIvarRegionKind:
1100 returngetCStringLengthForRegion(
C, state, Ex, MR, hypothetical);
1101 caseMemRegion::CompoundLiteralRegionKind:
1104 caseMemRegion::ElementRegionKind:
1112 if(
Filter.CheckCStringNotNullTerm) {
1114llvm::raw_svector_ostream os(buf);
1116assert(CurrentFunctionDescription);
1117os <<
"Argument to "<< CurrentFunctionDescription <<
" is ";
1119 if(SummarizeRegion(os,
C.getASTContext(), MR))
1120os <<
", which is not a null-terminated string";
1122os <<
"not a null-terminated string";
1124emitNotCStringBug(
C, state, Ex, os.str());
1142 const StringRegion*strRegion= dyn_cast<StringRegion>(bufRegion);
1166std::optional<NonLoc> Length = LengthVal.
getAs<
NonLoc>();
1172 SValOffset = SB.
evalBinOpNN(State, BO_Sub, *Length, One, LengthTy);
1173 if(Offset.isUnknown())
1179std::optional<Loc> BufLoc = BufStart.
getAs<
Loc>();
1183 SValBufEnd = SB.
evalBinOpLN(State, BO_Add, *BufLoc, LastOffset, PtrTy);
1197 "isFirstBufInBound should only be called with char* ElementRegions");
1208 return static_cast<bool>(StInBound);
1214 autoInvalidationTraitOperations =
1215[&
C, S, BufTy = BufE->
getType(), BufV, SizeV,
1219 if(MemRegion::FieldRegionKind == R->
getKind() &&
1220isFirstBufInBound(
C, S, BufV, BufTy, SizeV, SizeTy)) {
1228 returninvalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1232CStringChecker::invalidateDestinationBufferAlwaysEscapeSuperRegion(
1236 returnisa<FieldRegion>(R);
1239 returninvalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1242ProgramStateRefCStringChecker::invalidateDestinationBufferNeverOverflows(
1244 autoInvalidationTraitOperations =
1246 if(MemRegion::FieldRegionKind == R->
getKind())
1253 returninvalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1260 autoInvalidationTraitOperations =
1270 returninvalidateBufferAux(
C, S, BufE, BufV, InvalidationTraitOperations);
1277InvalidationTraitOperations) {
1278std::optional<Loc> L =
V.getAs<
Loc>();
1290 if(
const ElementRegion*ER = dyn_cast<ElementRegion>(R)) {
1298 boolCausesPointerEscape = InvalidationTraitOperations(ITraits, R);
1300 returnState->invalidateRegions(R,
E,
C.blockCount(), LCtx,
1301CausesPointerEscape,
nullptr,
nullptr,
1308 returnState->killBinding(*L);
1311boolCStringChecker::SummarizeRegion(raw_ostream &os,
ASTContext&Ctx,
1314 caseMemRegion::FunctionCodeRegionKind: {
1315 if(
const auto*FD = cast<FunctionCodeRegion>(MR)->getDecl())
1316os <<
"the address of the function '"<< *FD <<
'\'';
1318os <<
"the address of a function";
1321 caseMemRegion::BlockCodeRegionKind:
1322os <<
"block text";
1324 caseMemRegion::BlockDataRegionKind:
1327 caseMemRegion::CXXThisRegionKind:
1328 caseMemRegion::CXXTempObjectRegionKind:
1329os <<
"a C++ temp object of type " 1330<< cast<TypedValueRegion>(MR)->getValueType();
1332 caseMemRegion::NonParamVarRegionKind:
1333os <<
"a variable of type"<< cast<TypedValueRegion>(MR)->getValueType();
1335 caseMemRegion::ParamVarRegionKind:
1336os <<
"a parameter of type"<< cast<TypedValueRegion>(MR)->getValueType();
1338 caseMemRegion::FieldRegionKind:
1339os <<
"a field of type "<< cast<TypedValueRegion>(MR)->getValueType();
1341 caseMemRegion::ObjCIvarRegionKind:
1342os <<
"an instance variable of type " 1343<< cast<TypedValueRegion>(MR)->getValueType();
1350boolCStringChecker::memsetAux(
const Expr*DstBuffer,
SValCharVal,
1353 SValMemVal =
C.getSVal(DstBuffer);
1354 SValSizeVal =
C.getSVal(Size);
1364 const MemRegion*BR = Offset.getRegion();
1366std::optional<NonLoc> SizeNL = SizeVal.
getAs<
NonLoc>();
1375 if(Offset.isValid() && !Offset.hasSymbolicOffset() &&
1376Offset.getOffset() == 0) {
1381std::tie(StateWholeReg, StateNotWholeReg) =
1382State->assume(svalBuilder.
evalEQ(State, SizeDV, *SizeNL));
1389std::tie(StateNullChar, StateNonNullChar) =
1392 if(StateWholeReg && !StateNotWholeReg && StateNullChar &&
1393!StateNonNullChar) {
1400State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1401 C.getLocationContext());
1405State = invalidateDestinationBufferBySize(
C, State, DstBuffer, MemVal,
1406SizeVal,
Size->getType());
1409 if(StateNullChar && !StateNonNullChar) {
1412State = setCStringLength(State, MR,
1414}
else if(!StateNullChar && StateNonNullChar) {
1416CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1417 C.getLocationContext(),
C.blockCount());
1424State = setCStringLength(
1431State = invalidateDestinationBufferBySize(
C, State, DstBuffer, MemVal,
1432SizeVal,
Size->getType());
1443DestinationArgExpr Dest,
1444SourceArgExpr Source,
boolRestricted,
1445 boolIsMempcpy, CharKind CK)
const{
1446CurrentFunctionDescription =
"memory copy function";
1450 SValsizeVal = state->getSVal(
Size.Expression, LCtx);
1454std::tie(stateZeroSize, stateNonZeroSize) =
1455assumeZero(
C, state, sizeVal, sizeTy);
1458 SValdestVal = state->getSVal(Dest.Expression, LCtx);
1462 if(stateZeroSize && !stateNonZeroSize) {
1464stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1465 C.addTransition(stateZeroSize);
1470 if(stateNonZeroSize) {
1474state = stateNonZeroSize;
1478state = checkNonNull(
C, state, Dest, destVal);
1483 SValsrcVal = state->getSVal(Source.Expression, LCtx);
1487state = checkNonNull(
C, state, Source, srcVal);
1492state = CheckBufferAccess(
C, state, Dest, Size, AccessKind::write, CK);
1493state = CheckBufferAccess(
C, state, Source, Size, AccessKind::read, CK);
1496state = CheckOverlap(
C, state, Size, Dest, Source, CK);
1507 QualTypeCharPtrTy = getCharPtrType(Ctx, CK);
1508 SValDestRegCharVal =
1509SvalBuilder.
evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1510 SVallastElement =
C.getSValBuilder().evalBinOp(
1511state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1515lastElement =
C.getSValBuilder().conjureSymbolVal(
1516 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1519state = state->BindExpr(
Call.getOriginExpr(), LCtx, lastElement);
1523state = state->BindExpr(
Call.getOriginExpr(), LCtx, destVal);
1532state = invalidateDestinationBufferBySize(
1533 C, state, Dest.Expression,
C.getSVal(Dest.Expression), sizeVal,
1534 Size.Expression->getType());
1538state = invalidateSourceBuffer(
C, state, Source.Expression,
1539 C.getSVal(Source.Expression));
1541 C.addTransition(state);
1546CharKind CK)
const{
1549DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1550SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1551SizeArgExpr
Size= {{
Call.getArgExpr(2), 2}};
1555 constexpr boolIsRestricted =
true;
1556 constexpr boolIsMempcpy =
false;
1557evalCopyCommon(
C,
Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
1561CharKind CK)
const{
1564DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1565SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1566SizeArgExpr
Size= {{
Call.getArgExpr(2), 2}};
1568 constexpr boolIsRestricted =
true;
1569 constexpr boolIsMempcpy =
true;
1570evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1575CharKind CK)
const{
1578DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
1579SourceArgExpr Src = {{
Call.getArgExpr(1), 1}};
1580SizeArgExpr
Size= {{
Call.getArgExpr(2), 2}};
1582 constexpr boolIsRestricted =
false;
1583 constexpr boolIsMempcpy =
false;
1584evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1590SourceArgExpr Src{{
Call.getArgExpr(0), 0}};
1591DestinationArgExpr Dest = {{
Call.getArgExpr(1), 1}};
1592SizeArgExpr
Size= {{
Call.getArgExpr(2), 2}};
1594 constexpr boolIsRestricted =
false;
1595 constexpr boolIsMempcpy =
false;
1596evalCopyCommon(
C,
Call,
C.getState(), Size, Dest, Src, IsRestricted,
1597IsMempcpy, CharKind::Regular);
1601CharKind CK)
const{
1603CurrentFunctionDescription =
"memory comparison function";
1605AnyArgExpr
Left= {
Call.getArgExpr(0), 0};
1606AnyArgExpr
Right= {
Call.getArgExpr(1), 1};
1607SizeArgExpr
Size= {{
Call.getArgExpr(2), 2}};
1614 SValsizeVal = State->getSVal(
Size.Expression, LCtx);
1618std::tie(stateZeroSize, stateNonZeroSize) =
1619assumeZero(
C, State, sizeVal, sizeTy);
1623 if(stateZeroSize) {
1624State = stateZeroSize;
1625State = State->BindExpr(
Call.getOriginExpr(), LCtx,
1626Builder.makeZeroVal(
Call.getResultType()));
1627 C.addTransition(State);
1631 if(stateNonZeroSize) {
1632State = stateNonZeroSize;
1643std::tie(SameBuffer, NotSameBuffer) =
1644State->assume(Builder.evalEQ(State, LV, RV));
1648 if(SameBuffer && !NotSameBuffer) {
1650State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read);
1652State = SameBuffer->BindExpr(
Call.getOriginExpr(), LCtx,
1653Builder.makeZeroVal(
Call.getResultType()));
1654 C.addTransition(State);
1661assert(NotSameBuffer);
1662State = CheckBufferAccess(
C, State, Right, Size, AccessKind::read, CK);
1663State = CheckBufferAccess(
C, State, Left, Size, AccessKind::read, CK);
1666 SValCmpV = Builder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(), LCtx,
1668State = State->BindExpr(
Call.getOriginExpr(), LCtx, CmpV);
1669 C.addTransition(State);
1677evalstrLengthCommon(
C,
Call,
false);
1683evalstrLengthCommon(
C,
Call,
true);
1688 boolIsStrnlen)
const{
1689CurrentFunctionDescription =
"string length function";
1694 const Expr*maxlenExpr =
Call.getArgExpr(1);
1695 SValmaxlenVal = state->getSVal(maxlenExpr, LCtx);
1698std::tie(stateZeroSize, stateNonZeroSize) =
1699assumeZero(
C, state, maxlenVal, maxlenExpr->
getType());
1703 if(stateZeroSize) {
1704 SValzero =
C.getSValBuilder().makeZeroVal(
Call.getResultType());
1705stateZeroSize = stateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, zero);
1706 C.addTransition(stateZeroSize);
1710 if(!stateNonZeroSize)
1714state = stateNonZeroSize;
1718AnyArgExpr Arg = {
Call.getArgExpr(0), 0};
1719 SValArgVal = state->getSVal(Arg.Expression, LCtx);
1720state = checkNonNull(
C, state, Arg, ArgVal);
1725 SValstrLength = getCStringLength(
C, state, Arg.Expression, ArgVal);
1737 QualTypecmpTy =
C.getSValBuilder().getConditionType();
1741 const Expr*maxlenExpr =
Call.getArgExpr(1);
1742 SValmaxlenVal = state->getSVal(maxlenExpr, LCtx);
1744std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1745std::optional<NonLoc> maxlenValNL = maxlenVal.
getAs<
NonLoc>();
1747 if(strLengthNL && maxlenValNL) {
1751std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1753.evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1756 if(stateStringTooLong && !stateStringNotTooLong) {
1758result = *maxlenValNL;
1759}
else if(stateStringNotTooLong && !stateStringTooLong) {
1761result = *strLengthNL;
1770result =
C.getSValBuilder().conjureSymbolVal(
1771 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1775state = state->assume(
C.getSValBuilder().evalBinOpNN(
1776state, BO_LE, resultNL, *strLengthNL, cmpTy)
1781state = state->assume(
C.getSValBuilder().evalBinOpNN(
1782state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1794result =
C.getSValBuilder().conjureSymbolVal(
1795 nullptr,
Call.getOriginExpr(), LCtx,
C.blockCount());
1800assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1801state = state->BindExpr(
Call.getOriginExpr(), LCtx, result);
1802 C.addTransition(state);
1808evalStrcpyCommon(
C,
Call,
1811ConcatFnKind::none);
1817evalStrcpyCommon(
C,
Call,
1820ConcatFnKind::none);
1826evalStrcpyCommon(
C,
Call,
1829ConcatFnKind::none);
1835evalStrcpyCommon(
C,
Call,
1845evalStrcpyCommon(
C,
Call,
1848ConcatFnKind::strcat);
1854evalStrcpyCommon(
C,
Call,
1857ConcatFnKind::strcat);
1865evalStrcpyCommon(
C,
Call,
1868ConcatFnKind::strlcat,
1873 boolReturnEnd,
boolIsBounded,
1874ConcatFnKind appendK,
1875 boolreturnPtr)
const{
1876 if(appendK == ConcatFnKind::none)
1877CurrentFunctionDescription =
"string copy function";
1879CurrentFunctionDescription =
"string concatenation function";
1885DestinationArgExpr Dst = {{
Call.getArgExpr(0), 0}};
1886 SValDstVal = state->getSVal(Dst.Expression, LCtx);
1887state = checkNonNull(
C, state, Dst, DstVal);
1892SourceArgExpr srcExpr = {{
Call.getArgExpr(1), 1}};
1893 SValsrcVal = state->getSVal(srcExpr.Expression, LCtx);
1894state = checkNonNull(
C, state, srcExpr, srcVal);
1899 SValstrLength = getCStringLength(
C, state, srcExpr.Expression, srcVal);
1900std::optional<NonLoc> strLengthNL = strLength.
getAs<
NonLoc>();
1903 SValdstStrLength = getCStringLength(
C, state, Dst.Expression, DstVal);
1904std::optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<
NonLoc>();
1919 const char*boundWarning =
nullptr;
1923SizeArgExpr SrcExprAsSizeDummy = {
1924{srcExpr.Expression, srcExpr.ArgumentIndex}};
1925state = CheckOverlap(
1927(IsBounded ? SizeArgExpr{{
Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
1936SizeArgExpr lenExpr = {{
Call.getArgExpr(2), 2}};
1937 SVallenVal = state->getSVal(lenExpr.Expression, LCtx);
1941svalBuilder.
evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1943std::optional<NonLoc> lenValNL = lenVal.
getAs<
NonLoc>();
1947 if(strLengthNL && lenValNL) {
1949 caseConcatFnKind::none:
1950 caseConcatFnKind::strcat: {
1955std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1957.evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1958.castAs<DefinedOrUnknownSVal>());
1960 if(stateSourceTooLong && !stateSourceNotTooLong) {
1963state = stateSourceTooLong;
1964amountCopied = lenVal;
1966}
else if(!stateSourceTooLong && stateSourceNotTooLong) {
1968state = stateSourceNotTooLong;
1969amountCopied = strLength;
1973 caseConcatFnKind::strlcat:
1974 if(!dstStrLengthNL)
1979*dstStrLengthNL, sizeTy);
1980 if(!isa<NonLoc>(freeSpace))
1983svalBuilder.
evalBinOp(state, BO_Sub, freeSpace,
1984svalBuilder.
makeIntVal(1, sizeTy), sizeTy);
1985std::optional<NonLoc> freeSpaceNL = freeSpace.
getAs<
NonLoc>();
1992state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1995std::tie(TrueState, FalseState) =
1999 if(TrueState && !FalseState) {
2000amountCopied = strLength;
2004 if(!TrueState && FalseState) {
2005amountCopied = freeSpace;
2008 if(TrueState && FalseState)
2016 caseConcatFnKind::strcat:
2022 if(dstStrLength.isUndef())
2025 if(dstStrLengthNL) {
2027state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
2029boundWarning =
"Size argument is greater than the free space in the " 2030 "destination buffer";
2033 caseConcatFnKind::none:
2034 caseConcatFnKind::strlcat:
2044std::tie(StateZeroSize, StateNonZeroSize) =
2045assumeZero(
C, state, *lenValNL, sizeTy);
2048 if(StateZeroSize && !StateNonZeroSize) {
2051StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, DstVal);
2053 if(appendK == ConcatFnKind::none) {
2055StateZeroSize = StateZeroSize->BindExpr(
Call.getOriginExpr(),
2060state, BO_Add, strLength, dstStrLength, sizeTy);
2062StateZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, retSize);
2065 C.addTransition(StateZeroSize);
2073maxLastElementIndex =
2074svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
2075boundWarning =
"Size argument is greater than the length of the " 2076 "destination buffer";
2083amountCopied = strLength;
2094 if(appendK == ConcatFnKind::none && !returnPtr) {
2096strlRetVal = strLength;
2102 if(appendK != ConcatFnKind::none) {
2105 if(dstStrLength.isUndef())
2108 if(appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
2109strlRetVal = svalBuilder.
evalBinOpNN(state, BO_Add, *strLengthNL,
2110*dstStrLengthNL, sizeTy);
2113std::optional<NonLoc> amountCopiedNL = amountCopied.
getAs<
NonLoc>();
2116 if(amountCopiedNL && dstStrLengthNL) {
2118state = checkAdditionOverflow(
C, state, *amountCopiedNL, *dstStrLengthNL);
2122finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *amountCopiedNL,
2123*dstStrLengthNL, sizeTy);
2132getCStringLength(
C, state,
Call.getOriginExpr(), DstVal,
true);
2133assert(!finalStrLength.
isUndef());
2135 if(std::optional<NonLoc> finalStrLengthNL =
2137 if(amountCopiedNL && appendK == ConcatFnKind::none) {
2141state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
2148 if(dstStrLengthNL && appendK != ConcatFnKind::none) {
2166finalStrLength = amountCopied;
2174Result = (ReturnEnd ?
UnknownVal() : DstVal);
2176 if(appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
2178Result = strlRetVal;
2180Result = finalStrLength;
2187 if(std::optional<loc::MemRegionVal> dstRegVal =
2189 QualTypeptrTy = Dst.Expression->getType();
2193 if(std::optional<NonLoc> maxLastNL = maxLastElementIndex.
getAs<
NonLoc>()) {
2194 SValmaxLastElement =
2195svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
2198state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2202state = CheckLocation(
C, state, Dst, maxLastElement, AccessKind::write);
2208 if(std::optional<NonLoc> knownStrLength = finalStrLength.
getAs<
NonLoc>()) {
2209 SVallastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
2210*knownStrLength, ptrTy);
2213 if(!boundWarning) {
2215state = CheckLocation(
C, state, Dst, DstVal, AccessKind::write);
2219state = CheckLocation(
C, state, Dst, lastElement, AccessKind::write);
2225 if(returnPtr && ReturnEnd)
2226Result = lastElement;
2236state = invalidateDestinationBufferBySize(
C, state, Dst.Expression,
2237*dstRegVal, amountCopied,
2238 C.getASTContext().getSizeType());
2242state = invalidateSourceBuffer(
C, state, srcExpr.Expression, srcVal);
2245 if(IsBounded && (appendK == ConcatFnKind::none)) {
2250 if(amountCopied != strLength)
2253state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
2261 if(ReturnEnd && Result.isUnknown()) {
2267state = state->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2268 C.addTransition(state);
2274evalStrcmpCommon(
C,
Call,
false,
false);
2280evalStrcmpCommon(
C,
Call,
true,
false);
2286evalStrcmpCommon(
C,
Call,
false,
true);
2292evalStrcmpCommon(
C,
Call,
true,
true);
2296 boolIsBounded,
boolIgnoreCase)
const{
2297CurrentFunctionDescription =
"string comparison function";
2302AnyArgExpr
Left= {
Call.getArgExpr(0), 0};
2303 SValLeftVal = state->getSVal(
Left.Expression, LCtx);
2304state = checkNonNull(
C, state, Left, LeftVal);
2309AnyArgExpr
Right= {
Call.getArgExpr(1), 1};
2310 SValRightVal = state->getSVal(
Right.Expression, LCtx);
2311state = checkNonNull(
C, state, Right, RightVal);
2316 SValLeftLength = getCStringLength(
C, state,
Left.Expression, LeftVal);
2321 SValRightLength = getCStringLength(
C, state,
Right.Expression, RightVal);
2335std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
2341StSameBuf->BindExpr(
Call.getOriginExpr(), LCtx,
2342svalBuilder.makeZeroVal(
Call.getResultType()));
2343 C.addTransition(StSameBuf);
2350assert(StNotSameBuf);
2351state = StNotSameBuf;
2358getCStringLiteral(
C, state,
Left.Expression, LeftVal);
2360getCStringLiteral(
C, state,
Right.Expression, RightVal);
2361 boolcanComputeResult =
false;
2362 SValresultVal = svalBuilder.conjureSymbolVal(
nullptr,
Call.getOriginExpr(),
2363LCtx,
C.blockCount());
2365 if(LeftStrLiteral && RightStrLiteral) {
2366StringRef LeftStrRef = LeftStrLiteral->
getString();
2367StringRef RightStrRef = RightStrLiteral->
getString();
2371 const Expr*lenExpr =
Call.getArgExpr(2);
2372 SVallenVal = state->getSVal(lenExpr, LCtx);
2375 if(
constllvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2377LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2378RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2379canComputeResult =
true;
2383canComputeResult =
true;
2386 if(canComputeResult) {
2388 size_ts1Term = LeftStrRef.find(
'\0');
2389 if(s1Term != StringRef::npos)
2390LeftStrRef = LeftStrRef.substr(0, s1Term);
2392 size_ts2Term = RightStrRef.find(
'\0');
2393 if(s2Term != StringRef::npos)
2394RightStrRef = RightStrRef.substr(0, s2Term);
2397 intcompareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2398: LeftStrRef.compare(RightStrRef);
2402 if(compareRes == 0) {
2403resultVal = svalBuilder.makeIntVal(compareRes,
Call.getResultType());
2406 DefinedSValzeroVal = svalBuilder.makeIntVal(0,
Call.getResultType());
2410 SValcompareWithZero =
2411svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2412svalBuilder.getConditionType());
2414state = state->assume(compareWithZeroVal,
true);
2419state = state->BindExpr(
Call.getOriginExpr(), LCtx, resultVal);
2422 C.addTransition(state);
2429SourceArgExpr SearchStrPtr = {{
Call.getArgExpr(0), 0}};
2432 if(CharPtrTy.
isNull() ||
Call.getResultType().getUnqualifiedType() !=
2436CurrentFunctionDescription =
"strsep()";
2442 SValSearchStrVal = State->getSVal(SearchStrPtr.Expression, LCtx);
2443State = checkNonNull(
C, State, SearchStrPtr, SearchStrVal);
2448AnyArgExpr DelimStr = {
Call.getArgExpr(1), 1};
2449 SValDelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
2450State = checkNonNull(
C, State, DelimStr, DelimStrVal);
2456 if(std::optional<Loc> SearchStrLoc = SearchStrVal.
getAs<
Loc>()) {
2458Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2463State = invalidateDestinationBufferNeverOverflows(
2464 C, State, SearchStrPtr.Expression, Result);
2469State->bindLoc(*SearchStrLoc,
2471LCtx, CharPtrTy,
C.blockCount()),
2481State = State->BindExpr(
Call.getOriginExpr(), LCtx, Result);
2482 C.addTransition(State);
2488evalStdCopyCommon(
C,
Call);
2493evalStdCopyCommon(
C,
Call);
2498 if(!
Call.getArgExpr(2)->getType()->isPointerType())
2511 const Expr*Dst =
Call.getArgExpr(2);
2512 SValDstVal = State->getSVal(Dst, LCtx);
2516invalidateDestinationBufferAlwaysEscapeSuperRegion(
C, State, Dst, DstVal);
2522State = State->BindExpr(
Call.getOriginExpr(), LCtx, ResultVal);
2524 C.addTransition(State);
2530CurrentFunctionDescription =
"memory set function";
2532DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2533AnyArgExpr CharE = {
Call.getArgExpr(1), 1};
2534SizeArgExpr
Size= {{
Call.getArgExpr(2), 2}};
2540 SValSizeVal =
C.getSVal(
Size.Expression);
2544std::tie(ZeroSize, NonZeroSize) = assumeZero(
C, State, SizeVal, SizeTy);
2547 SValBufferPtrVal =
C.getSVal(Buffer.Expression);
2551 if(ZeroSize && !NonZeroSize) {
2552ZeroSize = ZeroSize->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2553 C.addTransition(ZeroSize);
2559State = checkNonNull(
C, NonZeroSize, Buffer, BufferPtrVal);
2563State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2570 if(!memsetAux(Buffer.Expression,
C.getSVal(CharE.Expression),
2571 Size.Expression,
C, State))
2574State = State->BindExpr(
Call.getOriginExpr(), LCtx, BufferPtrVal);
2575 C.addTransition(State);
2579CurrentFunctionDescription =
"memory clearance function";
2581DestinationArgExpr Buffer = {{
Call.getArgExpr(0), 0}};
2582SizeArgExpr
Size= {{
Call.getArgExpr(1), 1}};
2583 SVal Zero=
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2588 SValSizeVal =
C.getSVal(
Size.Expression);
2592std::tie(StateZeroSize, StateNonZeroSize) =
2593assumeZero(
C, State, SizeVal, SizeTy);
2597 if(StateZeroSize && !StateNonZeroSize) {
2598 C.addTransition(StateZeroSize);
2603 SValMemVal =
C.getSVal(Buffer.Expression);
2607State = checkNonNull(
C, StateNonZeroSize, Buffer, MemVal);
2611State = CheckBufferAccess(
C, State, Buffer, Size, AccessKind::write);
2615 if(!memsetAux(Buffer.Expression, Zero,
Size.Expression,
C, State))
2618 C.addTransition(State);
2623CurrentFunctionDescription =
"'sprintf'";
2624evalSprintfCommon(
C,
Call,
false);
2629CurrentFunctionDescription =
"'snprintf'";
2630evalSprintfCommon(
C,
Call,
true);
2634 boolIsBounded)
const{
2636 const auto*CE = cast<CallExpr>(
Call.getOriginExpr());
2637DestinationArgExpr Dest = {{
Call.getArgExpr(0), 0}};
2639 const autoNumParams =
Call.parameters().size();
2640 if(CE->getNumArgs() < NumParams) {
2645 const autoAllArguments =
2646llvm::make_range(CE->getArgs(), CE->getArgs() + CE->getNumArgs());
2647 const autoVariadicArguments = drop_begin(enumerate(AllArguments), NumParams);
2649 for(
const auto&[ArgIdx, ArgExpr] : VariadicArguments) {
2652!
type->isAnyPointerType() ||
2653!
type->getPointeeType()->isAnyCharacterType())
2655SourceArgExpr Source = {{ArgExpr,
unsigned(ArgIdx)}};
2658SizeArgExpr SrcExprAsSizeDummy = {
2659{Source.Expression, Source.ArgumentIndex}};
2660State = CheckOverlap(
2662(IsBounded ? SizeArgExpr{{
Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
2668 C.addTransition(State);
2675CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent&
Call,
2677 const auto*CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2685 if(StdCopy.matches(
Call))
2686 return&CStringChecker::evalStdCopy;
2687 if(StdCopyBackward.matches(
Call))
2688 return&CStringChecker::evalStdCopyBackward;
2694 for(
autoI : CE->arguments()) {
2700 constFnCheck *Callback = Callbacks.lookup(
Call);
2708FnCheck Callback = identifyCall(
Call,
C);
2715assert(isa<CallExpr>(
Call.getOriginExpr()));
2716Callback(
this,
C,
Call);
2724 return C.isDifferent();
2731 for(
const auto*I : DS->
decls()) {
2732 const VarDecl*
D= dyn_cast<VarDecl>(I);
2737 if(!
D->getType()->isArrayType())
2743 if(!isa<StringLiteral>(
Init))
2746 LocVarLoc = state->getLValue(
D,
C.getLocationContext());
2752assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2756state = state->set<CStringLength>(MR, strLength);
2759 C.addTransition(state);
2769CStringLengthTy Entries = state->get<CStringLength>();
2770 if(Entries.isEmpty())
2778Invalidated.insert(MR);
2780SuperRegions.insert(MR);
2781 while(
const SubRegion*SR = dyn_cast<SubRegion>(MR)) {
2782MR = SR->getSuperRegion();
2783SuperRegions.insert(MR);
2787CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2790 for(
const MemRegion*MR : llvm::make_first_range(Entries)) {
2792 if(SuperRegions.count(MR)) {
2793Entries = F.remove(Entries, MR);
2799 while(
const SubRegion*SR = dyn_cast<SubRegion>(Super)) {
2800Super = SR->getSuperRegion();
2801 if(Invalidated.count(Super)) {
2802Entries = F.remove(Entries, MR);
2808 returnstate->set<CStringLength>(Entries);
2814CStringLengthTy Entries = state->get<CStringLength>();
2816 for(
SValLen : llvm::make_second_range(Entries)) {
2822voidCStringChecker::checkDeadSymbols(
SymbolReaper&SR,
2825CStringLengthTy Entries = state->get<CStringLength>();
2826 if(Entries.isEmpty())
2829CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2830 for(
auto[Reg, Len] : Entries) {
2831 if(
SymbolRefSym = Len.getAsSymbol()) {
2833Entries = F.remove(Entries, Reg);
2837state = state->set<CStringLength>(Entries);
2838 C.addTransition(state);
2845boolento::shouldRegisterCStringModeling(
const CheckerManager&mgr) {
2849#define REGISTER_CHECKER(name) \ 2850 void ento::register##name(CheckerManager &mgr) { \ 2851 CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ 2852 checker->Filter.Check##name = true; \ 2853 checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ 2856 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }Defines enum values for all the target-independent builtin functions.
static std::optional< NonLoc > getIndex(ProgramStateRef State, const ElementRegion *ER, CharKind CK)
#define REGISTER_CHECKER(name)
static void printIdxWithOrdinalSuffix(llvm::raw_ostream &Os, unsigned Idx)
#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.
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
CanQualType UnsignedCharTy
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Decl - This represents one declaration (or definition), e.g.
This represents one expression.
Represents a function declaration or definition.
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Stmt - This represents one statement.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
StringLiteral - This represents a string literal expression, e.g.
unsigned getLength() const
StringRef getString() const
bool isPointerType() 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.
Represents a variable declaration or definition.
A record of the "type" of an APSInt, used for conversions.
llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY
APSIntPtr getMaxValue(const llvm::APSInt &v)
std::optional< APSIntPtr > evalAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt &V1, const llvm::APSInt &V2)
An immutable map from CallDescriptions to arbitrary data.
A CallDescription is a pattern that can be used to match calls based on the qualified name and the ar...
Represents an abstract call to a function or method along a particular path.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
This wrapper is used to ensure that only StringRefs originating from the CheckerRegistry are used as ...
ElementRegion is used to represent both array elements and casts.
QualType getValueType() const override
MemRegion - The root abstract class for all memory regions.
LLVM_ATTRIBUTE_RETURNS_NONNULL const RegionTy * castAs() const
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * StripCasts(bool StripBaseAndDerivedCasts=true) const
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
Put a diagnostic on return statement of all inlined functions for which the region of interest Region...
Information about invalidation for a particular region/symbol.
@ 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)
Represent a region's offset within the top level base region.
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)
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.
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
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)
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.
StringRegion - Region associated with a StringLiteral.
LLVM_ATTRIBUTE_RETURNS_NONNULL const StringLiteral * getStringLiteral() const
SubRegion - A region that subsets another larger region.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getSuperRegion() const
llvm::iterator_range< symbol_iterator > symbols() const
A class responsible for cleaning up unused symbols.
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.
TypedValueRegion - An abstract class representing regions having a typed value.
__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
DefinedOrUnknownSVal getDynamicExtent(ProgramStateRef State, const MemRegion *MR, SValBuilder &SVB)
llvm::DenseSet< SymbolRef > InvalidatedSymbols
bool Zero(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
const FunctionProtoType * T
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4