diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index 4eaf8ba61eaec..5b72382ca9772 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -675,7 +675,7 @@ static bool isNullTermPointer(const Expr *Ptr) { const CXXMethodDecl *MD = MCE->getMethodDecl(); const CXXRecordDecl *RD = MCE->getRecordDecl()->getCanonicalDecl(); - if (MD && RD && RD->isInStdNamespace()) + if (MD && RD && RD->isInStdNamespace() && MD->getIdentifier()) if (MD->getName() == "c_str" && RD->getName() == "basic_string") return true; } diff --git a/clang/test/SemaCXX/bug149071318.cpp b/clang/test/SemaCXX/bug149071318.cpp new file mode 100644 index 0000000000000..596d0e238dfba --- /dev/null +++ b/clang/test/SemaCXX/bug149071318.cpp @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \ +// RUN: -verify %s + +// This example uncovered a bug in UnsafeBufferUsage.cpp, where the +// code assumed that a CXXMethodDecl always have an identifier. + +int printf( const char* format, char *); // <-- Fake decl of `printf`; to reproduce the bug, this example needs an implicit cast within a printf call. + +namespace std { // fake std namespace; to reproduce the bug, a CXXConversionDecl needs to be in std namespace. + class X { + char * p; + public: + operator char*() {return p;} + }; + + class Y { + public: + X x; + }; + +} + +void test(std::Y &y) { + // Here `y.x` involves an implicit cast and calls the overloaded cast operator, which has no identifier: + printf("%s", y.x); // expected-warning{{function 'printf' is unsafe}} expected-note{{}} +}