@@ -114,6 +114,8 @@ class CStringChecker : public Checker< eval::Call,
114
114
bool isBounded = false ,
115
115
bool ignoreCase = false ) const ;
116
116
117
+ void evalStrsep (CheckerContext &C, const CallExpr *CE) const ;
118
+
117
119
// Utility methods
118
120
std::pair<ProgramStateRef , ProgramStateRef >
119
121
static assumeZero (CheckerContext &C,
@@ -1752,6 +1754,63 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
1752
1754
C.addTransition (state);
1753
1755
}
1754
1756
1757
+ void CStringChecker::evalStrsep (CheckerContext &C, const CallExpr *CE) const {
1758
+ // char *strsep(char **stringp, const char *delim);
1759
+ if (CE->getNumArgs () < 2 )
1760
+ return ;
1761
+
1762
+ // Sanity: does the search string parameter match the return type?
1763
+ const Expr *SearchStrPtr = CE->getArg (0 );
1764
+ QualType CharPtrTy = SearchStrPtr->getType ()->getPointeeType ();
1765
+ if (CharPtrTy.isNull () ||
1766
+ CE->getType ().getUnqualifiedType () != CharPtrTy.getUnqualifiedType ())
1767
+ return ;
1768
+
1769
+ CurrentFunctionDescription = " strsep()" ;
1770
+ ProgramStateRef State = C.getState ();
1771
+ const LocationContext *LCtx = C.getLocationContext ();
1772
+
1773
+ // Check that the search string pointer is non-null (though it may point to
1774
+ // a null string).
1775
+ SVal SearchStrVal = State->getSVal (SearchStrPtr, LCtx);
1776
+ State = checkNonNull (C, State, SearchStrPtr, SearchStrVal);
1777
+ if (!State)
1778
+ return ;
1779
+
1780
+ // Check that the delimiter string is non-null.
1781
+ const Expr *DelimStr = CE->getArg (1 );
1782
+ SVal DelimStrVal = State->getSVal (DelimStr, LCtx);
1783
+ State = checkNonNull (C, State, DelimStr, DelimStrVal);
1784
+ if (!State)
1785
+ return ;
1786
+
1787
+ SValBuilder &SVB = C.getSValBuilder ();
1788
+ SVal Result;
1789
+ if (Optional<Loc> SearchStrLoc = SearchStrVal.getAs <Loc>()) {
1790
+ // Get the current value of the search string pointer, as a char*.
1791
+ Result = State->getSVal (*SearchStrLoc, CharPtrTy);
1792
+
1793
+ // Invalidate the search string, representing the change of one delimiter
1794
+ // character to NUL.
1795
+ State = InvalidateBuffer (C, State, SearchStrPtr, Result);
1796
+
1797
+ // Overwrite the search string pointer. The new value is either an address
1798
+ // further along in the same string, or NULL if there are no more tokens.
1799
+ State = State->bindLoc (*SearchStrLoc,
1800
+ SVB.conjureSymbolVal (getTag (), CE, LCtx, CharPtrTy,
1801
+ C.blockCount ()));
1802
+ } else {
1803
+ assert (SearchStrVal.isUnknown ());
1804
+ // Conjure a symbolic value. It's the best we can do.
1805
+ Result = SVB.conjureSymbolVal (0 , CE, LCtx, C.blockCount ());
1806
+ }
1807
+
1808
+ // Set the return value, and finish.
1809
+ State = State->BindExpr (CE, LCtx, Result);
1810
+ C.addTransition (State);
1811
+ }
1812
+
1813
+
1755
1814
// ===----------------------------------------------------------------------===//
1756
1815
// The driver method, and other Checker callbacks.
1757
1816
// ===----------------------------------------------------------------------===//
@@ -1762,6 +1821,7 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
1762
1821
if (!FDecl)
1763
1822
return false ;
1764
1823
1824
+ // FIXME: Poorly-factored string switches are slow.
1765
1825
FnCheck evalFunction = 0 ;
1766
1826
if (C.isCLibraryFunction (FDecl, " memcpy" ))
1767
1827
evalFunction = &CStringChecker::evalMemcpy;
@@ -1793,6 +1853,8 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
1793
1853
evalFunction = &CStringChecker::evalStrcasecmp;
1794
1854
else if (C.isCLibraryFunction (FDecl, " strncasecmp" ))
1795
1855
evalFunction = &CStringChecker::evalStrncasecmp;
1856
+ else if (C.isCLibraryFunction (FDecl, " strsep" ))
1857
+ evalFunction = &CStringChecker::evalStrsep;
1796
1858
else if (C.isCLibraryFunction (FDecl, " bcopy" ))
1797
1859
evalFunction = &CStringChecker::evalBcopy;
1798
1860
else if (C.isCLibraryFunction (FDecl, " bcmp" ))
0 commit comments