Index: lib/StaticAnalyzer/Checkers/CStringChecker.cpp =================================================================== --- lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -188,7 +188,7 @@ const Expr *Buf, const char *message = nullptr, bool WarnAboutSize = false) const { - // This is a convenience override. + // This is a convenience overload. return CheckBufferAccess(C, state, Size, Buf, nullptr, message, nullptr, WarnAboutSize); } @@ -2255,11 +2255,20 @@ //===----------------------------------------------------------------------===// bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { - const FunctionDecl *FDecl = C.getCalleeDecl(CE); + const FunctionDecl *FDecl = C.getCalleeDecl(CE); if (!FDecl) return false; + // Pro-actively check that argument types are safe to do arithmetic upon. + // We do not want to crash if someone accidentally passes a structure + // into, say, a C++ overload of any of these functions. + for (auto I: CE->arguments()) { + QualType T = I->getType(); + if (!T->isIntegralOrEnumerationType() && !T->isPointerType()) + return false; + } + // FIXME: Poorly-factored string switches are slow. FnCheck evalFunction = nullptr; if (C.isCLibraryFunction(FDecl, "memcpy")) Index: test/Analysis/string.cpp =================================================================== --- /dev/null +++ test/Analysis/string.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix -verify %s + +// expected-no-diagnostics + +// Test functions that are called "memcpy" but aren't the memcpy +// we're looking for. Unfortunately, this test cannot be put into +// a namespace. The out-of-class weird memcpy needs to be recognized +// as a normal C function for the test to make sense. +typedef __typeof(sizeof(int)) size_t; +void *memcpy(void *, const void *, size_t); + +struct S { + static S s1, s2; + + // A weird overload within the class that accepts a structure reference + // instead of a pointer. + void memcpy(void *, const S &, size_t); + void test_in_class_weird_memcpy() { + memcpy(this, s2, 1); // no-crash + } +}; + +// A similarly weird overload outside of the class. +void *memcpy(void *, const S &, size_t); + +void test_out_of_class_weird_memcpy() { + memcpy(&S::s1, S::s2, 1); // no-crash +}