25 #include "llvm/ADT/STLExtras.h"
26 #include "llvm/ADT/SmallString.h"
27 #include "llvm/ADT/StringExtras.h"
28 #include "llvm/Support/raw_ostream.h"
30 using namespace clang;
39 unsigned ArgumentIndex;
42 struct SourceArgExpr : AnyArgExpr {
43 using AnyArgExpr::AnyArgExpr;
46 struct DestinationArgExpr : AnyArgExpr {
47 using AnyArgExpr::AnyArgExpr;
50 struct SizeArgExpr : AnyArgExpr {
51 using AnyArgExpr::AnyArgExpr;
57 static ErrorMessage createOutOfBoundErrorMsg(StringRef FunctionDescription,
60 llvm::raw_svector_ostream Os(Message);
64 << &FunctionDescription.data()[1];
66 if (Access == AccessKind::write) {
67 Os <<
" overflows the destination buffer";
69 Os <<
" accesses out-of-bound array element";
75 enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 };
76 class CStringChecker :
public Checker< eval::Call,
77 check::PreStmt<DeclStmt>,
82 mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
83 BT_NotCString, BT_AdditionOverflow, BT_UninitRead;
85 mutable const char *CurrentFunctionDescription;
90 struct CStringChecksFilter {
91 bool CheckCStringNullArg =
false;
92 bool CheckCStringOutOfBounds =
false;
93 bool CheckCStringBufferOverlap =
false;
94 bool CheckCStringNotNullTerm =
false;
95 bool CheckCStringUninitializedRead =
false;
97 CheckerNameRef CheckNameCStringNullArg;
98 CheckerNameRef CheckNameCStringOutOfBounds;
99 CheckerNameRef CheckNameCStringBufferOverlap;
100 CheckerNameRef CheckNameCStringNotNullTerm;
101 CheckerNameRef CheckNameCStringUninitializedRead;
104 CStringChecksFilter
Filter;
106 static void *getTag() {
static int tag;
return &tag; }
108 bool evalCall(
const CallEvent &Call, CheckerContext &C)
const;
109 void checkPreStmt(
const DeclStmt *DS, CheckerContext &C)
const;
111 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
119 const CallEvent *Call)
const;
121 typedef void (CStringChecker::*FnCheck)(CheckerContext &,
123 CallDescriptionMap<FnCheck> Callbacks = {
151 CallDescription StdCopy{{
"std",
"copy"}, 3},
152 StdCopyBackward{{
"std",
"copy_backward"}, 3};
154 FnCheck identifyCall(
const CallEvent &Call, CheckerContext &C)
const;
155 void evalMemcpy(CheckerContext &C,
const CallExpr *CE)
const;
156 void evalMempcpy(CheckerContext &C,
const CallExpr *CE)
const;
157 void evalMemmove(CheckerContext &C,
const CallExpr *CE)
const;
158 void evalBcopy(CheckerContext &C,
const CallExpr *CE)
const;
159 void evalCopyCommon(CheckerContext &C,
const CallExpr *CE,
161 DestinationArgExpr Dest, SourceArgExpr Source,
162 bool Restricted,
bool IsMempcpy)
const;
164 void evalMemcmp(CheckerContext &C,
const CallExpr *CE)
const;
166 void evalstrLength(CheckerContext &C,
const CallExpr *CE)
const;
167 void evalstrnLength(CheckerContext &C,
const CallExpr *CE)
const;
168 void evalstrLengthCommon(CheckerContext &C,
170 bool IsStrnlen =
false)
const;
172 void evalStrcpy(CheckerContext &C,
const CallExpr *CE)
const;
173 void evalStrncpy(CheckerContext &C,
const CallExpr *CE)
const;
174 void evalStpcpy(CheckerContext &C,
const CallExpr *CE)
const;
175 void evalStrlcpy(CheckerContext &C,
const CallExpr *CE)
const;
176 void evalStrcpyCommon(CheckerContext &C,
const CallExpr *CE,
bool ReturnEnd,
177 bool IsBounded, ConcatFnKind appendK,
178 bool returnPtr =
true)
const;
180 void evalStrcat(CheckerContext &C,
const CallExpr *CE)
const;
181 void evalStrncat(CheckerContext &C,
const CallExpr *CE)
const;
182 void evalStrlcat(CheckerContext &C,
const CallExpr *CE)
const;
184 void evalStrcmp(CheckerContext &C,
const CallExpr *CE)
const;
185 void evalStrncmp(CheckerContext &C,
const CallExpr *CE)
const;
186 void evalStrcasecmp(CheckerContext &C,
const CallExpr *CE)
const;
187 void evalStrncasecmp(CheckerContext &C,
const CallExpr *CE)
const;
188 void evalStrcmpCommon(CheckerContext &C,
190 bool IsBounded =
false,
191 bool IgnoreCase =
false)
const;
193 void evalStrsep(CheckerContext &C,
const CallExpr *CE)
const;
195 void evalStdCopy(CheckerContext &C,
const CallExpr *CE)
const;
196 void evalStdCopyBackward(CheckerContext &C,
const CallExpr *CE)
const;
197 void evalStdCopyCommon(CheckerContext &C,
const CallExpr *CE)
const;
198 void evalMemset(CheckerContext &C,
const CallExpr *CE)
const;
199 void evalBzero(CheckerContext &C,
const CallExpr *CE)
const;
202 std::pair<ProgramStateRef , ProgramStateRef >
203 static assumeZero(CheckerContext &C,
209 static SVal getCStringLengthForRegion(CheckerContext &C,
214 SVal getCStringLength(CheckerContext &C,
218 bool hypothetical =
false)
const;
227 const Expr *Ex, SVal
V,
231 static bool SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
232 const MemRegion *MR);
234 static bool memsetAux(
const Expr *DstBuffer, SVal CharE,
235 const Expr *Size, CheckerContext &C,
240 AnyArgExpr Arg, SVal l)
const;
242 AnyArgExpr Buffer, SVal Element,
245 AnyArgExpr Buffer, SizeArgExpr Size,
248 SizeArgExpr Size, AnyArgExpr First,
249 AnyArgExpr Second)
const;
250 void emitOverlapBug(CheckerContext &C,
253 const Stmt *Second)
const;
256 StringRef WarningMsg)
const;
258 const Stmt *S, StringRef WarningMsg)
const;
260 const Stmt *S, StringRef WarningMsg)
const;
263 const Expr *E)
const;
272 static bool IsFirstBufInBound(CheckerContext &C,
274 const Expr *FirstBuf,
286 std::pair<ProgramStateRef , ProgramStateRef >
291 return std::pair<ProgramStateRef , ProgramStateRef >(
state,
state);
293 SValBuilder &svalBuilder =
C.getSValBuilder();
294 DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
295 return state->assume(svalBuilder.evalEQ(
state, *val, zero));
300 AnyArgExpr Arg, SVal l)
const {
306 std::tie(stateNull, stateNonNull) =
307 assumeZero(C,
State, l, Arg.Expression->getType());
309 if (stateNull && !stateNonNull) {
310 if (
Filter.CheckCStringNullArg) {
312 llvm::raw_svector_ostream
OS(buf);
313 assert(CurrentFunctionDescription);
314 OS <<
"Null pointer passed as " << (Arg.ArgumentIndex + 1)
315 << llvm::getOrdinalSuffix(Arg.ArgumentIndex + 1) <<
" argument to "
316 << CurrentFunctionDescription;
318 emitNullArgBug(C, stateNull, Arg.Expression,
OS.str());
324 assert(stateNonNull);
331 AnyArgExpr Buffer, SVal Element,
339 const MemRegion *R = Element.getAsRegion();
343 const auto *ER = dyn_cast<ElementRegion>(R);
347 if (ER->getValueType() !=
C.getASTContext().CharTy)
351 const auto *superReg = cast<SubRegion>(ER->getSuperRegion());
352 DefinedOrUnknownSVal
Size =
356 DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
359 std::tie(StInBound, StOutBound) =
state->assumeInBoundDual(Idx, Size);
360 if (StOutBound && !StInBound) {
364 if (!
Filter.CheckCStringOutOfBounds)
369 createOutOfBoundErrorMsg(CurrentFunctionDescription, Access);
370 emitOutOfBoundsBug(C, StOutBound, Buffer.Expression, Message);
375 if (Access == AccessKind::read) {
376 if (
Filter.CheckCStringUninitializedRead &&
377 StInBound->getSVal(ER).isUndef()) {
378 emitUninitializedReadBug(C, StInBound, Buffer.Expression);
397 SValBuilder &svalBuilder =
C.getSValBuilder();
404 SVal BufVal =
C.getSVal(Buffer.Expression);
405 State = checkNonNull(C,
State, Buffer, BufVal);
410 if (!
Filter.CheckCStringOutOfBounds)
416 SVal LengthVal =
C.getSVal(
Size.Expression);
422 NonLoc One = svalBuilder.makeIntVal(1, SizeTy).castAs<NonLoc>();
423 SVal
Offset = svalBuilder.evalBinOpNN(
State, BO_Sub, *Length, One, SizeTy);
426 NonLoc LastOffset =
Offset.castAs<NonLoc>();
430 svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
434 svalBuilder.evalBinOpLN(
State, BO_Add, *BufLoc, LastOffset, PtrTy);
435 State = CheckLocation(C,
State, Buffer, BufEnd, Access);
448 SizeArgExpr Size, AnyArgExpr First,
449 AnyArgExpr Second)
const {
450 if (!
Filter.CheckCStringBufferOverlap)
464 if (
First.Expression->getType()->getPointeeType().getAddressSpace() !=
465 Second.Expression->getType()->getPointeeType().getAddressSpace())
470 SVal firstVal =
state->getSVal(
First.Expression, LCtx);
471 SVal secondVal =
state->getSVal(Second.Expression, LCtx);
482 SValBuilder &svalBuilder =
C.getSValBuilder();
483 std::tie(stateTrue, stateFalse) =
484 state->assume(svalBuilder.evalEQ(
state, *firstLoc, *secondLoc));
486 if (stateTrue && !stateFalse) {
488 emitOverlapBug(C, stateTrue,
First.Expression, Second.Expression);
497 QualType cmpTy = svalBuilder.getConditionType();
499 svalBuilder.evalBinOpLL(
state, BO_GT, *firstLoc, *secondLoc, cmpTy);
501 reverse.getAs<DefinedOrUnknownSVal>();
505 std::tie(stateTrue, stateFalse) =
state->assume(*reverseTest);
512 std::swap(firstLoc, secondLoc);
515 std::swap(First, Second);
520 SVal LengthVal =
state->getSVal(
Size.Expression, LCtx);
530 svalBuilder.evalCast(*firstLoc, CharPtrTy,
First.Expression->getType());
536 SVal FirstEnd = svalBuilder.evalBinOpLN(
state, BO_Add, *FirstStartLoc,
544 svalBuilder.evalBinOpLL(
state, BO_GT, *FirstEndLoc, *secondLoc, cmpTy);
546 Overlap.getAs<DefinedOrUnknownSVal>();
550 std::tie(stateTrue, stateFalse) =
state->assume(*OverlapTest);
552 if (stateTrue && !stateFalse) {
554 emitOverlapBug(C, stateTrue,
First.Expression, Second.Expression);
564 const Stmt *First,
const Stmt *Second)
const {
565 ExplodedNode *N =
C.generateErrorNode(
state);
570 BT_Overlap.reset(
new BugType(
Filter.CheckNameCStringBufferOverlap,
574 auto report = std::make_unique<PathSensitiveBugReport>(
575 *BT_Overlap,
"Arguments must not be overlapping buffers", N);
576 report->addRange(
First->getSourceRange());
579 C.emitReport(std::move(report));
583 const Stmt *S, StringRef WarningMsg)
const {
584 if (ExplodedNode *N =
C.generateErrorNode(
State)) {
586 BT_Null.reset(
new BuiltinBug(
588 "Null pointer argument in call to byte string function"));
590 BuiltinBug *BT =
static_cast<BuiltinBug *
>(BT_Null.get());
591 auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
592 Report->addRange(S->getSourceRange());
593 if (
const auto *Ex = dyn_cast<Expr>(S))
595 C.emitReport(std::move(Report));
599 void CStringChecker::emitUninitializedReadBug(CheckerContext &C,
601 const Expr *E)
const {
602 if (ExplodedNode *N =
C.generateErrorNode(
State)) {
604 "Bytes string function accesses uninitialized/garbage values";
607 new BuiltinBug(
Filter.CheckNameCStringUninitializedRead,
608 "Accessing unitialized/garbage values", Msg));
610 BuiltinBug *BT =
static_cast<BuiltinBug *
>(BT_UninitRead.get());
612 auto Report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
615 C.emitReport(std::move(Report));
619 void CStringChecker::emitOutOfBoundsBug(CheckerContext &C,
621 StringRef WarningMsg)
const {
622 if (ExplodedNode *N =
C.generateErrorNode(
State)) {
624 BT_Bounds.reset(
new BuiltinBug(
625 Filter.CheckCStringOutOfBounds ?
Filter.CheckNameCStringOutOfBounds
626 :
Filter.CheckNameCStringNullArg,
627 "Out-of-bound array access",
628 "Byte string function accesses out-of-bound array element"));
630 BuiltinBug *BT =
static_cast<BuiltinBug *
>(BT_Bounds.get());
635 auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
636 Report->addRange(S->getSourceRange());
637 C.emitReport(std::move(Report));
643 StringRef WarningMsg)
const {
644 if (ExplodedNode *N =
C.generateNonFatalErrorNode(
State)) {
646 BT_NotCString.reset(
new BuiltinBug(
648 "Argument is not a null-terminated string."));
651 std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
653 Report->addRange(S->getSourceRange());
654 C.emitReport(std::move(Report));
658 void CStringChecker::emitAdditionOverflowBug(CheckerContext &C,
660 if (ExplodedNode *N =
C.generateErrorNode(
State)) {
661 if (!BT_AdditionOverflow)
662 BT_AdditionOverflow.reset(
663 new BuiltinBug(
Filter.CheckNameCStringOutOfBounds,
"API",
664 "Sum of expressions causes overflow."));
669 const char *WarningMsg =
670 "This expression will create a string whose length is too big to "
671 "be represented as a size_t";
673 auto Report = std::make_unique<PathSensitiveBugReport>(*BT_AdditionOverflow,
675 C.emitReport(std::move(Report));
679 ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
682 NonLoc right)
const {
684 if (!
Filter.CheckCStringOutOfBounds)
691 SValBuilder &svalBuilder =
C.getSValBuilder();
692 BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
694 QualType sizeTy = svalBuilder.getContext().getSizeType();
695 const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
696 NonLoc maxVal = svalBuilder.makeIntVal(maxValInt);
699 if (isa<nonloc::ConcreteInt>(right)) {
700 maxMinusRight = svalBuilder.evalBinOpNN(
state, BO_Sub, maxVal, right,
705 maxMinusRight = svalBuilder.evalBinOpNN(
state, BO_Sub, maxVal, left,
711 QualType cmpTy = svalBuilder.getConditionType();
713 SVal willOverflow = svalBuilder.evalBinOpNN(
state, BO_GT, left,
714 *maxMinusRightNL, cmpTy);
717 std::tie(stateOverflow, stateOkay) =
718 state->assume(willOverflow.castAs<DefinedOrUnknownSVal>());
720 if (stateOverflow && !stateOkay) {
722 emitAdditionOverflowBug(C, stateOverflow);
737 assert(!strLength.isUndef() &&
"Attempt to set an undefined string length");
739 MR = MR->StripCasts();
741 switch (MR->getKind()) {
742 case MemRegion::StringRegionKind:
747 case MemRegion::SymbolicRegionKind:
748 case MemRegion::AllocaRegionKind:
749 case MemRegion::NonParamVarRegionKind:
750 case MemRegion::ParamVarRegionKind:
751 case MemRegion::FieldRegionKind:
752 case MemRegion::ObjCIvarRegionKind:
756 case MemRegion::ElementRegionKind:
769 if (strLength.isUnknown())
770 return state->remove<CStringLength>(MR);
772 return state->set<CStringLength>(MR, strLength);
775 SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
782 const SVal *Recorded =
state->get<CStringLength>(MR);
788 SValBuilder &svalBuilder =
C.getSValBuilder();
789 QualType sizeTy = svalBuilder.getContext().getSizeType();
790 SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
792 C.getLocationContext(),
798 BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
799 const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
800 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
801 const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt,
803 NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt);
804 SVal evalLength = svalBuilder.evalBinOpNN(
state, BO_LE, *strLn,
806 state =
state->assume(evalLength.castAs<DefinedOrUnknownSVal>(),
true);
808 state =
state->set<CStringLength>(MR, strLength);
815 const Expr *Ex, SVal Buf,
816 bool hypothetical)
const {
817 const MemRegion *MR = Buf.getAsRegion();
823 if (
Filter.CheckCStringNotNullTerm) {
825 llvm::raw_svector_ostream os(buf);
826 assert(CurrentFunctionDescription);
827 os <<
"Argument to " << CurrentFunctionDescription
828 <<
" is the address of the label '" <<
Label->getLabel()->getName()
829 <<
"', which is not a null-terminated string";
831 emitNotCStringBug(C,
state, Ex, os.str());
833 return UndefinedVal();
842 MR = MR->StripCasts();
844 switch (MR->getKind()) {
845 case MemRegion::StringRegionKind: {
848 SValBuilder &svalBuilder =
C.getSValBuilder();
849 QualType sizeTy = svalBuilder.getContext().getSizeType();
850 const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
851 return svalBuilder.makeIntVal(strLit->
getByteLength(), sizeTy);
853 case MemRegion::SymbolicRegionKind:
854 case MemRegion::AllocaRegionKind:
855 case MemRegion::NonParamVarRegionKind:
856 case MemRegion::ParamVarRegionKind:
857 case MemRegion::FieldRegionKind:
858 case MemRegion::ObjCIvarRegionKind:
859 return getCStringLengthForRegion(C,
state, Ex, MR, hypothetical);
860 case MemRegion::CompoundLiteralRegionKind:
863 case MemRegion::ElementRegionKind:
871 if (
Filter.CheckCStringNotNullTerm) {
873 llvm::raw_svector_ostream os(buf);
875 assert(CurrentFunctionDescription);
876 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
878 if (SummarizeRegion(os,
C.getASTContext(), MR))
879 os <<
", which is not a null-terminated string";
881 os <<
"not a null-terminated string";
883 emitNotCStringBug(C,
state, Ex, os.str());
885 return UndefinedVal();
889 const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
893 const MemRegion *bufRegion = val.getAsRegion();
898 bufRegion = bufRegion->StripCasts();
901 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
906 return strRegion->getStringLiteral();
909 bool CStringChecker::IsFirstBufInBound(CheckerContext &C,
911 const Expr *FirstBuf,
918 SValBuilder &svalBuilder =
C.getSValBuilder();
924 SVal BufVal =
state->getSVal(FirstBuf, LCtx);
926 SVal LengthVal =
state->getSVal(Size, LCtx);
932 NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
933 SVal
Offset = svalBuilder.evalBinOpNN(
state, BO_Sub, *Length, One, sizeTy);
936 NonLoc LastOffset =
Offset.castAs<NonLoc>();
939 SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->
getType());
945 svalBuilder.evalBinOpLN(
state, BO_Add, *BufLoc, LastOffset, PtrTy);
948 const MemRegion *R = BufEnd.getAsRegion();
952 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
958 assert(ER->getValueType() ==
C.getASTContext().CharTy &&
959 "IsFirstBufInBound should only be called with char* ElementRegions");
962 const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
966 DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
970 return static_cast<bool>(StInBound);
975 const Expr *E, SVal
V,
986 const MemRegion *R = MR->getRegion()->StripCasts();
990 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
991 R = ER->getSuperRegion();
998 bool CausesPointerEscape =
false;
999 RegionAndSymbolInvalidationTraits ITraits;
1002 if (IsSourceBuffer) {
1003 ITraits.setTrait(R->getBaseRegion(),
1006 CausesPointerEscape =
true;
1009 if (K == MemRegion::FieldRegionKind)
1010 if (Size && IsFirstBufInBound(C,
state, E, Size)) {
1019 return state->invalidateRegions(R, E,
C.blockCount(), LCtx,
1020 CausesPointerEscape,
nullptr,
nullptr,
1027 return state->killBinding(*L);
1030 bool CStringChecker::SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
1031 const MemRegion *MR) {
1032 switch (MR->getKind()) {
1033 case MemRegion::FunctionCodeRegionKind: {
1034 if (
const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
1035 os <<
"the address of the function '" << *FD <<
'\'';
1037 os <<
"the address of a function";
1040 case MemRegion::BlockCodeRegionKind:
1043 case MemRegion::BlockDataRegionKind:
1046 case MemRegion::CXXThisRegionKind:
1047 case MemRegion::CXXTempObjectRegionKind:
1048 os <<
"a C++ temp object of type "
1049 << cast<TypedValueRegion>(MR)->getValueType();
1051 case MemRegion::NonParamVarRegionKind:
1052 os <<
"a variable of type" << cast<TypedValueRegion>(MR)->getValueType();
1054 case MemRegion::ParamVarRegionKind:
1055 os <<
"a parameter of type" << cast<TypedValueRegion>(MR)->getValueType();
1057 case MemRegion::FieldRegionKind:
1058 os <<
"a field of type " << cast<TypedValueRegion>(MR)->getValueType();
1060 case MemRegion::ObjCIvarRegionKind:
1061 os <<
"an instance variable of type "
1062 << cast<TypedValueRegion>(MR)->getValueType();
1069 bool CStringChecker::memsetAux(
const Expr *DstBuffer, SVal CharVal,
1070 const Expr *Size, CheckerContext &C,
1072 SVal MemVal =
C.getSVal(DstBuffer);
1073 SVal SizeVal =
C.getSVal(Size);
1074 const MemRegion *MR = MemVal.getAsRegion();
1082 RegionOffset
Offset = MR->getAsOffset();
1083 const MemRegion *BR =
Offset.getRegion();
1089 SValBuilder &svalBuilder =
C.getSValBuilder();
1095 Offset.getOffset() == 0) {
1100 std::tie(StateWholeReg, StateNotWholeReg) =
1101 State->assume(svalBuilder.evalEQ(
State, SizeDV, *SizeNL));
1108 std::tie(StateNullChar, StateNonNullChar) =
1111 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1112 !StateNonNullChar) {
1119 State =
State->bindDefaultZero(svalBuilder.makeLoc(BR),
1120 C.getLocationContext());
1124 State = InvalidateBuffer(C,
State, DstBuffer, MemVal,
1128 if (StateNullChar && !StateNonNullChar) {
1133 }
else if (!StateNullChar && StateNonNullChar) {
1134 SVal NewStrLen = svalBuilder.getMetadataSymbolVal(
1135 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1136 C.getLocationContext(),
C.blockCount());
1140 SVal NewStrLenGESize = svalBuilder.evalBinOp(
1141 State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType());
1143 State = setCStringLength(
1144 State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(),
true),
1150 State = InvalidateBuffer(C,
State, DstBuffer, MemVal,
1160 void CStringChecker::evalCopyCommon(CheckerContext &C,
const CallExpr *CE,
1162 DestinationArgExpr Dest,
1163 SourceArgExpr Source,
bool Restricted,
1164 bool IsMempcpy)
const {
1165 CurrentFunctionDescription =
"memory copy function";
1169 SVal sizeVal =
state->getSVal(
Size.Expression, LCtx);
1173 std::tie(stateZeroSize, stateNonZeroSize) =
1174 assumeZero(C,
state, sizeVal, sizeTy);
1177 SVal destVal =
state->getSVal(Dest.Expression, LCtx);
1181 if (stateZeroSize && !stateNonZeroSize) {
1182 stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal);
1183 C.addTransition(stateZeroSize);
1188 if (stateNonZeroSize) {
1189 state = stateNonZeroSize;
1193 state = checkNonNull(C,
state, Dest, destVal);
1198 SVal srcVal =
state->getSVal(Source.Expression, LCtx);
1202 state = checkNonNull(C,
state, Source, srcVal);
1207 state = CheckBufferAccess(C,
state, Dest, Size, AccessKind::write);
1208 state = CheckBufferAccess(C,
state, Source, Size, AccessKind::read);
1211 state = CheckOverlap(C,
state, Size, Dest, Source);
1220 SValBuilder &SvalBuilder =
C.getSValBuilder();
1223 SVal DestRegCharVal =
1224 SvalBuilder.evalCast(destVal, CharPtrTy, Dest.Expression->getType());
1225 SVal lastElement =
C.getSValBuilder().evalBinOp(
1226 state, BO_Add, DestRegCharVal, sizeVal, Dest.Expression->getType());
1229 if (lastElement.isUnknown())
1230 lastElement =
C.getSValBuilder().conjureSymbolVal(
nullptr, CE, LCtx,
1234 state =
state->BindExpr(CE, LCtx, lastElement);
1248 InvalidateBuffer(C,
state, Dest.Expression,
C.getSVal(Dest.Expression),
1249 false,
Size.Expression);
1253 state = InvalidateBuffer(C,
state, Source.Expression,
1254 C.getSVal(Source.Expression),
1261 void CStringChecker::evalMemcpy(CheckerContext &C,
const CallExpr *CE)
const {
1264 DestinationArgExpr Dest = {CE->
getArg(0), 0};
1265 SourceArgExpr Src = {CE->
getArg(1), 1};
1270 constexpr
bool IsRestricted =
true;
1271 constexpr
bool IsMempcpy =
false;
1272 evalCopyCommon(C, CE,
State, Size, Dest, Src, IsRestricted, IsMempcpy);
1275 void CStringChecker::evalMempcpy(CheckerContext &C,
const CallExpr *CE)
const {
1278 DestinationArgExpr Dest = {CE->
getArg(0), 0};
1279 SourceArgExpr Src = {CE->
getArg(1), 1};
1282 constexpr
bool IsRestricted =
true;
1283 constexpr
bool IsMempcpy =
true;
1284 evalCopyCommon(C, CE,
C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
1287 void CStringChecker::evalMemmove(CheckerContext &C,
const CallExpr *CE)
const {
1290 DestinationArgExpr Dest = {CE->
getArg(0), 0};
1291 SourceArgExpr Src = {CE->
getArg(1), 1};
1294 constexpr
bool IsRestricted =
false;
1295 constexpr
bool IsMempcpy =
false;
1296 evalCopyCommon(C, CE,
C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
1299 void CStringChecker::evalBcopy(CheckerContext &C,
const CallExpr *CE)
const {
1301 SourceArgExpr Src(CE->
getArg(0), 0);
1302 DestinationArgExpr Dest = {CE->
getArg(1), 1};
1305 constexpr
bool IsRestricted =
false;
1306 constexpr
bool IsMempcpy =
false;
1307 evalCopyCommon(C, CE,
C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy);
1310 void CStringChecker::evalMemcmp(CheckerContext &C,
const CallExpr *CE)
const {
1312 CurrentFunctionDescription =
"memory comparison function";
1314 AnyArgExpr Left = {CE->
getArg(0), 0};
1315 AnyArgExpr Right = {CE->
getArg(1), 1};
1319 SValBuilder &Builder =
C.getSValBuilder();
1323 SVal sizeVal =
State->getSVal(
Size.Expression, LCtx);
1327 std::tie(stateZeroSize, stateNonZeroSize) =
1328 assumeZero(C,
State, sizeVal, sizeTy);
1332 if (stateZeroSize) {
1333 State = stateZeroSize;
1339 if (stateNonZeroSize) {
1340 State = stateNonZeroSize;
1344 DefinedOrUnknownSVal LV =
1345 State->getSVal(Left.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1346 DefinedOrUnknownSVal RV =
1347 State->getSVal(Right.Expression, LCtx).castAs<DefinedOrUnknownSVal>();
1351 std::tie(SameBuffer, NotSameBuffer) =
1352 State->assume(Builder.evalEQ(
State, LV, RV));
1356 if (SameBuffer && !NotSameBuffer) {
1358 State = CheckBufferAccess(C,
State, Left, Size, AccessKind::read);
1361 SameBuffer->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->
getType()));
1369 assert(NotSameBuffer);
1370 State = CheckBufferAccess(C,
State, Right, Size, AccessKind::read);
1371 State = CheckBufferAccess(C,
State, Left, Size, AccessKind::read);
1374 SVal CmpV = Builder.conjureSymbolVal(
nullptr, CE, LCtx,
C.blockCount());
1381 void CStringChecker::evalstrLength(CheckerContext &C,
1384 evalstrLengthCommon(C, CE,
false);
1387 void CStringChecker::evalstrnLength(CheckerContext &C,
1390 evalstrLengthCommon(C, CE,
true);
1393 void CStringChecker::evalstrLengthCommon(CheckerContext &C,
const CallExpr *CE,
1394 bool IsStrnlen)
const {
1395 CurrentFunctionDescription =
"string length function";
1401 SVal maxlenVal =
state->getSVal(maxlenExpr, LCtx);
1404 std::tie(stateZeroSize, stateNonZeroSize) =
1405 assumeZero(C,
state, maxlenVal, maxlenExpr->
getType());
1409 if (stateZeroSize) {
1410 SVal zero =
C.getSValBuilder().makeZeroVal(CE->
getType());
1411 stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero);
1412 C.addTransition(stateZeroSize);
1416 if (!stateNonZeroSize)
1420 state = stateNonZeroSize;
1424 AnyArgExpr Arg = {CE->
getArg(0), 0};
1425 SVal ArgVal =
state->getSVal(Arg.Expression, LCtx);
1431 SVal strLength = getCStringLength(C,
state, Arg.Expression, ArgVal);
1435 if (strLength.isUndef())
1438 DefinedOrUnknownSVal result = UnknownVal();
1443 QualType cmpTy =
C.getSValBuilder().getConditionType();
1448 SVal maxlenVal =
state->getSVal(maxlenExpr, LCtx);
1453 if (strLengthNL && maxlenValNL) {
1457 std::tie(stateStringTooLong, stateStringNotTooLong) =
state->assume(
1459 .evalBinOpNN(
state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1460 .castAs<DefinedOrUnknownSVal>());
1462 if (stateStringTooLong && !stateStringNotTooLong) {
1464 result = *maxlenValNL;
1465 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1467 result = *strLengthNL;
1471 if (result.isUnknown()) {
1476 result =
C.getSValBuilder().conjureSymbolVal(
nullptr, CE, LCtx,
1478 NonLoc resultNL = result.castAs<NonLoc>();
1481 state =
state->assume(
C.getSValBuilder().evalBinOpNN(
1482 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1483 .castAs<DefinedOrUnknownSVal>(),
true);
1487 state =
state->assume(
C.getSValBuilder().evalBinOpNN(
1488 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1489 .castAs<DefinedOrUnknownSVal>(),
true);
1495 result = strLength.castAs<DefinedOrUnknownSVal>();
1499 if (result.isUnknown()) {
1500 result =
C.getSValBuilder().conjureSymbolVal(
nullptr, CE, LCtx,
1506 assert(!result.isUnknown() &&
"Should have conjured a value by now");
1511 void CStringChecker::evalStrcpy(CheckerContext &C,
const CallExpr *CE)
const {
1513 evalStrcpyCommon(C, CE,
1516 ConcatFnKind::none);
1519 void CStringChecker::evalStrncpy(CheckerContext &C,
const CallExpr *CE)
const {
1521 evalStrcpyCommon(C, CE,
1524 ConcatFnKind::none);
1527 void CStringChecker::evalStpcpy(CheckerContext &C,
const CallExpr *CE)
const {
1529 evalStrcpyCommon(C, CE,
1532 ConcatFnKind::none);
1535 void CStringChecker::evalStrlcpy(CheckerContext &C,
const CallExpr *CE)
const {
1537 evalStrcpyCommon(C, CE,
1544 void CStringChecker::evalStrcat(CheckerContext &C,
const CallExpr *CE)
const {
1546 evalStrcpyCommon(C, CE,
1549 ConcatFnKind::strcat);
1552 void CStringChecker::evalStrncat(CheckerContext &C,
const CallExpr *CE)
const {
1554 evalStrcpyCommon(C, CE,
1557 ConcatFnKind::strcat);
1560 void CStringChecker::evalStrlcat(CheckerContext &C,
const CallExpr *CE)
const {
1564 evalStrcpyCommon(C, CE,
1567 ConcatFnKind::strlcat,
1571 void CStringChecker::evalStrcpyCommon(CheckerContext &C,
const CallExpr *CE,
1572 bool ReturnEnd,
bool IsBounded,
1573 ConcatFnKind appendK,
1574 bool returnPtr)
const {
1575 if (appendK == ConcatFnKind::none)
1576 CurrentFunctionDescription =
"string copy function";
1578 CurrentFunctionDescription =
"string concatenation function";
1584 DestinationArgExpr Dst = {CE->
getArg(0), 0};
1585 SVal DstVal =
state->getSVal(Dst.Expression, LCtx);
1591 SourceArgExpr srcExpr = {CE->
getArg(1), 1};
1592 SVal srcVal =
state->getSVal(srcExpr.Expression, LCtx);
1593 state = checkNonNull(C,
state, srcExpr, srcVal);
1598 SVal strLength = getCStringLength(C,
state, srcExpr.Expression, srcVal);
1602 SVal dstStrLength = getCStringLength(C,
state, Dst.Expression, DstVal);
1606 if (strLength.isUndef())
1609 SValBuilder &svalBuilder =
C.getSValBuilder();
1610 QualType cmpTy = svalBuilder.getConditionType();
1611 QualType sizeTy = svalBuilder.getContext().getSizeType();
1616 SVal amountCopied = UnknownVal();
1617 SVal maxLastElementIndex = UnknownVal();
1618 const char *boundWarning =
nullptr;
1622 SizeArgExpr SrcExprAsSizeDummy = {srcExpr.Expression, srcExpr.ArgumentIndex};
1623 state = CheckOverlap(
1625 (IsBounded ? SizeArgExpr{CE->
getArg(2), 2} : SrcExprAsSizeDummy), Dst,
1634 SizeArgExpr lenExpr = {CE->
getArg(2), 2};
1635 SVal lenVal =
state->getSVal(lenExpr.Expression, LCtx);
1639 svalBuilder.evalCast(lenVal, sizeTy, lenExpr.Expression->getType());
1645 if (strLengthNL && lenValNL) {
1647 case ConcatFnKind::none:
1648 case ConcatFnKind::strcat: {
1653 std::tie(stateSourceTooLong, stateSourceNotTooLong) =
state->assume(
1655 .evalBinOpNN(
state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1656 .castAs<DefinedOrUnknownSVal>());
1658 if (stateSourceTooLong && !stateSourceNotTooLong) {
1661 state = stateSourceTooLong;
1662 amountCopied = lenVal;
1664 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1666 state = stateSourceNotTooLong;
1667 amountCopied = strLength;
1671 case ConcatFnKind::strlcat:
1672 if (!dstStrLengthNL)
1676 SVal freeSpace = svalBuilder.evalBinOpNN(
state, BO_Sub, *lenValNL,
1677 *dstStrLengthNL, sizeTy);
1678 if (!isa<NonLoc>(freeSpace))
1681 svalBuilder.evalBinOp(
state, BO_Sub, freeSpace,
1682 svalBuilder.makeIntVal(1, sizeTy), sizeTy);
1689 SVal hasEnoughSpace = svalBuilder.evalBinOpNN(
1690 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1693 std::tie(TrueState, FalseState) =
1694 state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>());
1697 if (TrueState && !FalseState) {
1698 amountCopied = strLength;
1702 if (!TrueState && FalseState) {
1703 amountCopied = freeSpace;
1706 if (TrueState && FalseState)
1707 amountCopied = UnknownVal();
1714 case ConcatFnKind::strcat:
1720 if (dstStrLength.isUndef())
1723 if (dstStrLengthNL) {
1724 maxLastElementIndex = svalBuilder.evalBinOpNN(
1725 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1727 boundWarning =
"Size argument is greater than the free space in the "
1728 "destination buffer";
1731 case ConcatFnKind::none:
1732 case ConcatFnKind::strlcat:
1742 std::tie(StateZeroSize, StateNonZeroSize) =
1743 assumeZero(C,
state, *lenValNL, sizeTy);
1746 if (StateZeroSize && !StateNonZeroSize) {
1748 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal);
1750 if (appendK == ConcatFnKind::none) {
1752 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength);
1755 SVal retSize = svalBuilder.evalBinOp(
1756 state, BO_Add, strLength, dstStrLength, sizeTy);
1757 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize);
1760 C.addTransition(StateZeroSize);
1767 NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
1768 maxLastElementIndex =
1769 svalBuilder.evalBinOpNN(
state, BO_Sub, *lenValNL, one, sizeTy);
1770 boundWarning =
"Size argument is greater than the length of the "
1771 "destination buffer";
1778 amountCopied = strLength;
1786 SVal finalStrLength = UnknownVal();
1787 SVal strlRetVal = UnknownVal();
1789 if (appendK == ConcatFnKind::none && !returnPtr) {
1791 strlRetVal = strLength;
1797 if (appendK != ConcatFnKind::none) {
1800 if (dstStrLength.isUndef())
1803 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
1804 strlRetVal = svalBuilder.evalBinOpNN(
state, BO_Add, *strLengthNL,
1805 *dstStrLengthNL, sizeTy);
1811 if (amountCopiedNL && dstStrLengthNL) {
1813 state = checkAdditionOverflow(C,
state, *amountCopiedNL, *dstStrLengthNL);
1817 finalStrLength = svalBuilder.evalBinOpNN(
state, BO_Add, *amountCopiedNL,
1818 *dstStrLengthNL, sizeTy);
1823 if (finalStrLength.isUnknown()) {
1826 finalStrLength = getCStringLength(C,
state, CE, DstVal,
true);
1827 assert(!finalStrLength.isUndef());
1830 if (amountCopiedNL && appendK == ConcatFnKind::none) {
1833 SVal sourceInResult = svalBuilder.evalBinOpNN(
1834 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
1835 state =
state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(),
1841 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
1844 SVal destInResult = svalBuilder.evalBinOpNN(
state, BO_GE,
1849 state->assume(destInResult.castAs<DefinedOrUnknownSVal>(),
true);
1859 finalStrLength = amountCopied;
1867 Result = (ReturnEnd ? UnknownVal() : DstVal);
1869 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
1871 Result = strlRetVal;
1873 Result = finalStrLength;
1881 DstVal.getAs<loc::MemRegionVal>()) {
1882 QualType ptrTy = Dst.Expression->getType();
1887 SVal maxLastElement =
1888 svalBuilder.evalBinOpLN(
state, BO_Add, *dstRegVal, *maxLastNL, ptrTy);
1890 state = CheckLocation(C,
state, Dst, maxLastElement, AccessKind::write);
1897 SVal lastElement = svalBuilder.evalBinOpLN(
state, BO_Add, *dstRegVal,
1898 *knownStrLength, ptrTy);
1901 if (!boundWarning) {
1902 state = CheckLocation(C,
state, Dst, lastElement, AccessKind::write);
1908 if (returnPtr && ReturnEnd)
1909 Result = lastElement;
1919 state = InvalidateBuffer(C,
state, Dst.Expression, *dstRegVal,
1924 state = InvalidateBuffer(C,
state, srcExpr.Expression, srcVal,
1928 if (IsBounded && (appendK == ConcatFnKind::none)) {
1933 if (amountCopied != strLength)
1934 finalStrLength = UnknownVal();
1936 state = setCStringLength(
state, dstRegVal->getRegion(), finalStrLength);
1944 if (ReturnEnd && Result.isUnknown()) {
1945 Result = svalBuilder.conjureSymbolVal(
nullptr, CE, LCtx,
C.blockCount());
1953 void CStringChecker::evalStrcmp(CheckerContext &C,
const CallExpr *CE)
const {
1955 evalStrcmpCommon(C, CE,
false,
false);
1958 void CStringChecker::evalStrncmp(CheckerContext &C,
const CallExpr *CE)
const {
1960 evalStrcmpCommon(C, CE,
true,
false);
1963 void CStringChecker::evalStrcasecmp(CheckerContext &C,
1966 evalStrcmpCommon(C, CE,
false,
true);
1969 void CStringChecker::evalStrncasecmp(CheckerContext &C,
1972 evalStrcmpCommon(C, CE,
true,
true);
1975 void CStringChecker::evalStrcmpCommon(CheckerContext &C,
const CallExpr *CE,
1976 bool IsBounded,
bool IgnoreCase)
const {
1977 CurrentFunctionDescription =
"string comparison function";
1982 AnyArgExpr Left = {CE->
getArg(0), 0};
1983 SVal LeftVal =
state->getSVal(Left.Expression, LCtx);
1984 state = checkNonNull(C,
state, Left, LeftVal);
1989 AnyArgExpr Right = {CE->
getArg(1), 1};
1990 SVal RightVal =
state->getSVal(Right.Expression, LCtx);
1991 state = checkNonNull(C,
state, Right, RightVal);
1996 SVal LeftLength = getCStringLength(C,
state, Left.Expression, LeftVal);
1997 if (LeftLength.isUndef())
2001 SVal RightLength = getCStringLength(C,
state, Right.Expression, RightVal);
2002 if (RightLength.isUndef())
2008 DefinedOrUnknownSVal LV = LeftVal.castAs<DefinedOrUnknownSVal>();
2009 DefinedOrUnknownSVal RV = RightVal.castAs<DefinedOrUnknownSVal>();
2012 SValBuilder &svalBuilder =
C.getSValBuilder();
2013 DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(
state, LV, RV);
2015 std::tie(StSameBuf, StNotSameBuf) =
state->assume(SameBuf);
2020 StSameBuf = StSameBuf->BindExpr(CE, LCtx,
2021 svalBuilder.makeZeroVal(CE->
getType()));
2022 C.addTransition(StSameBuf);
2029 assert(StNotSameBuf);
2030 state = StNotSameBuf;
2037 getCStringLiteral(C,
state, Left.Expression, LeftVal);
2039 getCStringLiteral(C,
state, Right.Expression, RightVal);
2040 bool canComputeResult =
false;
2041 SVal resultVal = svalBuilder.conjureSymbolVal(
nullptr, CE, LCtx,
2044 if (LeftStrLiteral && RightStrLiteral) {
2045 StringRef LeftStrRef = LeftStrLiteral->
getString();
2046 StringRef RightStrRef = RightStrLiteral->
getString();
2051 SVal lenVal =
state->getSVal(lenExpr, LCtx);
2056 LeftStrRef = LeftStrRef.substr(0, (
size_t)len->getZExtValue());
2057 RightStrRef = RightStrRef.substr(0, (
size_t)len->getZExtValue());
2058 canComputeResult =
true;
2062 canComputeResult =
true;
2065 if (canComputeResult) {
2067 size_t s1Term = LeftStrRef.find(
'\0');
2068 if (s1Term != StringRef::npos)
2069 LeftStrRef = LeftStrRef.substr(0, s1Term);
2071 size_t s2Term = RightStrRef.find(
'\0');
2072 if (s2Term != StringRef::npos)
2073 RightStrRef = RightStrRef.substr(0, s2Term);
2076 int compareRes = IgnoreCase ? LeftStrRef.compare_insensitive(RightStrRef)
2077 : LeftStrRef.compare(RightStrRef);
2081 if (compareRes == 0) {
2082 resultVal = svalBuilder.makeIntVal(compareRes, CE->
getType());
2085 DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->
getType());
2089 SVal compareWithZero =
2090 svalBuilder.evalBinOp(
state, op, resultVal, zeroVal,
2091 svalBuilder.getConditionType());
2092 DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>();
2093 state =
state->assume(compareWithZeroVal,
true);
2098 state =
state->BindExpr(CE, LCtx, resultVal);
2104 void CStringChecker::evalStrsep(CheckerContext &C,
const CallExpr *CE)
const {
2107 SourceArgExpr SearchStrPtr = {CE->
getArg(0), 0};
2109 QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
2110 if (CharPtrTy.
isNull() ||
2114 CurrentFunctionDescription =
"strsep()";
2120 SVal SearchStrVal =
State->getSVal(SearchStrPtr.Expression, LCtx);
2121 State = checkNonNull(C,
State, SearchStrPtr, SearchStrVal);
2126 AnyArgExpr DelimStr = {CE->
getArg(1), 1};
2127 SVal DelimStrVal =
State->getSVal(DelimStr.Expression, LCtx);
2128 State = checkNonNull(C,
State, DelimStr, DelimStrVal);
2132 SValBuilder &SVB =
C.getSValBuilder();
2134 if (
Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
2136 Result =
State->getSVal(*SearchStrLoc, CharPtrTy);
2140 State = InvalidateBuffer(C,
State, SearchStrPtr.Expression, Result,
2146 SVB.conjureSymbolVal(getTag(),
2153 assert(SearchStrVal.isUnknown());
2155 Result = SVB.conjureSymbolVal(
nullptr, CE, LCtx,
C.blockCount());
2164 void CStringChecker::evalStdCopy(CheckerContext &C,
const CallExpr *CE)
const {
2165 evalStdCopyCommon(C, CE);
2168 void CStringChecker::evalStdCopyBackward(CheckerContext &C,
2170 evalStdCopyCommon(C, CE);
2173 void CStringChecker::evalStdCopyCommon(CheckerContext &C,
2189 SVal DstVal =
State->getSVal(Dst, LCtx);
2190 State = InvalidateBuffer(C,
State, Dst, DstVal,
false,
2193 SValBuilder &SVB =
C.getSValBuilder();
2195 SVal ResultVal = SVB.conjureSymbolVal(
nullptr, CE, LCtx,
C.blockCount());
2196 State =
State->BindExpr(CE, LCtx, ResultVal);
2201 void CStringChecker::evalMemset(CheckerContext &C,
const CallExpr *CE)
const {
2203 CurrentFunctionDescription =
"memory set function";
2205 DestinationArgExpr Buffer = {CE->
getArg(0), 0};
2206 AnyArgExpr CharE = {CE->
getArg(1), 1};
2213 SVal SizeVal =
C.getSVal(
Size.Expression);
2217 std::tie(ZeroSize, NonZeroSize) = assumeZero(C,
State, SizeVal, SizeTy);
2220 SVal BufferPtrVal =
C.getSVal(Buffer.Expression);
2224 if (ZeroSize && !NonZeroSize) {
2225 ZeroSize = ZeroSize->BindExpr(CE, LCtx, BufferPtrVal);
2226 C.addTransition(ZeroSize);
2232 State = checkNonNull(C, NonZeroSize, Buffer, BufferPtrVal);
2236 State = CheckBufferAccess(C,
State, Buffer, Size, AccessKind::write);
2243 if (!memsetAux(Buffer.Expression,
C.getSVal(CharE.Expression),
2247 State =
State->BindExpr(CE, LCtx, BufferPtrVal);
2251 void CStringChecker::evalBzero(CheckerContext &C,
const CallExpr *CE)
const {
2252 CurrentFunctionDescription =
"memory clearance function";
2254 DestinationArgExpr Buffer = {CE->
getArg(0), 0};
2256 SVal
Zero =
C.getSValBuilder().makeZeroVal(
C.getASTContext().IntTy);
2261 SVal SizeVal =
C.getSVal(
Size.Expression);
2265 std::tie(StateZeroSize, StateNonZeroSize) =
2266 assumeZero(C,
State, SizeVal, SizeTy);
2270 if (StateZeroSize && !StateNonZeroSize) {
2271 C.addTransition(StateZeroSize);
2276 SVal MemVal =
C.getSVal(Buffer.Expression);
2280 State = checkNonNull(C, StateNonZeroSize, Buffer, MemVal);
2284 State = CheckBufferAccess(C,
State, Buffer, Size, AccessKind::write);
2288 if (!memsetAux(Buffer.Expression,
Zero,
Size.Expression, C,
State))
2298 CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &Call,
2299 CheckerContext &C)
const {
2300 const auto *CE = dyn_cast_or_null<CallExpr>(
Call.getOriginExpr());
2308 if (StdCopy.matches(Call))
2309 return &CStringChecker::evalStdCopy;
2310 if (StdCopyBackward.matches(Call))
2311 return &CStringChecker::evalStdCopyBackward;
2323 const FnCheck *Callback = Callbacks.lookup(Call);
2330 bool CStringChecker::evalCall(
const CallEvent &Call, CheckerContext &C)
const {
2331 FnCheck Callback = identifyCall(Call, C);
2338 const auto *CE = cast<CallExpr>(
Call.getOriginExpr());
2339 (this->*Callback)(C, CE);
2347 return C.isDifferent();
2350 void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &C)
const {
2354 for (
const auto *I : DS->
decls()) {
2355 const VarDecl *D = dyn_cast<VarDecl>(I);
2366 if (!isa<StringLiteral>(Init))
2369 Loc VarLoc =
state->getLValue(D,
C.getLocationContext());
2370 const MemRegion *MR = VarLoc.getAsRegion();
2374 SVal StrVal =
C.getSVal(Init);
2375 assert(StrVal.isValid() &&
"Initializer string is unknown or undefined");
2376 DefinedOrUnknownSVal strLength =
2377 getCStringLength(C,
state, Init, StrVal).castAs<DefinedOrUnknownSVal>();
2379 state =
state->set<CStringLength>(MR, strLength);
2391 const CallEvent *Call)
const {
2392 CStringLengthTy Entries =
state->get<CStringLength>();
2393 if (Entries.isEmpty())
2401 I = Regions.begin(), E = Regions.end(); I != E; ++I) {
2402 const MemRegion *MR = *I;
2403 Invalidated.insert(MR);
2405 SuperRegions.insert(MR);
2406 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2407 MR = SR->getSuperRegion();
2408 SuperRegions.insert(MR);
2412 CStringLengthTy::Factory &F =
state->get_context<CStringLength>();
2415 for (CStringLengthTy::iterator I = Entries.begin(),
2416 E = Entries.end(); I != E; ++I) {
2417 const MemRegion *MR = I.getKey();
2420 if (SuperRegions.count(MR)) {
2421 Entries = F.remove(Entries, MR);
2426 const MemRegion *Super = MR;
2427 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2428 Super = SR->getSuperRegion();
2429 if (Invalidated.count(Super)) {
2430 Entries = F.remove(Entries, MR);
2436 return state->set<CStringLength>(Entries);
2440 SymbolReaper &SR)
const {
2442 CStringLengthTy Entries =
state->get<CStringLength>();
2444 for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
2446 SVal Len = I.getData();
2448 for (SymExpr::symbol_iterator si = Len.symbol_begin(),
2449 se = Len.symbol_end(); si != se; ++si)
2454 void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2455 CheckerContext &C)
const {
2457 CStringLengthTy Entries =
state->get<CStringLength>();
2458 if (Entries.isEmpty())
2461 CStringLengthTy::Factory &F =
state->get_context<CStringLength>();
2462 for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
2464 SVal Len = I.getData();
2465 if (
SymbolRef Sym = Len.getAsSymbol()) {
2467 Entries = F.remove(Entries, I.getKey());
2475 void ento::registerCStringModeling(CheckerManager &Mgr) {
2476 Mgr.registerChecker<CStringChecker>();
2479 bool ento::shouldRegisterCStringModeling(
const CheckerManager &mgr) {
2483 #define REGISTER_CHECKER(name) \
2484 void ento::register##name(CheckerManager &mgr) { \
2485 CStringChecker *checker = mgr.getChecker<CStringChecker>(); \
2486 checker->Filter.Check##name = true; \
2487 checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \
2490 bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }