diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -2009,6 +2009,11 @@ SVal maxLastElement = svalBuilder.evalBinOpLN(state, BO_Add, *dstRegVal, *maxLastNL, ptrTy); + // Check if the first byte of the destination is writable. + state = CheckLocation(C, state, Dst, DstVal, AccessKind::write); + if (!state) + return; + // Check if the last byte of the destination is writable. state = CheckLocation(C, state, Dst, maxLastElement, AccessKind::write); if (!state) return; @@ -2021,6 +2026,11 @@ // ...and we haven't checked the bound, we'll check the actual copy. if (!boundWarning) { + // Check if the first byte of the destination is writable. + state = CheckLocation(C, state, Dst, DstVal, AccessKind::write); + if (!state) + return; + // Check if the last byte of the destination is writable. state = CheckLocation(C, state, Dst, lastElement, AccessKind::write); if (!state) return; diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c --- a/clang/test/Analysis/string.c +++ b/clang/test/Analysis/string.c @@ -1667,3 +1667,49 @@ strcpy(x, "12\0"); } #endif + +#ifndef SUPPRESS_OUT_OF_BOUND +void testStrcpyDestinationWritableFirstByte(void) { + char dst[10]; + char *p = dst - 8; + strcpy(p, "src"); // expected-warning {{String copy function overflows the destination buffer}} +} + +void CWE124_Buffer_Underwrite__malloc_char_cpy() { + char * dataBuffer = (char *)malloc(100*sizeof(char)); + if (dataBuffer == NULL) return; + memset(dataBuffer, 'A', 100-1); + dataBuffer[100-1] = '\0'; + char * data = dataBuffer - 8; + char source[100]; + memset(source, 'C', 100-1); // fill with 'C's + source[100-1] = '\0'; // null terminate + strcpy(data, source); // expected-warning {{String copy function overflows the destination buffer}} + free(dataBuffer); +} +#endif + +#ifndef SUPPRESS_OUT_OF_BOUND +void testStrncpyDestinationWritableFirstByte(void) { + char source[100]; + use_string(source); // escape + char buf[100]; + char *p = buf - 8; + strncpy(p, source, 100-1); // expected-warning {{String copy function overflows the destination buffer}} +} + +void CWE124_Buffer_Underwrite__malloc_char_ncpy() { + char * dataBuffer = (char *)malloc(100*sizeof(char)); + if (dataBuffer == 0) return; + memset(dataBuffer, 'A', 100-1); + dataBuffer[100-1] = '\0'; + char *data = dataBuffer - 8; + + char source[100]; + memset(source, 'C', 100-1); // fill with 'C's + source[100-1] = '\0'; // null terminate + strncpy(data, source, 100-1); // expected-warning {{String copy function overflows the destination buffer}} + data[100-1] = '\0'; // null terminate + free(dataBuffer); +} +#endif