23 #include "llvm/ADT/STLExtras.h" 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/Support/raw_ostream.h" 27 using namespace clang;
31 class CStringChecker :
public Checker< eval::Call,
32 check::PreStmt<DeclStmt>,
37 mutable std::unique_ptr<BugType> BT_Null, BT_Bounds, BT_Overlap,
38 BT_NotCString, BT_AdditionOverflow;
40 mutable const char *CurrentFunctionDescription;
45 struct CStringChecksFilter {
57 CStringChecksFilter Filter;
59 static void *getTag() {
static int tag;
return &tag; }
77 void evalMemcpy(CheckerContext &C,
const CallExpr *CE)
const;
78 void evalMempcpy(CheckerContext &C,
const CallExpr *CE)
const;
79 void evalMemmove(CheckerContext &C,
const CallExpr *CE)
const;
80 void evalBcopy(CheckerContext &C,
const CallExpr *CE)
const;
81 void evalCopyCommon(CheckerContext &C,
const CallExpr *CE,
86 bool Restricted =
false,
87 bool IsMempcpy =
false)
const;
89 void evalMemcmp(CheckerContext &C,
const CallExpr *CE)
const;
91 void evalstrLength(CheckerContext &C,
const CallExpr *CE)
const;
92 void evalstrnLength(CheckerContext &C,
const CallExpr *CE)
const;
93 void evalstrLengthCommon(CheckerContext &C,
95 bool IsStrnlen =
false)
const;
97 void evalStrcpy(CheckerContext &C,
const CallExpr *CE)
const;
98 void evalStrncpy(CheckerContext &C,
const CallExpr *CE)
const;
99 void evalStpcpy(CheckerContext &C,
const CallExpr *CE)
const;
100 void evalStrlcpy(CheckerContext &C,
const CallExpr *CE)
const;
101 void evalStrcpyCommon(CheckerContext &C,
106 bool returnPtr =
true)
const;
108 void evalStrcat(CheckerContext &C,
const CallExpr *CE)
const;
109 void evalStrncat(CheckerContext &C,
const CallExpr *CE)
const;
110 void evalStrlcat(CheckerContext &C,
const CallExpr *CE)
const;
112 void evalStrcmp(CheckerContext &C,
const CallExpr *CE)
const;
113 void evalStrncmp(CheckerContext &C,
const CallExpr *CE)
const;
114 void evalStrcasecmp(CheckerContext &C,
const CallExpr *CE)
const;
115 void evalStrncasecmp(CheckerContext &C,
const CallExpr *CE)
const;
116 void evalStrcmpCommon(CheckerContext &C,
118 bool isBounded =
false,
119 bool ignoreCase =
false)
const;
121 void evalStrsep(CheckerContext &C,
const CallExpr *CE)
const;
123 void evalStdCopy(CheckerContext &C,
const CallExpr *CE)
const;
124 void evalStdCopyBackward(CheckerContext &C,
const CallExpr *CE)
const;
125 void evalStdCopyCommon(CheckerContext &C,
const CallExpr *CE)
const;
126 void evalMemset(CheckerContext &C,
const CallExpr *CE)
const;
129 std::pair<ProgramStateRef , ProgramStateRef >
130 static assumeZero(CheckerContext &C,
136 static SVal getCStringLengthForRegion(CheckerContext &C,
141 SVal getCStringLength(CheckerContext &C,
145 bool hypothetical =
false)
const;
158 static bool SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
161 static bool memsetAux(
const Expr *DstBuffer,
const Expr *CharE,
162 const Expr *Size, CheckerContext &C,
174 const char *message =
nullptr)
const;
178 const Expr *FirstBuf,
179 const Expr *SecondBuf,
180 const char *firstMessage =
nullptr,
181 const char *secondMessage =
nullptr,
182 bool WarnAboutSize =
false)
const;
188 const char *message =
nullptr,
189 bool WarnAboutSize =
false)
const {
191 return CheckBufferAccess(C, state, Size, Buf,
nullptr, message,
nullptr,
198 const Expr *Second)
const;
199 void emitOverlapBug(CheckerContext &C,
202 const Stmt *Second)
const;
205 StringRef WarningMsg)
const;
207 const Stmt *S, StringRef WarningMsg)
const;
209 const Stmt *S, StringRef WarningMsg)
const;
220 static bool IsFirstBufInBound(CheckerContext &C,
222 const Expr *FirstBuf,
234 std::pair<ProgramStateRef , ProgramStateRef >
239 return std::pair<ProgramStateRef , ProgramStateRef >(
state,
state);
243 return state->assume(svalBuilder.evalEQ(state, *val, zero));
254 std::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->
getType());
256 if (stateNull && !stateNonNull) {
257 if (Filter.CheckCStringNullArg) {
259 llvm::raw_svector_ostream os(buf);
260 assert(CurrentFunctionDescription);
261 os <<
"Null pointer argument in call to " << CurrentFunctionDescription;
263 emitNullArgBug(C, stateNull, S, os.str());
269 assert(stateNonNull);
277 const char *warningMsg)
const {
298 svalBuilder.convertToArrayIndex(superReg->
getExtent(svalBuilder));
306 if (StOutBound && !StInBound) {
310 if (!Filter.CheckCStringOutOfBounds)
314 emitOutOfBoundsBug(C, StOutBound, S, warningMsg);
316 assert(CurrentFunctionDescription);
317 assert(CurrentFunctionDescription[0] !=
'\0');
320 llvm::raw_svector_ostream os(buf);
322 << &CurrentFunctionDescription[1]
323 <<
" accesses out-of-bound array element";
324 emitOutOfBoundsBug(C, StOutBound, S, os.str());
337 const Expr *FirstBuf,
338 const Expr *SecondBuf,
339 const char *firstMessage,
340 const char *secondMessage,
341 bool WarnAboutSize)
const {
355 state = checkNonNull(C, state, FirstBuf, BufVal);
360 if (!Filter.CheckCStringOutOfBounds)
374 if (Offset.isUnknown())
381 const Expr *warningExpr = (WarnAboutSize ? Size : FirstBuf);
385 state = CheckLocation(C, state, warningExpr, BufEnd, firstMessage);
394 BufVal = state->getSVal(SecondBuf, LCtx);
395 state = checkNonNull(C, state, SecondBuf, BufVal);
401 const Expr *warningExpr = (WarnAboutSize ? Size : SecondBuf);
405 state = CheckLocation(C, state, warningExpr, BufEnd, secondMessage);
417 const Expr *Second)
const {
418 if (!Filter.CheckCStringBufferOverlap)
433 SVal firstVal = state->getSVal(First, LCtx);
434 SVal secondVal = state->getSVal(Second, LCtx);
446 std::tie(stateTrue, stateFalse) =
447 state->assume(svalBuilder.
evalEQ(state, *firstLoc, *secondLoc));
449 if (stateTrue && !stateFalse) {
451 emitOverlapBug(C, stateTrue, First, Second);
462 *firstLoc, *secondLoc, cmpTy);
468 std::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
475 std::swap(firstLoc, secondLoc);
478 std::swap(First, Second);
483 SVal LengthVal = state->getSVal(Size, LCtx);
492 SVal FirstStart = svalBuilder.
evalCast(*firstLoc, CharPtrTy,
500 *FirstStartLoc, *Length, CharPtrTy);
507 *FirstEndLoc, *secondLoc, cmpTy);
513 std::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
515 if (stateTrue && !stateFalse) {
517 emitOverlapBug(C, stateTrue, First, Second);
527 const Stmt *First,
const Stmt *Second)
const {
533 BT_Overlap.reset(
new BugType(Filter.CheckNameCStringBufferOverlap,
537 auto report = llvm::make_unique<BugReport>(
538 *BT_Overlap,
"Arguments must not be overlapping buffers", N);
546 const Stmt *S, StringRef WarningMsg)
const {
551 "Null pointer argument in call to byte string function"));
554 auto Report = llvm::make_unique<BugReport>(*BT, WarningMsg, N);
556 bugreporter::trackNullOrUndefValue(N, S, *Report);
563 StringRef WarningMsg)
const {
567 Filter.CheckCStringOutOfBounds ? Filter.CheckNameCStringOutOfBounds
568 : Filter.CheckNameCStringNullArg,
569 "Out-of-bound array access",
570 "Byte string function accesses out-of-bound array element"));
577 auto Report = llvm::make_unique<BugReport>(*BT, WarningMsg, N);
585 StringRef WarningMsg)
const {
590 "Argument is not a null-terminated string."));
592 auto Report = llvm::make_unique<BugReport>(*BT_NotCString, WarningMsg, N);
604 new BuiltinBug(Filter.CheckNameCStringOutOfBounds,
"API",
605 "Sum of expressions causes overflow."));
610 const char *WarningMsg =
611 "This expression will create a string whose length is too big to " 612 "be represented as a size_t";
614 auto Report = llvm::make_unique<BugReport>(*BT_NotCString, WarningMsg, N);
624 if (!Filter.CheckCStringOutOfBounds)
635 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
640 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, right,
645 maxMinusRight = svalBuilder.
evalBinOpNN(state, BO_Sub, maxVal, left,
654 *maxMinusRightNL, cmpTy);
657 std::tie(stateOverflow, stateOkay) =
660 if (stateOverflow && !stateOkay) {
662 emitAdditionOverflowBug(C, stateOverflow);
677 assert(!strLength.
isUndef() &&
"Attempt to set an undefined string length");
681 switch (MR->getKind()) {
682 case MemRegion::StringRegionKind:
687 case MemRegion::SymbolicRegionKind:
688 case MemRegion::AllocaRegionKind:
689 case MemRegion::VarRegionKind:
690 case MemRegion::FieldRegionKind:
691 case MemRegion::ObjCIvarRegionKind:
695 case MemRegion::ElementRegionKind:
709 return state->remove<CStringLength>(MR);
711 return state->set<CStringLength>(MR, strLength);
721 const SVal *Recorded = state->get<CStringLength>(MR);
738 const llvm::APSInt &maxValInt = BVF.
getMaxValue(sizeTy);
740 const llvm::APSInt *maxLengthInt = BVF.
evalAPSInt(BO_Div, maxValInt,
747 state = state->set<CStringLength>(MR, strLength);
755 bool hypothetical)
const {
762 if (Filter.CheckCStringNotNullTerm) {
764 llvm::raw_svector_ostream os(buf);
765 assert(CurrentFunctionDescription);
766 os <<
"Argument to " << CurrentFunctionDescription
767 <<
" is the address of the label '" <<
Label->getLabel()->getName()
768 <<
"', which is not a null-terminated string";
770 emitNotCStringBug(C, state, Ex, os.str());
784 case MemRegion::StringRegionKind: {
789 const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
792 case MemRegion::SymbolicRegionKind:
793 case MemRegion::AllocaRegionKind:
794 case MemRegion::VarRegionKind:
795 case MemRegion::FieldRegionKind:
796 case MemRegion::ObjCIvarRegionKind:
797 return getCStringLengthForRegion(C, state, Ex, MR, hypothetical);
798 case MemRegion::CompoundLiteralRegionKind:
801 case MemRegion::ElementRegionKind:
809 if (Filter.CheckCStringNotNullTerm) {
811 llvm::raw_svector_ostream os(buf);
813 assert(CurrentFunctionDescription);
814 os <<
"Argument to " << CurrentFunctionDescription <<
" is ";
817 os <<
", which is not a null-terminated string";
819 os <<
"not a null-terminated string";
821 emitNotCStringBug(C, state, Ex, os.str());
849 const Expr *FirstBuf,
862 SVal BufVal = state->getSVal(FirstBuf, LCtx);
864 SVal LengthVal = state->getSVal(Size, LCtx);
871 SVal Offset = svalBuilder.
evalBinOpNN(state, BO_Sub, *Length, One, sizeTy);
872 if (Offset.isUnknown())
883 svalBuilder.
evalBinOpLN(state, BO_Add, *BufLoc, LastOffset, PtrTy);
897 "IsFirstBufInBound should only be called with char* ElementRegions");
908 ProgramStateRef StInBound = state->assumeInBound(Idx, ExtentSize,
true);
910 return static_cast<bool>(StInBound);
938 bool CausesPointerEscape =
false;
942 if (IsSourceBuffer) {
946 CausesPointerEscape =
true;
949 if (K == MemRegion::FieldRegionKind)
950 if (Size && IsFirstBufInBound(C, state, E, Size)) {
959 return state->invalidateRegions(R, E, C.
blockCount(), LCtx,
960 CausesPointerEscape,
nullptr,
nullptr,
967 return state->killBinding(*L);
970 bool CStringChecker::SummarizeRegion(raw_ostream &os,
ASTContext &Ctx,
975 case MemRegion::FunctionCodeRegionKind: {
976 const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl();
978 os <<
"the address of the function '" << *FD <<
'\'';
980 os <<
"the address of a function";
983 case MemRegion::BlockCodeRegionKind:
986 case MemRegion::BlockDataRegionKind:
989 case MemRegion::CXXThisRegionKind:
990 case MemRegion::CXXTempObjectRegionKind:
993 case MemRegion::VarRegionKind:
996 case MemRegion::FieldRegionKind:
999 case MemRegion::ObjCIvarRegionKind:
1007 bool CStringChecker::memsetAux(
const Expr *DstBuffer,
const Expr *CharE,
1036 auto *SubReg = cast<SubRegion>(BR);
1040 std::tie(StateWholeReg, StateNotWholeReg) =
1041 State->assume(svalBuilder.
evalEQ(State, Extent, *SizeNL));
1048 std::tie(StateNullChar, StateNonNullChar) =
1051 if (StateWholeReg && !StateNotWholeReg && StateNullChar &&
1052 !StateNonNullChar) {
1059 State = State->bindDefaultZero(svalBuilder.
makeLoc(BR),
1064 State = InvalidateBuffer(C, State, DstBuffer, MemVal,
1068 if (StateNullChar && !StateNonNullChar) {
1071 State = setCStringLength(State, MR,
1073 }
else if (!StateNullChar && StateNonNullChar) {
1075 CStringChecker::getTag(), MR, DstBuffer, Ctx.
getSizeType(),
1083 State = setCStringLength(
1090 State = InvalidateBuffer(C, State, DstBuffer, MemVal,
1103 const Expr *Size,
const Expr *Dest,
1104 const Expr *Source,
bool Restricted,
1105 bool IsMempcpy)
const {
1106 CurrentFunctionDescription =
"memory copy function";
1110 SVal sizeVal = state->getSVal(Size, LCtx);
1114 std::tie(stateZeroSize, stateNonZeroSize) =
1115 assumeZero(C, state, sizeVal, sizeTy);
1118 SVal destVal = state->getSVal(Dest, LCtx);
1122 if (stateZeroSize && !stateNonZeroSize) {
1123 stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal);
1129 if (stateNonZeroSize) {
1130 state = stateNonZeroSize;
1134 state = checkNonNull(C, state, Dest, destVal);
1139 SVal srcVal = state->getSVal(Source, LCtx);
1143 state = checkNonNull(C, state, Source, srcVal);
1148 const char *
const writeWarning =
1149 "Memory copy function overflows destination buffer";
1150 state = CheckBufferAccess(C, state, Size, Dest, Source,
1151 writeWarning,
nullptr);
1153 state = CheckOverlap(C, state, Size, Dest, Source);
1165 SVal DestRegCharVal =
1168 state, BO_Add, DestRegCharVal, sizeVal, Dest->
getType());
1176 state = state->BindExpr(CE, LCtx, lastElement);
1180 state = state->BindExpr(CE, LCtx, destVal);
1189 state = InvalidateBuffer(C, state, Dest, C.
getSVal(Dest),
1194 state = InvalidateBuffer(C, state, Source, C.
getSVal(Source),
1211 evalCopyCommon(C, CE, state, CE->
getArg(2), Dest, CE->
getArg(1),
true);
1223 evalCopyCommon(C, CE, state, CE->
getArg(2), Dest, CE->
getArg(1),
true,
true);
1235 evalCopyCommon(C, CE, state, CE->
getArg(2), Dest, CE->
getArg(1));
1243 evalCopyCommon(C, CE, C.
getState(),
1252 CurrentFunctionDescription =
"memory comparison function";
1263 SVal sizeVal = state->getSVal(Size, LCtx);
1267 std::tie(stateZeroSize, stateNonZeroSize) =
1268 assumeZero(C, state, sizeVal, sizeTy);
1272 if (stateZeroSize) {
1273 state = stateZeroSize;
1274 state = state->BindExpr(CE, LCtx,
1280 if (stateNonZeroSize) {
1281 state = stateNonZeroSize;
1293 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
1299 state = CheckBufferAccess(C, state, Size, Left);
1301 state = StSameBuf->BindExpr(CE, LCtx,
1310 state = StNotSameBuf;
1311 state = CheckBufferAccess(C, state, Size, Left, Right);
1316 state = state->BindExpr(CE, LCtx, CmpV);
1329 evalstrLengthCommon(C, CE,
false);
1338 evalstrLengthCommon(C, CE,
true);
1342 bool IsStrnlen)
const {
1343 CurrentFunctionDescription =
"string length function";
1349 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1352 std::tie(stateZeroSize, stateNonZeroSize) =
1353 assumeZero(C, state, maxlenVal, maxlenExpr->
getType());
1357 if (stateZeroSize) {
1359 stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero);
1364 if (!stateNonZeroSize)
1368 state = stateNonZeroSize;
1373 SVal ArgVal = state->getSVal(Arg, LCtx);
1375 state = checkNonNull(C, state, Arg, ArgVal);
1380 SVal strLength = getCStringLength(C, state, Arg, ArgVal);
1397 SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
1402 if (strLengthNL && maxlenValNL) {
1406 std::tie(stateStringTooLong, stateStringNotTooLong) = state->assume(
1408 .
evalBinOpNN(state, BO_GT, *strLengthNL, *maxlenValNL, cmpTy)
1411 if (stateStringTooLong && !stateStringNotTooLong) {
1413 result = *maxlenValNL;
1414 }
else if (stateStringNotTooLong && !stateStringTooLong) {
1416 result = *strLengthNL;
1431 state, BO_LE, resultNL, *strLengthNL, cmpTy)
1437 state, BO_LE, resultNL, *maxlenValNL, cmpTy)
1455 assert(!result.
isUnknown() &&
"Should have conjured a value by now");
1456 state = state->BindExpr(CE, LCtx, result);
1465 evalStrcpyCommon(C, CE,
1476 evalStrcpyCommon(C, CE,
1487 evalStrcpyCommon(C, CE,
1498 evalStrcpyCommon(C, CE,
1510 evalStrcpyCommon(C, CE,
1521 evalStrcpyCommon(C, CE,
1532 evalStrcpyCommon(C, CE,
1540 bool returnEnd,
bool isBounded,
1541 bool isAppending,
bool returnPtr)
const {
1542 CurrentFunctionDescription =
"string copy function";
1548 SVal DstVal = state->getSVal(Dst, LCtx);
1550 state = checkNonNull(C, state, Dst, DstVal);
1556 SVal srcVal = state->getSVal(srcExpr, LCtx);
1557 state = checkNonNull(C, state, srcExpr, srcVal);
1562 SVal strLength = getCStringLength(C, state, srcExpr, srcVal);
1577 const char *boundWarning =
nullptr;
1579 state = CheckOverlap(C, state, isBounded ? CE->
getArg(2) : CE->
getArg(1), Dst, srcExpr);
1588 SVal lenVal = state->getSVal(lenExpr, LCtx);
1598 if (strLengthNL && lenValNL) {
1604 std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume(
1605 svalBuilder.
evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy)
1608 if (stateSourceTooLong && !stateSourceNotTooLong) {
1611 state = stateSourceTooLong;
1612 amountCopied = lenVal;
1614 }
else if (!stateSourceTooLong && stateSourceNotTooLong) {
1616 state = stateSourceNotTooLong;
1617 amountCopied = strLength;
1629 SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
1634 maxLastElementIndex = svalBuilder.
evalBinOpNN(state, BO_Add,
1638 boundWarning =
"Size argument is greater than the free space in the " 1639 "destination buffer";
1651 std::tie(StateZeroSize, StateNonZeroSize) =
1652 assumeZero(C, state, *lenValNL, sizeTy);
1655 if (StateZeroSize && !StateNonZeroSize) {
1657 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal);
1659 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, *lenValNL);
1669 maxLastElementIndex = svalBuilder.
evalBinOpNN(state, BO_Sub, *lenValNL,
1671 boundWarning =
"Size argument is greater than the length of the " 1672 "destination buffer";
1680 if (amountCopied.
isUnknown() && !isAppending) {
1683 amountCopied = getCStringLength(C, state, lenExpr, srcVal,
true);
1684 assert(!amountCopied.
isUndef());
1693 state = state->assume(
1705 state = state->assume(
1716 amountCopied = strLength;
1732 SVal dstStrLength = getCStringLength(C, state, Dst, DstVal);
1740 if (srcStrLengthNL && dstStrLengthNL) {
1742 state = checkAdditionOverflow(C, state, *srcStrLengthNL, *dstStrLengthNL);
1746 finalStrLength = svalBuilder.
evalBinOpNN(state, BO_Add, *srcStrLengthNL,
1747 *dstStrLengthNL, sizeTy);
1755 finalStrLength = getCStringLength(C, state, CE, DstVal,
true);
1756 assert(!finalStrLength.
isUndef());
1759 if (srcStrLengthNL) {
1771 if (dstStrLengthNL) {
1788 finalStrLength = amountCopied;
1796 Result = (returnEnd ?
UnknownVal() : DstVal);
1798 Result = finalStrLength;
1813 SVal maxLastElement = svalBuilder.
evalBinOpLN(state, BO_Add, *dstRegVal,
1815 state = CheckLocation(C, state, CE->
getArg(2), maxLastElement,
1825 *knownStrLength, ptrTy);
1828 if (!boundWarning) {
1829 const char *
const warningMsg =
1830 "String copy function overflows destination buffer";
1831 state = CheckLocation(C, state, Dst, lastElement, warningMsg);
1837 if (returnPtr && returnEnd)
1838 Result = lastElement;
1848 state = InvalidateBuffer(C, state, Dst, *dstRegVal,
1853 state = InvalidateBuffer(C, state, srcExpr, srcVal,
true,
1857 if (isBounded && !isAppending) {
1862 if (amountCopied != strLength)
1865 state = setCStringLength(state, dstRegVal->getRegion(), finalStrLength);
1878 state = state->BindExpr(CE, LCtx, Result);
1887 evalStrcmpCommon(C, CE,
false,
false);
1895 evalStrcmpCommon(C, CE,
true,
false);
1904 evalStrcmpCommon(C, CE,
false,
true);
1913 evalStrcmpCommon(C, CE,
true,
true);
1917 bool isBounded,
bool ignoreCase)
const {
1918 CurrentFunctionDescription =
"string comparison function";
1924 SVal s1Val = state->getSVal(s1, LCtx);
1925 state = checkNonNull(C, state, s1, s1Val);
1931 SVal s2Val = state->getSVal(s2, LCtx);
1932 state = checkNonNull(C, state, s2, s2Val);
1937 SVal s1Length = getCStringLength(C, state, s1, s1Val);
1942 SVal s2Length = getCStringLength(C, state, s2, s2Val);
1956 std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
1961 StSameBuf = StSameBuf->BindExpr(CE, LCtx,
1962 svalBuilder.makeZeroVal(CE->
getType()));
1970 assert(StNotSameBuf);
1971 state = StNotSameBuf;
1977 const StringLiteral *s1StrLiteral = getCStringLiteral(C, state, s1, s1Val);
1978 const StringLiteral *s2StrLiteral = getCStringLiteral(C, state, s2, s2Val);
1979 bool canComputeResult =
false;
1980 SVal resultVal = svalBuilder.conjureSymbolVal(
nullptr, CE, LCtx,
1983 if (s1StrLiteral && s2StrLiteral) {
1984 StringRef s1StrRef = s1StrLiteral->
getString();
1985 StringRef s2StrRef = s2StrLiteral->
getString();
1990 SVal lenVal = state->getSVal(lenExpr, LCtx);
1993 if (
const llvm::APSInt *len = svalBuilder.getKnownValue(state, lenVal)) {
1995 s1StrRef = s1StrRef.substr(0, (
size_t)len->getZExtValue());
1996 s2StrRef = s2StrRef.substr(0, (
size_t)len->getZExtValue());
1997 canComputeResult =
true;
2001 canComputeResult =
true;
2004 if (canComputeResult) {
2006 size_t s1Term = s1StrRef.find(
'\0');
2007 if (s1Term != StringRef::npos)
2008 s1StrRef = s1StrRef.substr(0, s1Term);
2010 size_t s2Term = s2StrRef.find(
'\0');
2011 if (s2Term != StringRef::npos)
2012 s2StrRef = s2StrRef.substr(0, s2Term);
2015 int compareRes = ignoreCase ? s1StrRef.compare_lower(s2StrRef)
2016 : s1StrRef.compare(s2StrRef);
2020 if (compareRes == 0) {
2021 resultVal = svalBuilder.makeIntVal(compareRes, CE->
getType());
2028 SVal compareWithZero =
2029 svalBuilder.evalBinOp(state, op, resultVal, zeroVal,
2030 svalBuilder.getConditionType());
2032 state = state->assume(compareWithZeroVal,
true);
2037 state = state->BindExpr(CE, LCtx, resultVal);
2051 if (CharPtrTy.
isNull() ||
2055 CurrentFunctionDescription =
"strsep()";
2061 SVal SearchStrVal = State->getSVal(SearchStrPtr, LCtx);
2062 State = checkNonNull(C, State, SearchStrPtr, SearchStrVal);
2068 SVal DelimStrVal = State->getSVal(DelimStr, LCtx);
2069 State = checkNonNull(C, State, DelimStr, DelimStrVal);
2077 Result = State->getSVal(*SearchStrLoc, CharPtrTy);
2081 State = InvalidateBuffer(C, State, SearchStrPtr, Result,
2086 State = State->bindLoc(*SearchStrLoc,
2100 State = State->BindExpr(CE, LCtx, Result);
2106 evalStdCopyCommon(C, CE);
2111 evalStdCopyCommon(C, CE);
2130 SVal DstVal = State->getSVal(Dst, LCtx);
2131 State = InvalidateBuffer(C, State, Dst, DstVal,
false,
2137 State = State->BindExpr(CE, LCtx, ResultVal);
2146 CurrentFunctionDescription =
"memory set function";
2155 SVal SizeVal = State->getSVal(Size, LCtx);
2159 std::tie(StateZeroSize, StateNonZeroSize) =
2160 assumeZero(C, State, SizeVal, SizeTy);
2163 SVal MemVal = State->getSVal(Mem, LCtx);
2167 if (StateZeroSize && !StateNonZeroSize) {
2168 StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal);
2175 State = checkNonNull(C, StateNonZeroSize, Mem, MemVal);
2179 State = CheckBufferAccess(C, State, Size, Mem);
2186 if (!memsetAux(Mem, CharE, Size, C, State))
2189 State = State->BindExpr(CE, LCtx, MemVal);
2201 if (II->
getName().equals(Name))
2217 FnCheck evalFunction =
nullptr;
2219 evalFunction = &CStringChecker::evalMemcpy;
2221 evalFunction = &CStringChecker::evalMempcpy;
2223 evalFunction = &CStringChecker::evalMemcmp;
2225 evalFunction = &CStringChecker::evalMemmove;
2227 evalFunction = &CStringChecker::evalMemset;
2229 evalFunction = &CStringChecker::evalStrcpy;
2231 evalFunction = &CStringChecker::evalStrncpy;
2233 evalFunction = &CStringChecker::evalStpcpy;
2235 evalFunction = &CStringChecker::evalStrlcpy;
2237 evalFunction = &CStringChecker::evalStrcat;
2239 evalFunction = &CStringChecker::evalStrncat;
2241 evalFunction = &CStringChecker::evalStrlcat;
2243 evalFunction = &CStringChecker::evalstrLength;
2245 evalFunction = &CStringChecker::evalstrnLength;
2247 evalFunction = &CStringChecker::evalStrcmp;
2249 evalFunction = &CStringChecker::evalStrncmp;
2251 evalFunction = &CStringChecker::evalStrcasecmp;
2253 evalFunction = &CStringChecker::evalStrncasecmp;
2255 evalFunction = &CStringChecker::evalStrsep;
2257 evalFunction = &CStringChecker::evalBcopy;
2259 evalFunction = &CStringChecker::evalMemcmp;
2261 evalFunction = &CStringChecker::evalStdCopy;
2263 evalFunction = &CStringChecker::evalStdCopyBackward;
2270 (this->*evalFunction)(C, CE);
2285 for (
const auto *I : DS->
decls()) {
2297 if (!isa<StringLiteral>(Init))
2306 assert(StrVal.
isValid() &&
"Initializer string is unknown or undefined");
2310 state = state->set<CStringLength>(MR, strLength);
2323 CStringLengthTy Entries = state->get<CStringLength>();
2324 if (Entries.isEmpty())
2327 llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
2328 llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
2332 I = Regions.begin(), E = Regions.end(); I != E; ++I) {
2334 Invalidated.insert(MR);
2336 SuperRegions.insert(MR);
2337 while (
const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
2338 MR = SR->getSuperRegion();
2339 SuperRegions.insert(MR);
2346 for (CStringLengthTy::iterator I = Entries.begin(),
2347 E = Entries.end(); I != E; ++I) {
2351 if (SuperRegions.count(MR)) {
2352 Entries = F.remove(Entries, MR);
2358 while (
const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
2359 Super = SR->getSuperRegion();
2360 if (Invalidated.count(Super)) {
2361 Entries = F.remove(Entries, MR);
2367 return state->set<CStringLength>(Entries);
2373 CStringLengthTy Entries = state->get<CStringLength>();
2375 for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
2377 SVal Len = I.getData();
2385 void CStringChecker::checkDeadSymbols(
SymbolReaper &SR,
2391 CStringLengthTy Entries = state->get<CStringLength>();
2392 if (Entries.isEmpty())
2396 for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end();
2398 SVal Len = I.getData();
2401 Entries = F.remove(Entries, I.getKey());
2405 state = state->set<CStringLength>(Entries);
2409 #define REGISTER_CHECKER(name) \ 2410 void ento::register##name(CheckerManager &mgr) { \ 2411 CStringChecker *checker = mgr.registerChecker<CStringChecker>(); \ 2412 checker->Filter.Check##name = true; \ 2413 checker->Filter.CheckName##name = mgr.getCurrentCheckName(); \ 2422 Mgr.registerChecker<CStringChecker>();
Suppress pointer-escaping of a region.
Represents a function declaration or definition.
TypedValueRegion - An abstract class representing regions having a typed value.
nonloc::ConcreteInt makeIntVal(const IntegerLiteral *integer)
A (possibly-)qualified type.
MemRegion - The root abstract class for all memory regions.
ExplodedNode * generateErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Stmt - This represents one statement.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Information about invalidation for a particular region/symbol.
A helper class which wraps a boolean value set to false by default.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
ExplodedNode * addTransition(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generates a new transition in the program state graph (ExplodedGraph).
virtual QualType getValueType() const =0
const MemRegion * getRegion() const
SVal evalCast(SVal val, QualType castTy, QualType originalType)
Value representing integer constant.
Represents a variable declaration or definition.
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
void setTrait(SymbolRef Sym, InvalidationKinds IK)
const FunctionDecl * getCalleeDecl(const CallExpr *CE) const
Get the declaration of the called function (path-sensitive).
bool isDead(SymbolRef sym) const
Returns whether or not a symbol has been confirmed dead.
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
const char *const UnixAPI
SVal getSVal(const Stmt *S) const
Get the value of arbitrary expressions at this point in the path.
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
const MemRegion * getSuperRegion() const
void markInUse(SymbolRef sym)
Marks a symbol as important to a checker.
One of these records is kept for each identifier that is lexed.
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...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
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
virtual DefinedOrUnknownSVal getExtent(SValBuilder &svalBuilder) const
getExtent - Returns the size of the region in bytes.
void registerCStringCheckerBasic(CheckerManager &Mgr)
Register the checker which evaluates CString API calls.
static bool isInStdNamespace(const Decl *D)
Returns true if the root namespace of the given declaration is the 'std' C++ namespace.
const LocationContext * getLocationContext() const
static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name)
A record of the "type" of an APSInt, used for conversions.
const StringLiteral * getStringLiteral() const
SymExpr::symbol_iterator symbol_end() const
Represent a region's offset within the top level base region.
CanQualType UnsignedCharTy
SymbolRef getAsSymbol(bool IncludeBaseRegions=false) const
If this SVal wraps a symbol return that SymbolRef.
StringRef getString() const
#define REGISTER_CHECKER(name)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
bool hasDeadSymbols() const
Loc makeLoc(SymbolRef sym)
DefinedOrUnknownSVal makeZeroVal(QualType type)
Construct an SVal representing '0' for the specified type.
Expr - This represents one expression.
static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name=StringRef())
Returns true if the callee is an externally-visible function in the top-level namespace, such as malloc.
QualType getConditionType() const
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.
SVal evalBinOp(ProgramStateRef state, BinaryOperator::Opcode op, SVal lhs, SVal rhs, QualType type)
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Optional< T > getAs() const
Convert to the specified SVal type, returning None if this SVal is not of the desired type...
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
const MemRegion * StripCasts(bool StripBaseCasts=true) const
DefinedOrUnknownSVal conjureSymbolVal(const void *symbolTag, const Expr *expr, const LocationContext *LCtx, unsigned count)
Create a new symbol with a unique 'name'.
const MemRegion * getAsRegion() const
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
ASTContext & getContext()
SVal - This represents a symbolic expression, which can be either an L-value or an R-value...
A class responsible for cleaning up unused symbols.
const llvm::APSInt * evalAPSInt(BinaryOperator::Opcode Op, const llvm::APSInt &V1, const llvm::APSInt &V2)
Tells that a region's contents is not changed.
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.
unsigned blockCount() const
Returns the number of times the current block has been visited along the analyzed path...
StringRef getName() const
Return the actual identifier string.
llvm::APSInt getValue(uint64_t RawValue) const LLVM_READONLY
Dataflow Directional Tag Classes.
ASTContext & getASTContext()
const Expr * getInit() const
static std::string getAsString(SplitQualType split, const PrintingPolicy &Policy)
SVal evalEQ(ProgramStateRef state, SVal lhs, SVal rhs)
Represents an abstract call to a function or method along a particular path.
SVal convertToArrayIndex(SVal val)
DefinedSVal getMetadataSymbolVal(const void *symbolTag, const MemRegion *region, const Expr *expr, QualType type, const LocationContext *LCtx, unsigned count)
unsigned getByteLength() const
T castAs() const
Convert to the specified SVal type, asserting that this SVal is of the desired type.
BasicValueFactory & getBasicValueFactory()
SubRegion - A region that subsets another larger region.
const ProgramStateRef & getState() const
RegionOffset getAsOffset() const
Compute the offset within the top level memory object.
int64_t getOffset() const
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
QualType getValueType() const override
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
const MemRegion * getBaseRegion() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SValBuilder & getSValBuilder()
StringLiteral - This represents a string literal expression, e.g.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
const llvm::APSInt & getMaxValue(const llvm::APSInt &v)
StringRegion - Region associated with a StringLiteral.
LLVM_READONLY char toUppercase(char c)
Converts the given ASCII character to its uppercase equivalent.
ElementRegin is used to represent both array elements and casts.
SymExpr::symbol_iterator symbol_begin() const
static llvm::ImmutableListFactory< const FieldRegion * > Factory
This represents a decl that may have a name.
const LocationContext * getLocationContext() const
bool isDifferent()
Check if the checker changed the state of the execution; ex: added a new transition or a bug report...
bool hasSymbolicOffset() const
CanQualType getSizeType() const
Return the unique type for "size_t" (C99 7.17), defined in <stddef.h>.
Iterator over symbols that the current symbol depends on.