Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -97,14 +97,17 @@ void evalStrcpy(CheckerContext &C, const CallExpr *CE) const; void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; + void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const; void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd, bool isBounded, - bool isAppending) const; + bool isAppending, + bool canOverlap = false) const; void evalStrcat(CheckerContext &C, const CallExpr *CE) const; void evalStrncat(CheckerContext &C, const CallExpr *CE) const; + void evalStrlcat(CheckerContext &C, const CallExpr *CE) const; void evalStrcmp(CheckerContext &C, const CallExpr *CE) const; void evalStrncmp(CheckerContext &C, const CallExpr *CE) const; @@ -1397,6 +1400,18 @@ /* isAppending = */ false); } +void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const { + if (CE->getNumArgs() < 3) + return; + + // char *strlcpy(char *dst, const char *src, size_t n); + evalStrcpyCommon(C, CE, + /* returnEnd = */ true, + /* isBounded = */ true, + /* isAppending = */ false, + /* canOverlap = */ true); +} + void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { if (CE->getNumArgs() < 2) return; @@ -1419,9 +1434,21 @@ /* isAppending = */ true); } +void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const { + if (CE->getNumArgs() < 3) + return; + + //char *strlcat(char *s1, const char *s2, size_t n); + evalStrcpyCommon(C, CE, + /* returnEnd = */ false, + /* isBounded = */ true, + /* isAppending = */ true, + /* canOverlap = */ true); +} + void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd, bool isBounded, - bool isAppending) const { + bool isAppending, bool canOverlap) const { CurrentFunctionDescription = "string copy function"; ProgramStateRef state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); @@ -1459,6 +1486,12 @@ SVal maxLastElementIndex = UnknownVal(); const char *boundWarning = nullptr; + if (canOverlap) + state = CheckOverlap(C, state, CE->getArg(2), Dst, srcExpr); + + if (!state) + return; + // If the function is strncpy, strncat, etc... it is bounded. if (isBounded) { // Get the max number of characters to copy. @@ -2095,10 +2128,14 @@ evalFunction = &CStringChecker::evalStrncpy; else if (C.isCLibraryFunction(FDecl, "stpcpy")) evalFunction = &CStringChecker::evalStpcpy; + else if (C.isCLibraryFunction(FDecl, "strlcpy")) + evalFunction = &CStringChecker::evalStrlcpy; else if (C.isCLibraryFunction(FDecl, "strcat")) evalFunction = &CStringChecker::evalStrcat; else if (C.isCLibraryFunction(FDecl, "strncat")) evalFunction = &CStringChecker::evalStrncat; + else if (C.isCLibraryFunction(FDecl, "strlcat")) + evalFunction = &CStringChecker::evalStrlcat; else if (C.isCLibraryFunction(FDecl, "strlen")) evalFunction = &CStringChecker::evalstrLength; else if (C.isCLibraryFunction(FDecl, "strnlen")) Index: test/Analysis/bsd-string.c =================================================================== --- /dev/null +++ test/Analysis/bsd-string.c @@ -0,0 +1,32 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s + +#define NULL ((void *)0) + +typedef __typeof(sizeof(int)) size_t; +size_t strlcpy(char *dst, const char *src, size_t n); +size_t strlcat(char *dst, const char *src, size_t n); + +void f1() { + char overlap[] = "123456789"; + strlcpy(overlap, overlap + 1, 3); // expected-warning{{Arguments must not be overlapping buffers}} +} + +void f2() { + char buf[5]; + strlcpy(buf, "abcd", sizeof(buf)); // expected-no-warning + strlcat(buf, "efgh", sizeof(buf)); // expected-warning{{Size argument is greater than the free space in the destination buffer}} +} + +void f3() { + char dst[2]; + const char *src = "abdef"; + strlcpy(dst, src, 5); // expected-warning{{Size argument is greater than the length of the destination buffer}} +} + +void f4() { + strlcpy(NULL, "abcdef", 6); // expected-warning{{Null pointer argument in call to string copy function}} +} + +void f5() { + strlcat(NULL, "abcdef", 6); // expected-warning{{Null pointer argument in call to string copy function}} +}