23 #include "llvm/ADT/STLExtras.h" 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/Support/raw_ostream.h" 27 using namespace clang;
32 class CStringChecker :
public Checker< eval::Call,
33 check::PreStmt<DeclStmt>,
38 mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
39 BT_NotCString, BT_AdditionOverflow;
41 mutable const char *CurrentFunctionDescription;
46 struct CStringChecksFilter {
47 DefaultBool CheckCStringNullArg;
48 DefaultBool CheckCStringOutOfBounds;
49 DefaultBool CheckCStringBufferOverlap;
50 DefaultBool CheckCStringNotNullTerm;
52 CheckerNameRef CheckNameCStringNullArg;
53 CheckerNameRef CheckNameCStringOutOfBounds;
54 CheckerNameRef CheckNameCStringBufferOverlap;
55 CheckerNameRef CheckNameCStringNotNullTerm;
58 CStringChecksFilter
Filter;
60 static void *getTag() {
static int tag;
return &tag; }
62 bool evalCall(
const CallEvent &Call, CheckerContext &C)
const;
63 void checkPreStmt(
const DeclStmt *DS, CheckerContext &C)
const;
65 void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C)
const;
75 typedef void (CStringChecker::*FnCheck)(CheckerContext &,
106 StdCopyBackward{{
"std",
"copy_backward"}, 3};
108 FnCheck identifyCall(
const CallEvent &Call, CheckerContext &C)
const;
109 void evalMemcpy(CheckerContext &C,
const CallExpr *CE)
const;
110 void evalMempcpy(CheckerContext &C,
const CallExpr *CE)
const;
111 void evalMemmove(CheckerContext &C,
const CallExpr *CE)
const;
112 void evalBcopy(CheckerContext &C,
const CallExpr *CE)
const;
113 void evalCopyCommon(CheckerContext &C,
const CallExpr *CE,
118 bool Restricted =
false,
119 bool IsMempcpy =
false)
const;
121 void evalMemcmp(CheckerContext &C,
const CallExpr *CE)
const;
123 void evalstrLength(CheckerContext &C,
const CallExpr *CE)
const;
124 void evalstrnLength(CheckerContext &C,
const CallExpr *CE)
const;
125 void evalstrLengthCommon(CheckerContext &C,
127 bool IsStrnlen =
false)
const;
129 void evalStrcpy(CheckerContext &C,
const CallExpr *CE)
const;
130 void evalStrncpy(CheckerContext &C,
const CallExpr *CE)
const;
131 void evalStpcpy(CheckerContext &C,
const CallExpr *CE)
const;
132 void evalStrlcpy(CheckerContext &C,
const CallExpr *CE)
const;
133 void evalStrcpyCommon(CheckerContext &C,
const CallExpr *CE,
bool ReturnEnd,
135 bool returnPtr =
true)
const;
137 void evalStrcat(CheckerContext &C,
const CallExpr *CE)
const;
138 void evalStrncat(CheckerContext &C,
const CallExpr *CE)
const;
139 void evalStrlcat(CheckerContext &C,
const CallExpr *CE)
const;
141 void evalStrcmp(CheckerContext &C,
const CallExpr *CE)
const;
142 void evalStrncmp(CheckerContext &C,
const CallExpr *CE)
const;
143 void evalStrcasecmp(CheckerContext &C,
const CallExpr *CE)
const;
144 void evalStrncasecmp(CheckerContext &C,
const CallExpr *CE)
const;
145 void evalStrcmpCommon(CheckerContext &C,
147 bool IsBounded =
false,
148 bool IgnoreCase =
false)
const;
150 void evalStrsep(CheckerContext &C,
const CallExpr *CE)
const;
152 void evalStdCopy(CheckerContext &C,
const CallExpr *CE)
const;
153 void evalStdCopyBackward(CheckerContext &C,
const CallExpr *CE)
const;
154 void evalStdCopyCommon(CheckerContext &C,
const CallExpr *CE)
const;
155 void evalMemset(CheckerContext &C,
const CallExpr *CE)
const;
156 void evalBzero(CheckerContext &C,
const CallExpr *CE)
const;
159 std::pair<ProgramStateRef , ProgramStateRef >
160 static assumeZero(CheckerContext &C,
166 static SVal getCStringLengthForRegion(CheckerContext &C,
171 SVal getCStringLength(CheckerContext &C,
175 bool hypothetical =
false)
const;
184 const Expr *Ex, SVal V,
188 static bool SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
189 const MemRegion *MR);
191 static bool memsetAux(
const Expr *DstBuffer, SVal CharE,
192 const Expr *Size, CheckerContext &C,
200 unsigned IdxOfArg)
const;
205 const char *message =
nullptr)
const;
209 const Expr *FirstBuf,
210 const Expr *SecondBuf,
211 const char *firstMessage =
nullptr,
212 const char *secondMessage =
nullptr,
213 bool WarnAboutSize =
false)
const;
219 const char *message =
nullptr,
220 bool WarnAboutSize =
false)
const {
222 return CheckBufferAccess(C, state, Size, Buf,
nullptr, message,
nullptr,
229 const Expr *Second)
const;
230 void emitOverlapBug(CheckerContext &C,
233 const Stmt *Second)
const;
236 StringRef WarningMsg)
const;
238 const Stmt *S, StringRef WarningMsg)
const;
240 const Stmt *S, StringRef WarningMsg)
const;
241 void emitAdditionOverflowBug(CheckerContext &C,
ProgramStateRef State)
const;
251 static bool IsFirstBufInBound(CheckerContext &C,
253 const Expr *FirstBuf,
265 std::pair<ProgramStateRef , ProgramStateRef >
270 return std::pair<ProgramStateRef , ProgramStateRef >(
state,
state);
272 SValBuilder &svalBuilder = C.getSValBuilder();
273 DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
274 return state->assume(svalBuilder.evalEQ(state, *val, zero));
279 const Expr *S, SVal l,
280 unsigned IdxOfArg)
const {
286 std::tie(stateNull, stateNonNull) = assumeZero(C,
state, l, S->
getType());
288 if (stateNull && !stateNonNull) {
289 if (
Filter.CheckCStringNullArg) {
291 llvm::raw_svector_ostream
OS(buf);
292 assert(CurrentFunctionDescription);
293 OS <<
"Null pointer passed as " << IdxOfArg
294 << llvm::getOrdinalSuffix(IdxOfArg) <<
" argument to " 295 << CurrentFunctionDescription;
297 emitNullArgBug(C, stateNull, S, OS.str());
303 assert(stateNonNull);
310 const Expr *S, SVal l,
311 const char *warningMsg)
const {
317 const MemRegion *R = l.getAsRegion();
321 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
325 if (ER->getValueType() != C.getASTContext().CharTy)
329 const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
330 SValBuilder &svalBuilder = C.getSValBuilder();
332 svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
333 DefinedOrUnknownSVal Size = Extent.castAs<DefinedOrUnknownSVal>();
336 DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
340 if (StOutBound && !StInBound) {
344 if (!
Filter.CheckCStringOutOfBounds)
348 emitOutOfBoundsBug(C, StOutBound, S, warningMsg);
350 assert(CurrentFunctionDescription);
351 assert(CurrentFunctionDescription[0] !=
'\0');
354 llvm::raw_svector_ostream os(buf);
356 << &CurrentFunctionDescription[1]
357 <<
" accesses out-of-bound array element";
358 emitOutOfBoundsBug(C, StOutBound, S, os.str());
371 const Expr *FirstBuf,
372 const Expr *SecondBuf,
373 const char *firstMessage,
374 const char *secondMessage,
375 bool WarnAboutSize)
const {
380 SValBuilder &svalBuilder = C.getSValBuilder();
388 SVal BufVal = C.getSVal(FirstBuf);
389 state = checkNonNull(C,
state, FirstBuf, BufVal, 1);
394 if (!
Filter.CheckCStringOutOfBounds)
400 SVal LengthVal = C.getSVal(Size);
406 NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
407 SVal
Offset = svalBuilder.evalBinOpNN(
state, BO_Sub, *Length, One, sizeTy);
408 if (Offset.isUnknown())
410 NonLoc LastOffset = Offset.castAs<NonLoc>();
413 SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->
getType());
415 const Expr *warningExpr = (WarnAboutSize ? Size : FirstBuf);
417 SVal BufEnd = svalBuilder.evalBinOpLN(
state, BO_Add, *BufLoc,
419 state = CheckLocation(C,
state, warningExpr, BufEnd, firstMessage);
428 BufVal =
state->getSVal(SecondBuf, LCtx);
429 state = checkNonNull(C,
state, SecondBuf, BufVal, 2);
433 BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->
getType());
435 const Expr *warningExpr = (WarnAboutSize ? Size : SecondBuf);
437 SVal BufEnd = svalBuilder.evalBinOpLN(
state, BO_Add, *BufLoc,
439 state = CheckLocation(C,
state, warningExpr, BufEnd, secondMessage);
451 const Expr *Second)
const {
452 if (!
Filter.CheckCStringBufferOverlap)
467 SVal firstVal =
state->getSVal(First, LCtx);
468 SVal secondVal =
state->getSVal(Second, LCtx);
479 SValBuilder &svalBuilder = C.getSValBuilder();
480 std::tie(stateTrue, stateFalse) =
481 state->assume(svalBuilder.evalEQ(
state, *firstLoc, *secondLoc));
483 if (stateTrue && !stateFalse) {
485 emitOverlapBug(C, stateTrue, First, Second);
494 QualType cmpTy = svalBuilder.getConditionType();
495 SVal reverse = svalBuilder.evalBinOpLL(
state, BO_GT,
496 *firstLoc, *secondLoc, cmpTy);
498 reverse.getAs<DefinedOrUnknownSVal>();
502 std::tie(stateTrue, stateFalse) =
state->assume(*reverseTest);
509 std::swap(firstLoc, secondLoc);
512 std::swap(First, Second);
517 SVal LengthVal =
state->getSVal(Size, LCtx);
526 SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy,
533 SVal FirstEnd = svalBuilder.evalBinOpLN(
state, BO_Add,
534 *FirstStartLoc, *Length, CharPtrTy);
540 SVal Overlap = svalBuilder.evalBinOpLL(
state, BO_GT,
541 *FirstEndLoc, *secondLoc, cmpTy);
543 Overlap.getAs<DefinedOrUnknownSVal>();
547 std::tie(stateTrue, stateFalse) =
state->assume(*OverlapTest);
549 if (stateTrue && !stateFalse) {
551 emitOverlapBug(C, stateTrue, First, Second);
561 const Stmt *First,
const Stmt *Second)
const {
562 ExplodedNode *N = C.generateErrorNode(
state);
567 BT_Overlap.reset(
new BugType(
Filter.CheckNameCStringBufferOverlap,
571 auto report = std::make_unique<PathSensitiveBugReport>(
572 *BT_Overlap,
"Arguments must not be overlapping buffers", N);
576 C.emitReport(std::move(report));
580 const Stmt *S, StringRef WarningMsg)
const {
581 if (ExplodedNode *N = C.generateErrorNode(
State)) {
583 BT_Null.reset(
new BuiltinBug(
585 "Null pointer argument in call to byte string function"));
587 BuiltinBug *BT =
static_cast<BuiltinBug *
>(BT_Null.get());
588 auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
590 if (
const auto *Ex = dyn_cast<Expr>(S))
591 bugreporter::trackExpressionValue(N, Ex, *Report);
592 C.emitReport(std::move(Report));
596 void CStringChecker::emitOutOfBoundsBug(CheckerContext &C,
598 StringRef WarningMsg)
const {
599 if (ExplodedNode *N = C.generateErrorNode(
State)) {
601 BT_Bounds.reset(
new BuiltinBug(
602 Filter.CheckCStringOutOfBounds ?
Filter.CheckNameCStringOutOfBounds
603 :
Filter.CheckNameCStringNullArg,
604 "Out-of-bound array access",
605 "Byte string function accesses out-of-bound array element"));
607 BuiltinBug *BT =
static_cast<BuiltinBug *
>(BT_Bounds.get());
612 auto Report = std::make_unique<PathSensitiveBugReport>(*BT, WarningMsg, N);
614 C.emitReport(std::move(Report));
620 StringRef WarningMsg)
const {
621 if (ExplodedNode *N = C.generateNonFatalErrorNode(
State)) {
623 BT_NotCString.reset(
new BuiltinBug(
625 "Argument is not a null-terminated string."));
628 std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
631 C.emitReport(std::move(Report));
635 void CStringChecker::emitAdditionOverflowBug(CheckerContext &C,
637 if (ExplodedNode *N = C.generateErrorNode(State)) {
640 new BuiltinBug(
Filter.CheckNameCStringOutOfBounds,
"API",
641 "Sum of expressions causes overflow."));
646 const char *WarningMsg =
647 "This expression will create a string whose length is too big to " 648 "be represented as a size_t";
651 std::make_unique<PathSensitiveBugReport>(*BT_NotCString, WarningMsg, N);
652 C.emitReport(std::move(Report));
656 ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C,
659 NonLoc right)
const {
661 if (!
Filter.CheckCStringOutOfBounds)
668 SValBuilder &svalBuilder = C.getSValBuilder();
669 BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
671 QualType sizeTy = svalBuilder.getContext().getSizeType();
672 const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
673 NonLoc maxVal = svalBuilder.makeIntVal(maxValInt);
676 if (right.getAs<nonloc::ConcreteInt>()) {
677 maxMinusRight = svalBuilder.evalBinOpNN(
state, BO_Sub, maxVal, right,
682 maxMinusRight = svalBuilder.evalBinOpNN(
state, BO_Sub, maxVal, left,
688 QualType cmpTy = svalBuilder.getConditionType();
690 SVal willOverflow = svalBuilder.evalBinOpNN(
state, BO_GT, left,
691 *maxMinusRightNL, cmpTy);
694 std::tie(stateOverflow, stateOkay) =
695 state->assume(willOverflow.castAs<DefinedOrUnknownSVal>());
697 if (stateOverflow && !stateOkay) {
699 emitAdditionOverflowBug(C, stateOverflow);
714 assert(!strLength.isUndef() &&
"Attempt to set an undefined string length");
716 MR = MR->StripCasts();
718 switch (MR->getKind()) {
719 case MemRegion::StringRegionKind:
724 case MemRegion::SymbolicRegionKind:
725 case MemRegion::AllocaRegionKind:
726 case MemRegion::VarRegionKind:
727 case MemRegion::FieldRegionKind:
728 case MemRegion::ObjCIvarRegionKind:
732 case MemRegion::ElementRegionKind:
745 if (strLength.isUnknown())
746 return state->remove<CStringLength>(MR);
748 return state->set<CStringLength>(MR, strLength);
751 SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
758 const SVal *Recorded =
state->get<CStringLength>(MR);
764 SValBuilder &svalBuilder = C.getSValBuilder();
765 QualType sizeTy = svalBuilder.getContext().getSizeType();
766 SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(),
768 C.getLocationContext(),
774 BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
775 const llvm::APSInt &maxValInt = BVF.getMaxValue(sizeTy);
776 llvm::APSInt fourInt = APSIntType(maxValInt).getValue(4);
777 const llvm::APSInt *maxLengthInt = BVF.evalAPSInt(BO_Div, maxValInt,
779 NonLoc maxLength = svalBuilder.makeIntVal(*maxLengthInt);
780 SVal evalLength = svalBuilder.evalBinOpNN(
state, BO_LE, *strLn,
782 state =
state->assume(evalLength.castAs<DefinedOrUnknownSVal>(),
true);
784 state =
state->set<CStringLength>(MR, strLength);
791 const Expr *Ex, SVal Buf,
792 bool hypothetical)
const {
793 const MemRegion *MR = Buf.getAsRegion();
799 if (
Filter.CheckCStringNotNullTerm) {
801 llvm::raw_svector_ostream os(buf);
802 assert(CurrentFunctionDescription);
803 os <<
"Argument to " << CurrentFunctionDescription
804 <<
" is the address of the label '" <<
Label->getLabel()->getName()
805 <<
"', which is not a null-terminated string";
807 emitNotCStringBug(C,
state, Ex, os.str());
809 return UndefinedVal();
818 MR = MR->StripCasts();
820 switch (MR->getKind()) {
821 case MemRegion::StringRegionKind: {
824 SValBuilder &svalBuilder = C.getSValBuilder();
825 QualType sizeTy = svalBuilder.getContext().getSizeType();
826 const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
827 return svalBuilder.makeIntVal(strLit->
getByteLength(), sizeTy);
829 case MemRegion::SymbolicRegionKind:
830 case MemRegion::AllocaRegionKind:
831 case MemRegion::VarRegionKind:
832 case MemRegion::FieldRegionKind:
833 case MemRegion::ObjCIvarRegionKind:
834 return getCStringLengthForRegion(C,
state, Ex, MR, hypothetical);
835 case MemRegion::CompoundLiteralRegionKind:
838 case MemRegion::ElementRegionKind:
846 if (
Filter.CheckCStringNotNullTerm) {
848 llvm::raw_svector_ostream os(buf);
850 assert(CurrentFunctionDescription);
851 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
853 if (SummarizeRegion(os, C.getASTContext(), MR))
854 os <<
", which is not a null-terminated string";
856 os <<
"not a null-terminated string";
858 emitNotCStringBug(C,
state, Ex, os.str());
860 return UndefinedVal();
864 const StringLiteral *CStringChecker::getCStringLiteral(CheckerContext &C,
868 const MemRegion *bufRegion = val.getAsRegion();
873 bufRegion = bufRegion->StripCasts();
876 const StringRegion *strRegion= dyn_cast<StringRegion>(bufRegion);
881 return strRegion->getStringLiteral();
884 bool CStringChecker::IsFirstBufInBound(CheckerContext &C,
886 const Expr *FirstBuf,
893 SValBuilder &svalBuilder = C.getSValBuilder();
899 SVal BufVal =
state->getSVal(FirstBuf, LCtx);
901 SVal LengthVal =
state->getSVal(Size, LCtx);
907 NonLoc One = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
908 SVal
Offset = svalBuilder.evalBinOpNN(
state, BO_Sub, *Length, One, sizeTy);
909 if (Offset.isUnknown())
911 NonLoc LastOffset = Offset.castAs<NonLoc>();
914 SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->
getType());
920 svalBuilder.evalBinOpLN(
state, BO_Add, *BufLoc, LastOffset, PtrTy);
923 const MemRegion *R = BufEnd.getAsRegion();
927 const ElementRegion *ER = dyn_cast<ElementRegion>(R);
933 assert(ER->getValueType() == C.getASTContext().CharTy &&
934 "IsFirstBufInBound should only be called with char* ElementRegions");
937 const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
939 svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
940 DefinedOrUnknownSVal ExtentSize = Extent.castAs<DefinedOrUnknownSVal>();
943 DefinedOrUnknownSVal Idx = ER->getIndex().castAs<DefinedOrUnknownSVal>();
947 return static_cast<bool>(StInBound);
952 const Expr *E, SVal
V,
963 const MemRegion *R = MR->getRegion()->StripCasts();
967 if (
const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
968 R = ER->getSuperRegion();
973 const LocationContext *LCtx = C.getPredecessor()->getLocationContext();
975 bool CausesPointerEscape =
false;
976 RegionAndSymbolInvalidationTraits ITraits;
979 if (IsSourceBuffer) {
980 ITraits.setTrait(R->getBaseRegion(),
983 CausesPointerEscape =
true;
986 if (K == MemRegion::FieldRegionKind)
987 if (Size && IsFirstBufInBound(C,
state, E, Size)) {
996 return state->invalidateRegions(R, E, C.blockCount(), LCtx,
997 CausesPointerEscape,
nullptr,
nullptr,
1004 return state->killBinding(*L);
1007 bool CStringChecker::SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
1008 const MemRegion *MR) {
1009 switch (MR->getKind()) {
1010 case MemRegion::FunctionCodeRegionKind: {
1011 if (
const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl())
1012 os <<
"the address of the function '" << *FD <<
'\'';
1014 os <<
"the address of a function";
1017 case MemRegion::BlockCodeRegionKind:
1020 case MemRegion::BlockDataRegionKind:
1023 case MemRegion::CXXThisRegionKind:
1024 case MemRegion::CXXTempObjectRegionKind:
1025 os <<
"a C++ temp object of type " 1026 << cast<TypedValueRegion>(MR)->getValueType().getAsString();
1028 case MemRegion::VarRegionKind:
1029 os <<
"a variable of type" 1030 << cast<TypedValueRegion>(MR)->getValueType().getAsString();
1032 case MemRegion::FieldRegionKind:
1033 os <<
"a field of type " 1034 << cast<TypedValueRegion>(MR)->getValueType().getAsString();
1036 case MemRegion::ObjCIvarRegionKind:
1037 os <<
"an instance variable of type " 1038 << cast<TypedValueRegion>(MR)->getValueType().getAsString();
1045 bool CStringChecker::memsetAux(
const Expr *DstBuffer, SVal CharVal,
1046 const Expr *Size, CheckerContext &C,
1048 SVal MemVal = C.getSVal(DstBuffer);
1049 SVal SizeVal = C.getSVal(Size);
1050 const MemRegion *MR = MemVal.getAsRegion();
1058 RegionOffset
Offset = MR->getAsOffset();
1059 const MemRegion *BR = Offset.getRegion();
1065 SValBuilder &svalBuilder = C.getSValBuilder();
1070 if (Offset.isValid() && !Offset.hasSymbolicOffset() &&
1071 Offset.getOffset() == 0) {
1073 auto *SubReg = cast<SubRegion>(BR);
1074 DefinedOrUnknownSVal Extent = SubReg->getExtent(svalBuilder);
1077 std::tie(StateWholeReg, StateNotWholeReg) =
1078 State->assume(svalBuilder.evalEQ(State, Extent, *SizeNL));
1085 std::tie(StateNullChar, StateNonNullChar) =
1088 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1089 !StateNonNullChar) {
1096 State = State->bindDefaultZero(svalBuilder.makeLoc(BR),
1097 C.getLocationContext());
1101 State = InvalidateBuffer(C, State, DstBuffer, MemVal,
1105 if (StateNullChar && !StateNonNullChar) {
1108 State = setCStringLength(State, MR,
1110 }
else if (!StateNullChar && StateNonNullChar) {
1111 SVal NewStrLen = svalBuilder.getMetadataSymbolVal(
1112 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1113 C.getLocationContext(), C.blockCount());
1117 SVal NewStrLenGESize = svalBuilder.evalBinOp(
1118 State, BO_GE, NewStrLen, SizeVal, svalBuilder.getConditionType());
1120 State = setCStringLength(
1121 State->assume(NewStrLenGESize.castAs<DefinedOrUnknownSVal>(),
true),
1127 State = InvalidateBuffer(C, State, DstBuffer, MemVal,
1137 void CStringChecker::evalCopyCommon(CheckerContext &C,
1140 const Expr *Size,
const Expr *Dest,
1141 const Expr *Source,
bool Restricted,
1142 bool IsMempcpy)
const {
1143 CurrentFunctionDescription =
"memory copy function";
1147 SVal sizeVal =
state->getSVal(Size, LCtx);
1151 std::tie(stateZeroSize, stateNonZeroSize) =
1152 assumeZero(C,
state, sizeVal, sizeTy);
1155 SVal destVal =
state->getSVal(Dest, LCtx);
1159 if (stateZeroSize && !stateNonZeroSize) {
1160 stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal);
1161 C.addTransition(stateZeroSize);
1166 if (stateNonZeroSize) {
1167 state = stateNonZeroSize;
1171 state = checkNonNull(C,
state, Dest, destVal, 1);
1176 SVal srcVal =
state->getSVal(Source, LCtx);
1180 state = checkNonNull(C,
state, Source, srcVal, 2);
1185 const char *
const writeWarning =
1186 "Memory copy function overflows destination buffer";
1187 state = CheckBufferAccess(C,
state, Size, Dest, Source,
1188 writeWarning,
nullptr);
1190 state = CheckOverlap(C,
state, Size, Dest, Source);
1199 SValBuilder &SvalBuilder = C.getSValBuilder();
1202 SVal DestRegCharVal =
1203 SvalBuilder.evalCast(destVal, CharPtrTy, Dest->
getType());
1204 SVal lastElement = C.getSValBuilder().evalBinOp(
1205 state, BO_Add, DestRegCharVal, sizeVal, Dest->
getType());
1208 if (lastElement.isUnknown())
1209 lastElement = C.getSValBuilder().conjureSymbolVal(
nullptr, CE, LCtx,
1213 state =
state->BindExpr(CE, LCtx, lastElement);
1226 state = InvalidateBuffer(C,
state, Dest, C.getSVal(Dest),
1231 state = InvalidateBuffer(C, state, Source, C.getSVal(Source),
1234 C.addTransition(state);
1239 void CStringChecker::evalMemcpy(CheckerContext &C,
const CallExpr *CE)
const {
1245 evalCopyCommon(C, CE, state, CE->
getArg(2), Dest, CE->
getArg(1),
true);
1248 void CStringChecker::evalMempcpy(CheckerContext &C,
const CallExpr *CE)
const {
1254 evalCopyCommon(C, CE, state, CE->
getArg(2), Dest, CE->
getArg(1),
true,
true);
1257 void CStringChecker::evalMemmove(CheckerContext &C,
const CallExpr *CE)
const {
1263 evalCopyCommon(C, CE, state, CE->
getArg(2), Dest, CE->
getArg(1));
1266 void CStringChecker::evalBcopy(CheckerContext &C,
const CallExpr *CE)
const {
1268 evalCopyCommon(C, CE, C.getState(),
1272 void CStringChecker::evalMemcmp(CheckerContext &C,
const CallExpr *CE)
const {
1274 CurrentFunctionDescription =
"memory comparison function";
1281 SValBuilder &svalBuilder = C.getSValBuilder();
1285 SVal sizeVal = state->getSVal(Size, LCtx);
1289 std::tie(stateZeroSize, stateNonZeroSize) =
1290 assumeZero(C, state, sizeVal, sizeTy);
1294 if (stateZeroSize) {
1295 state = stateZeroSize;
1296 state = state->BindExpr(CE, LCtx,
1297 svalBuilder.makeZeroVal(CE->
getType()));
1298 C.addTransition(state);
1302 if (stateNonZeroSize) {
1303 state = stateNonZeroSize;
1307 DefinedOrUnknownSVal LV =
1308 state->getSVal(Left, LCtx).castAs<DefinedOrUnknownSVal>();
1309 DefinedOrUnknownSVal RV =
1310 state->getSVal(Right, LCtx).castAs<DefinedOrUnknownSVal>();
1313 DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
1315 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
1319 if (StSameBuf && !StNotSameBuf) {
1321 state = CheckBufferAccess(C, state, Size, Left);
1323 state = StSameBuf->BindExpr(CE, LCtx,
1324 svalBuilder.makeZeroVal(CE->
getType()));
1325 C.addTransition(state);
1332 assert(StNotSameBuf);
1333 state = CheckBufferAccess(C, state, Size, Left, Right);
1337 svalBuilder.conjureSymbolVal(
nullptr, CE, LCtx, C.blockCount());
1338 state = state->BindExpr(CE, LCtx, CmpV);
1339 C.addTransition(state);
1344 void CStringChecker::evalstrLength(CheckerContext &C,
1347 evalstrLengthCommon(C, CE,
false);
1350 void CStringChecker::evalstrnLength(CheckerContext &C,
1353 evalstrLengthCommon(C, CE,
true);
1356 void CStringChecker::evalstrLengthCommon(CheckerContext &C,
const CallExpr *CE,
1357 bool IsStrnlen)
const {
1358 CurrentFunctionDescription =
"string length function";
1364 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1367 std::tie(stateZeroSize, stateNonZeroSize) =
1368 assumeZero(C, state, maxlenVal, maxlenExpr->
getType());
1372 if (stateZeroSize) {
1373 SVal zero = C.getSValBuilder().makeZeroVal(CE->
getType());
1374 stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero);
1375 C.addTransition(stateZeroSize);
1379 if (!stateNonZeroSize)
1383 state = stateNonZeroSize;
1388 SVal ArgVal = state->getSVal(Arg, LCtx);
1390 state = checkNonNull(C, state, Arg, ArgVal, 1);
1395 SVal strLength = getCStringLength(C, state, Arg, ArgVal);
1399 if (strLength.isUndef())
1402 DefinedOrUnknownSVal result = UnknownVal();
1407 QualType cmpTy = C.getSValBuilder().getConditionType();
1412 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1417 if (strLengthNL && maxlenValNL) {
1421 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1423 .evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1424 .castAs<DefinedOrUnknownSVal>());
1426 if (stateStringTooLong && !stateStringNotTooLong) {
1428 result = *maxlenValNL;
1429 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1431 result = *strLengthNL;
1435 if (result.isUnknown()) {
1440 result = C.getSValBuilder().conjureSymbolVal(
nullptr, CE, LCtx,
1442 NonLoc resultNL = result.castAs<NonLoc>();
1445 state = state->assume(C.getSValBuilder().evalBinOpNN(
1446 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1447 .castAs<DefinedOrUnknownSVal>(),
true);
1451 state = state->assume(C.getSValBuilder().evalBinOpNN(
1452 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1453 .castAs<DefinedOrUnknownSVal>(),
true);
1459 result = strLength.castAs<DefinedOrUnknownSVal>();
1463 if (result.isUnknown()) {
1464 result = C.getSValBuilder().conjureSymbolVal(
nullptr, CE, LCtx,
1470 assert(!result.isUnknown() &&
"Should have conjured a value by now");
1471 state = state->BindExpr(CE, LCtx, result);
1472 C.addTransition(state);
1475 void CStringChecker::evalStrcpy(CheckerContext &C,
const CallExpr *CE)
const {
1477 evalStrcpyCommon(C, CE,
1480 ConcatFnKind::none);
1483 void CStringChecker::evalStrncpy(CheckerContext &C,
const CallExpr *CE)
const {
1485 evalStrcpyCommon(C, CE,
1488 ConcatFnKind::none);
1491 void CStringChecker::evalStpcpy(CheckerContext &C,
const CallExpr *CE)
const {
1493 evalStrcpyCommon(C, CE,
1496 ConcatFnKind::none);
1499 void CStringChecker::evalStrlcpy(CheckerContext &C,
const CallExpr *CE)
const {
1501 evalStrcpyCommon(C, CE,
1508 void CStringChecker::evalStrcat(CheckerContext &C,
const CallExpr *CE)
const {
1510 evalStrcpyCommon(C, CE,
1513 ConcatFnKind::strcat);
1516 void CStringChecker::evalStrncat(CheckerContext &C,
const CallExpr *CE)
const {
1518 evalStrcpyCommon(C, CE,
1521 ConcatFnKind::strcat);
1524 void CStringChecker::evalStrlcat(CheckerContext &C,
const CallExpr *CE)
const {
1528 evalStrcpyCommon(C, CE,
1531 ConcatFnKind::strlcat,
1535 void CStringChecker::evalStrcpyCommon(CheckerContext &C,
const CallExpr *CE,
1536 bool ReturnEnd,
bool IsBounded,
1538 bool returnPtr)
const {
1539 if (appendK == ConcatFnKind::none)
1540 CurrentFunctionDescription =
"string copy function";
1542 CurrentFunctionDescription =
"string concatenation function";
1548 SVal DstVal = state->getSVal(Dst, LCtx);
1550 state = checkNonNull(C, state, Dst, DstVal, 1);
1556 SVal srcVal = state->getSVal(srcExpr, LCtx);
1557 state = checkNonNull(C, state, srcExpr, srcVal, 2);
1562 SVal strLength = getCStringLength(C, state, srcExpr, srcVal);
1566 SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
1570 if (strLength.isUndef())
1573 SValBuilder &svalBuilder = C.getSValBuilder();
1574 QualType cmpTy = svalBuilder.getConditionType();
1575 QualType sizeTy = svalBuilder.getContext().getSizeType();
1580 SVal amountCopied = UnknownVal();
1581 SVal maxLastElementIndex = UnknownVal();
1582 const char *boundWarning =
nullptr;
1584 state = CheckOverlap(C, state, IsBounded ? CE->
getArg(2) : CE->
getArg(1), Dst,
1594 SVal lenVal = state->getSVal(lenExpr, LCtx);
1597 lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->
getType());
1603 if (strLengthNL && lenValNL) {
1605 case ConcatFnKind::none:
1606 case ConcatFnKind::strcat: {
1611 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1613 .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1614 .castAs<DefinedOrUnknownSVal>());
1616 if (stateSourceTooLong && !stateSourceNotTooLong) {
1619 state = stateSourceTooLong;
1620 amountCopied = lenVal;
1622 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1624 state = stateSourceNotTooLong;
1625 amountCopied = strLength;
1629 case ConcatFnKind::strlcat:
1630 if (!dstStrLengthNL)
1634 SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL,
1635 *dstStrLengthNL, sizeTy);
1636 if (!freeSpace.getAs<NonLoc>())
1639 svalBuilder.evalBinOp(state, BO_Sub, freeSpace,
1640 svalBuilder.makeIntVal(1, sizeTy), sizeTy);
1647 SVal hasEnoughSpace = svalBuilder.evalBinOpNN(
1648 state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy);
1651 std::tie(TrueState, FalseState) =
1652 state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>());
1655 if (TrueState && !FalseState) {
1656 amountCopied = strLength;
1660 if (!TrueState && FalseState) {
1661 amountCopied = freeSpace;
1664 if (TrueState && FalseState)
1665 amountCopied = UnknownVal();
1672 case ConcatFnKind::strcat:
1678 if (dstStrLength.isUndef())
1681 if (dstStrLengthNL) {
1682 maxLastElementIndex = svalBuilder.evalBinOpNN(
1683 state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy);
1685 boundWarning =
"Size argument is greater than the free space in the " 1686 "destination buffer";
1689 case ConcatFnKind::none:
1690 case ConcatFnKind::strlcat:
1700 std::tie(StateZeroSize, StateNonZeroSize) =
1701 assumeZero(C, state, *lenValNL, sizeTy);
1704 if (StateZeroSize && !StateNonZeroSize) {
1706 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal);
1708 if (appendK == ConcatFnKind::none) {
1710 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength);
1713 SVal retSize = svalBuilder.evalBinOp(
1714 state, BO_Add, strLength, dstStrLength, sizeTy);
1715 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize);
1718 C.addTransition(StateZeroSize);
1725 NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>();
1726 maxLastElementIndex =
1727 svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy);
1728 boundWarning =
"Size argument is greater than the length of the " 1729 "destination buffer";
1736 amountCopied = strLength;
1744 SVal finalStrLength = UnknownVal();
1745 SVal strlRetVal = UnknownVal();
1747 if (appendK == ConcatFnKind::none && !returnPtr) {
1749 strlRetVal = strLength;
1755 if (appendK != ConcatFnKind::none) {
1758 if (dstStrLength.isUndef())
1761 if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) {
1762 strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL,
1763 *dstStrLengthNL, sizeTy);
1769 if (amountCopiedNL && dstStrLengthNL) {
1771 state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL);
1775 finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL,
1776 *dstStrLengthNL, sizeTy);
1781 if (finalStrLength.isUnknown()) {
1784 finalStrLength = getCStringLength(C, state, CE, DstVal,
true);
1785 assert(!finalStrLength.isUndef());
1788 if (amountCopiedNL && appendK == ConcatFnKind::none) {
1791 SVal sourceInResult = svalBuilder.evalBinOpNN(
1792 state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy);
1793 state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(),
1799 if (dstStrLengthNL && appendK != ConcatFnKind::none) {
1802 SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE,
1807 state->assume(destInResult.castAs<DefinedOrUnknownSVal>(),
true);
1817 finalStrLength = amountCopied;
1825 Result = (ReturnEnd ? UnknownVal() : DstVal);
1827 if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none)
1829 Result = strlRetVal;
1831 Result = finalStrLength;
1839 DstVal.getAs<loc::MemRegionVal>()) {
1846 SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
1848 state = CheckLocation(C, state, CE->
getArg(2), maxLastElement,
1857 SVal lastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal,
1858 *knownStrLength, ptrTy);
1861 if (!boundWarning) {
1862 const char *
const warningMsg =
1863 "String copy function overflows destination buffer";
1864 state = CheckLocation(C, state, Dst, lastElement, warningMsg);
1870 if (returnPtr && ReturnEnd)
1871 Result = lastElement;
1881 state = InvalidateBuffer(C, state, Dst, *dstRegVal,
1886 state = InvalidateBuffer(C, state, srcExpr, srcVal,
true,
1890 if (IsBounded && (appendK == ConcatFnKind::none)) {
1895 if (amountCopied != strLength)
1896 finalStrLength = UnknownVal();
1898 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
1906 if (ReturnEnd && Result.isUnknown()) {
1907 Result = svalBuilder.conjureSymbolVal(
nullptr, CE, LCtx, C.blockCount());
1911 state = state->BindExpr(CE, LCtx, Result);
1912 C.addTransition(state);
1915 void CStringChecker::evalStrcmp(CheckerContext &C,
const CallExpr *CE)
const {
1917 evalStrcmpCommon(C, CE,
false,
false);
1920 void CStringChecker::evalStrncmp(CheckerContext &C,
const CallExpr *CE)
const {
1922 evalStrcmpCommon(C, CE,
true,
false);
1925 void CStringChecker::evalStrcasecmp(CheckerContext &C,
1928 evalStrcmpCommon(C, CE,
false,
true);
1931 void CStringChecker::evalStrncasecmp(CheckerContext &C,
1934 evalStrcmpCommon(C, CE,
true,
true);
1937 void CStringChecker::evalStrcmpCommon(CheckerContext &C,
const CallExpr *CE,
1938 bool IsBounded,
bool IgnoreCase)
const {
1939 CurrentFunctionDescription =
"string comparison function";
1945 SVal s1Val = state->getSVal(s1, LCtx);
1946 state = checkNonNull(C, state, s1, s1Val, 1);
1952 SVal s2Val = state->getSVal(s2, LCtx);
1953 state = checkNonNull(C, state, s2, s2Val, 2);
1958 SVal s1Length = getCStringLength(C, state, s1, s1Val);
1959 if (s1Length.isUndef())
1963 SVal s2Length = getCStringLength(C, state, s2, s2Val);
1964 if (s2Length.isUndef())
1970 DefinedOrUnknownSVal LV = s1Val.castAs<DefinedOrUnknownSVal>();
1971 DefinedOrUnknownSVal RV = s2Val.castAs<DefinedOrUnknownSVal>();
1974 SValBuilder &svalBuilder = C.getSValBuilder();
1975 DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
1977 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
1982 StSameBuf = StSameBuf->BindExpr(CE, LCtx,
1983 svalBuilder.makeZeroVal(CE->
getType()));
1984 C.addTransition(StSameBuf);
1991 assert(StNotSameBuf);
1992 state = StNotSameBuf;
1998 const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val);
1999 const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val);
2000 bool canComputeResult =
false;
2001 SVal resultVal = svalBuilder.conjureSymbolVal(
nullptr, CE, LCtx,
2004 if (s1StrLiteral && s2StrLiteral) {
2005 StringRef s1StrRef = s1StrLiteral->
getString();
2006 StringRef s2StrRef = s2StrLiteral->
getString();
2011 SVal lenVal = state->getSVal(lenExpr, LCtx);
2014 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
2016 s1StrRef = s1StrRef.substr(0, (
size_t)len->getZExtValue());
2017 s2StrRef = s2StrRef.substr(0, (
size_t)len->getZExtValue());
2018 canComputeResult =
true;
2022 canComputeResult =
true;
2025 if (canComputeResult) {
2027 size_t s1Term = s1StrRef.find(
'\0');
2028 if (s1Term != StringRef::npos)
2029 s1StrRef = s1StrRef.substr(0, s1Term);
2031 size_t s2Term = s2StrRef.find(
'\0');
2032 if (s2Term != StringRef::npos)
2033 s2StrRef = s2StrRef.substr(0, s2Term);
2036 int compareRes = IgnoreCase ? s1StrRef.compare_lower(s2StrRef)
2037 : s1StrRef.compare(s2StrRef);
2041 if (compareRes == 0) {
2042 resultVal = svalBuilder.makeIntVal(compareRes, CE->
getType());
2045 DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->
getType());
2049 SVal compareWithZero =
2050 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2051 svalBuilder.getConditionType());
2052 DefinedSVal compareWithZeroVal = compareWithZero.castAs<DefinedSVal>();
2053 state = state->assume(compareWithZeroVal,
true);
2058 state = state->BindExpr(CE, LCtx, resultVal);
2061 C.addTransition(state);
2064 void CStringChecker::evalStrsep(CheckerContext &C,
const CallExpr *CE)
const {
2069 if (CharPtrTy.
isNull() ||
2073 CurrentFunctionDescription =
"strsep()";
2079 SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx);
2080 State = checkNonNull(C, State, SearchStrPtr, SearchStrVal, 1);
2086 SVal DelimStrVal = State->getSVal(DelimStr, LCtx);
2087 State = checkNonNull(C, State, DelimStr, DelimStrVal, 2);
2091 SValBuilder &SVB = C.getSValBuilder();
2093 if (
Optional<Loc> SearchStrLoc = SearchStrVal.getAs<Loc>()) {
2095 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2099 State = InvalidateBuffer(C, State, SearchStrPtr, Result,
2104 State = State->bindLoc(*SearchStrLoc,
2105 SVB.conjureSymbolVal(getTag(),
2112 assert(SearchStrVal.isUnknown());
2114 Result = SVB.conjureSymbolVal(
nullptr, CE, LCtx, C.blockCount());
2118 State = State->BindExpr(CE, LCtx, Result);
2119 C.addTransition(State);
2123 void CStringChecker::evalStdCopy(CheckerContext &C,
const CallExpr *CE)
const {
2124 evalStdCopyCommon(C, CE);
2127 void CStringChecker::evalStdCopyBackward(CheckerContext &C,
2129 evalStdCopyCommon(C, CE);
2132 void CStringChecker::evalStdCopyCommon(CheckerContext &C,
2148 SVal DstVal = State->getSVal(Dst, LCtx);
2149 State = InvalidateBuffer(C, State, Dst, DstVal,
false,
2152 SValBuilder &SVB = C.getSValBuilder();
2154 SVal ResultVal = SVB.conjureSymbolVal(
nullptr, CE, LCtx, C.blockCount());
2155 State = State->BindExpr(CE, LCtx, ResultVal);
2157 C.addTransition(State);
2160 void CStringChecker::evalMemset(CheckerContext &C,
const CallExpr *CE)
const {
2161 CurrentFunctionDescription =
"memory set function";
2170 SVal SizeVal = State->getSVal(Size, LCtx);
2174 std::tie(StateZeroSize, StateNonZeroSize) =
2175 assumeZero(C, State, SizeVal, SizeTy);
2178 SVal MemVal = State->getSVal(Mem, LCtx);
2182 if (StateZeroSize && !StateNonZeroSize) {
2183 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal);
2184 C.addTransition(StateZeroSize);
2190 State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1);
2194 State = CheckBufferAccess(C, State, Size, Mem);
2201 if (!memsetAux(Mem, C.getSVal(CharE), Size, C,
State))
2204 State = State->BindExpr(CE, LCtx, MemVal);
2205 C.addTransition(State);
2208 void CStringChecker::evalBzero(CheckerContext &C,
const CallExpr *CE)
const {
2209 CurrentFunctionDescription =
"memory clearance function";
2213 SVal
Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy);
2218 SVal SizeVal = C.getSVal(Size);
2222 std::tie(StateZeroSize, StateNonZeroSize) =
2223 assumeZero(C, State, SizeVal, SizeTy);
2227 if (StateZeroSize && !StateNonZeroSize) {
2228 C.addTransition(StateZeroSize);
2233 SVal MemVal = C.getSVal(Mem);
2237 State = checkNonNull(C, StateNonZeroSize, Mem, MemVal, 1);
2241 State = CheckBufferAccess(C, State, Size, Mem);
2245 if (!memsetAux(Mem, Zero, Size, C, State))
2248 C.addTransition(State);
2255 CStringChecker::FnCheck CStringChecker::identifyCall(
const CallEvent &Call,
2256 CheckerContext &C)
const {
2257 const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
2261 const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Call.getDecl());
2265 if (Call.isCalled(StdCopy)) {
2266 return &CStringChecker::evalStdCopy;
2267 }
else if (Call.isCalled(StdCopyBackward)) {
2268 return &CStringChecker::evalStdCopyBackward;
2281 const FnCheck *Callback = Callbacks.lookup(Call);
2288 bool CStringChecker::evalCall(
const CallEvent &Call, CheckerContext &C)
const {
2289 FnCheck Callback = identifyCall(Call, C);
2296 const auto *CE = cast<CallExpr>(Call.getOriginExpr());
2297 (this->*Callback)(C, CE);
2305 return C.isDifferent();
2308 void CStringChecker::checkPreStmt(
const DeclStmt *DS, CheckerContext &C)
const {
2312 for (
const auto *I : DS->
decls()) {
2324 if (!isa<StringLiteral>(Init))
2327 Loc VarLoc = state->getLValue(D, C.getLocationContext());
2328 const MemRegion *MR = VarLoc.getAsRegion();
2332 SVal StrVal = C.getSVal(Init);
2333 assert(StrVal.isValid() &&
"Initializer string is unknown or undefined");
2334 DefinedOrUnknownSVal strLength =
2335 getCStringLength(C, state, Init, StrVal).castAs<DefinedOrUnknownSVal>();
2337 state = state->set<CStringLength>(MR, strLength);
2340 C.addTransition(state);
2350 CStringLengthTy Entries =
state->get<CStringLength>();
2351 if (Entries.isEmpty())
2354 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2355 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2359 I = Regions.begin(), E = Regions.end(); I != E; ++I) {
2360 const MemRegion *MR = *I;
2361 Invalidated.insert(MR);
2363 SuperRegions.insert(MR);
2364 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2365 MR = SR->getSuperRegion();
2366 SuperRegions.insert(MR);
2370 CStringLengthTy::Factory &F =
state->get_context<CStringLength>();
2373 for (CStringLengthTy::iterator I = Entries.begin(),
2374 E = Entries.end(); I != E; ++I) {
2375 const MemRegion *MR = I.getKey();
2378 if (SuperRegions.count(MR)) {
2379 Entries = F.remove(Entries, MR);
2384 const MemRegion *Super = MR;
2385 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2386 Super = SR->getSuperRegion();
2387 if (Invalidated.count(Super)) {
2388 Entries = F.remove(Entries, MR);
2394 return state->set<CStringLength>(Entries);
2398 SymbolReaper &SR)
const {
2400 CStringLengthTy Entries =
state->get<CStringLength>();
2402 for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
2404 SVal Len = I.getData();
2406 for (SymExpr::symbol_iterator si = Len.symbol_begin(),
2407 se = Len.symbol_end(); si != se; ++si)
2412 void CStringChecker::checkDeadSymbols(SymbolReaper &SR,
2413 CheckerContext &C)
const {
2415 CStringLengthTy Entries = state->get<CStringLength>();
2416 if (Entries.isEmpty())
2419 CStringLengthTy::Factory &F = state->get_context<CStringLength>();
2420 for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
2422 SVal Len = I.getData();
2423 if (
SymbolRef Sym = Len.getAsSymbol()) {
2425 Entries = F.remove(Entries, I.getKey());
2429 state = state->set<CStringLength>(Entries);
2430 C.addTransition(state);
2433 void ento::registerCStringModeling(CheckerManager &Mgr) {
2434 Mgr.registerChecker<CStringChecker>();
2437 bool ento::shouldRegisterCStringModeling(
const LangOptions &LO) {
2441 #define REGISTER_CHECKER(name) \ 2442 void ento::register##name(CheckerManager &mgr) { \ 2443 CStringChecker *checker = mgr.getChecker<CStringChecker>(); \ 2444 checker->Filter.Check##name = true; \ 2445 checker->Filter.CheckName##name = mgr.getCurrentCheckerName(); \ 2448 bool ento::shouldRegister##name(const LangOptions &LO) { return true; } Suppress pointer-escaping of a region.
Represents a function declaration or definition.
A (possibly-)qualified type.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
Stmt - This represents one statement.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
Represents a variable declaration or definition.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
const char *const UnixAPI
const SymExpr * SymbolRef
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
bool Zero(InterpState &S, CodePtr OpPC)
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
i32 captured_struct **param SharedsTy A type which contains references the shared variables *param Shareds Context with the list of shared variables from the p *TaskFunction *param Data Additional data for task generation like final * state
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
This class represents a description of a function call using the number of arguments and the name of ...
CanQualType UnsignedCharTy
StringRef getString() const
#define REGISTER_CHECKER(name)
This represents one expression.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
Tells that a region's contents is not changed.
Dataflow Directional Tag Classes.
const Expr * getInit() const
Describes a C standard function that is sometimes implemented as a macro that expands to a compiler b...
unsigned getByteLength() const
Indicates that the tracking object is a descendant of a referenced-counted OSObject, used in the Darwin kernel.
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
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.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
An immutable map from CallDescriptions to arbitrary data.
bool isPointerType() const
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.