[clang] 0954dc3 - [analyzer] CStringChecker buffer access checks should check the first bytes
Balazs Benics via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 11 05:21:36 PDT 2023
Author: Balazs Benics
Date: 2023-09-11T14:19:33+02:00
New Revision: 0954dc3fb9214b994623f5306473de075f8e3593
URL: https://github.com/llvm/llvm-project/commit/0954dc3fb9214b994623f5306473de075f8e3593
DIFF: https://github.com/llvm/llvm-project/commit/0954dc3fb9214b994623f5306473de075f8e3593.diff
LOG: [analyzer] CStringChecker buffer access checks should check the first bytes
By not checking if the first byte of the buffer is accessible,
we missed some reports in the Juliet benchmark.
(Juliet CWE-124 Buffer Underwrite: memcpy, memmove)
https://discourse.llvm.org/t/patches-inspired-by-the-juliet-benchmark/73106
Depends on D159108
Differential Revision: https://reviews.llvm.org/D159109
Added:
Modified:
clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
clang/test/Analysis/string.c
Removed:
################################################################################
diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
index 66ed78e4b17a72..f1539f2733298d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp
@@ -480,6 +480,14 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
if (!Filter.CheckCStringOutOfBounds)
return State;
+ SVal BufStart =
+ svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
+
+ // Check if the first byte of the buffer is accessible.
+ State = CheckLocation(C, State, Buffer, BufStart, Access, CK);
+ if (!State)
+ return nullptr;
+
// Get the access length and make sure it is known.
// FIXME: This assumes the caller has already checked that the access length
// is positive. And that it's unsigned.
@@ -496,8 +504,6 @@ CStringChecker::CheckBufferAccess(CheckerContext &C, ProgramStateRef State,
NonLoc LastOffset = Offset.castAs<NonLoc>();
// Check that the first buffer is sufficiently long.
- SVal BufStart =
- svalBuilder.evalCast(BufVal, PtrTy, Buffer.Expression->getType());
if (std::optional<Loc> BufLoc = BufStart.getAs<Loc>()) {
SVal BufEnd =
diff --git a/clang/test/Analysis/string.c b/clang/test/Analysis/string.c
index 476f44d7830d33..234b526788aa35 100644
--- a/clang/test/Analysis/string.c
+++ b/clang/test/Analysis/string.c
@@ -71,6 +71,7 @@ void clang_analyzer_eval(int);
int scanf(const char *restrict format, ...);
void *malloc(size_t);
void free(void *);
+void *memcpy(void *dest, const void *src, unsigned long n);
//===----------------------------------------------------------------------===
// strlen()
@@ -1713,3 +1714,21 @@ void CWE124_Buffer_Underwrite__malloc_char_ncpy() {
free(dataBuffer);
}
#endif
+
+#ifndef SUPPRESS_OUT_OF_BOUND
+void CWE124_Buffer_Underwrite__malloc_char_memcpy() {
+ 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
+
+ memcpy(data, source, 100*sizeof(char)); // expected-warning {{Memory copy function overflows the destination buffer}}
+ data[100-1] = '\0';
+ free(dataBuffer);
+}
+#endif
More information about the cfe-commits
mailing list