[clang] 2345796 - Revert "[-Wunsafe-buffer-usage] Warning Libc functions (#101583)"

via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 4 16:27:58 PDT 2024


Author: ziqingluo-90
Date: 2024-09-04T16:26:44-07:00
New Revision: 23457964392d00fc872fa6021763859024fb38da

URL: https://github.com/llvm/llvm-project/commit/23457964392d00fc872fa6021763859024fb38da
DIFF: https://github.com/llvm/llvm-project/commit/23457964392d00fc872fa6021763859024fb38da.diff

LOG: Revert "[-Wunsafe-buffer-usage] Warning Libc functions (#101583)"

This reverts commit 0fffdeb5f46078ddcc61e112cd38856b1165f050.

Will re-land this commit soon with a way to opt-out

Added: 
    

Modified: 
    clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
    clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/lib/Analysis/UnsafeBufferUsage.cpp
    clang/lib/Sema/AnalysisBasedWarnings.cpp
    clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp

Removed: 
    clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions-inline-namespace.cpp
    clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp


################################################################################
diff  --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index aa2c01ad10d45d..228b4ae1e3e115 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -15,7 +15,6 @@
 #define LLVM_CLANG_ANALYSIS_ANALYSES_UNSAFEBUFFERUSAGE_H
 
 #include "clang/AST/Decl.h"
-#include "clang/AST/Expr.h"
 #include "clang/AST/Stmt.h"
 #include "clang/Basic/SourceLocation.h"
 #include "llvm/Support/Debug.h"
@@ -107,20 +106,6 @@ class UnsafeBufferUsageHandler {
   virtual void handleUnsafeOperation(const Stmt *Operation,
                                      bool IsRelatedToDecl, ASTContext &Ctx) = 0;
 
-  /// Invoked when a call to an unsafe libc function is found.
-  /// \param PrintfInfo
-  ///  is 0 if the callee function is not a member of the printf family;
-  ///  is 1 if the callee is `sprintf`;
-  ///  is 2 if arguments of the call have `__size_by` relation but are not in a
-  ///  safe pattern;
-  ///  is 3 if string arguments do not guarantee null-termination
-  ///  is 4 if the callee takes va_list
-  /// \param UnsafeArg one of the actual arguments that is unsafe, non-null
-  /// only when `2 <= PrintfInfo <= 3`
-  virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo,
-                                    ASTContext &Ctx,
-                                    const Expr *UnsafeArg = nullptr) = 0;
-
   /// Invoked when an unsafe operation with a std container is found.
   virtual void handleUnsafeOperationInContainer(const Stmt *Operation,
                                                 bool IsRelatedToDecl,

diff  --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index ac01b285ae833b..242ad763ba62b9 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -38,7 +38,6 @@ WARNING_GADGET(PointerArithmetic)
 WARNING_GADGET(UnsafeBufferUsageAttr)
 WARNING_GADGET(UnsafeBufferUsageCtorAttr)
 WARNING_GADGET(DataInvocation)
-WARNING_GADGET(UnsafeLibcFunctionCall)
 WARNING_CONTAINER_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)`
 FIXABLE_GADGET(ULCArraySubscript)          // `DRE[any]` in an Unspecified Lvalue Context
 FIXABLE_GADGET(DerefSimplePtrArithFixable)

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 35f68f51dfb356..dcb49d8a67604a 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12412,13 +12412,6 @@ def warn_unsafe_buffer_operation : Warning<
   "unsafe buffer access|function introduces unsafe buffer manipulation|unsafe invocation of span::data|"
   "field %1 prone to unsafe buffer manipulation}0">,
   InGroup<UnsafeBufferUsage>, DefaultIgnore;
-def warn_unsafe_buffer_libc_call : Warning<
-  "function %0 is unsafe">,
-  InGroup<UnsafeBufferUsage>, DefaultIgnore;
-def note_unsafe_buffer_printf_call : Note<
-  "%select{|change to 'snprintf' for explicit bounds checking | buffer pointer and size may not match"
-          "|string argument is not guaranteed to be null-terminated"
-          "|'va_list' is unsafe}0">;
 def note_unsafe_buffer_operation : Note<
   "used%select{| in pointer arithmetic| in buffer access}0 here">;
 def note_unsafe_buffer_variable_fixit_group : Note<

diff  --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index f0d072643f8ff0..da7446913f7c87 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -10,12 +10,12 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/Expr.h"
-#include "clang/AST/FormatString.h"
 #include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/StmtVisitor.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/CharInfo.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Lex/Lexer.h"
 #include "clang/Lex/Preprocessor.h"
@@ -443,426 +443,6 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) {
   return false;
 }
 
-AST_MATCHER_P(CallExpr, hasNumArgs, unsigned, Num) {
-  return Node.getNumArgs() == Num;
-}
-
-namespace libc_func_matchers {
-// Under `libc_func_matchers`, define a set of matchers that match unsafe
-// functions in libc and unsafe calls to them.
-
-//  A tiny parser to strip off common prefix and suffix of libc function names
-//  in real code.
-//
-//  Given a function name, `matchName` returns `CoreName` according to the
-//  following grammar:
-//
-//  LibcName     := CoreName | CoreName + "_s"
-//  MatchingName := "__builtin_" + LibcName              |
-//                  "__builtin___" + LibcName + "_chk"   |
-//                  "__asan_" + LibcName
-//
-struct LibcFunNamePrefixSuffixParser {
-  StringRef matchName(StringRef FunName, bool isBuiltin) {
-    // Try to match __builtin_:
-    if (isBuiltin && FunName.starts_with("__builtin_"))
-      // Then either it is __builtin_LibcName or __builtin___LibcName_chk or
-      // no match:
-      return matchLibcNameOrBuiltinChk(
-          FunName.drop_front(10 /* truncate "__builtin_" */));
-    // Try to match __asan_:
-    if (FunName.starts_with("__asan_"))
-      return matchLibcName(FunName.drop_front(7 /* truncate of "__asan_" */));
-    return matchLibcName(FunName);
-  }
-
-  // Parameter `Name` is the substring after stripping off the prefix
-  // "__builtin_".
-  StringRef matchLibcNameOrBuiltinChk(StringRef Name) {
-    if (Name.starts_with("__") && Name.ends_with("_chk"))
-      return matchLibcName(
-          Name.drop_front(2).drop_back(4) /* truncate "__" and "_chk" */);
-    return matchLibcName(Name);
-  }
-
-  StringRef matchLibcName(StringRef Name) {
-    if (Name.ends_with("_s"))
-      return Name.drop_back(2 /* truncate "_s" */);
-    return Name;
-  }
-};
-
-// A pointer type expression is known to be null-terminated, if it has the
-// form: E.c_str(), for any expression E of `std::string` type.
-static bool isNullTermPointer(const Expr *Ptr) {
-  if (isa<StringLiteral>(Ptr->IgnoreParenImpCasts()))
-    return true;
-  if (isa<PredefinedExpr>(Ptr->IgnoreParenImpCasts()))
-    return true;
-  if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Ptr->IgnoreParenImpCasts())) {
-    const CXXMethodDecl *MD = MCE->getMethodDecl();
-    const CXXRecordDecl *RD = MCE->getRecordDecl()->getCanonicalDecl();
-
-    if (MD && RD && RD->isInStdNamespace())
-      if (MD->getName() == "c_str" && RD->getName() == "basic_string")
-        return true;
-  }
-  return false;
-}
-
-// Return true iff at least one of following cases holds:
-//  1. Format string is a literal and there is an unsafe pointer argument
-//     corresponding to an `s` specifier;
-//  2. Format string is not a literal and there is least an unsafe pointer
-//     argument (including the formatter argument).
-//
-// `UnsafeArg` is the output argument that will be set only if this function
-// returns true.
-static bool hasUnsafeFormatOrSArg(const CallExpr *Call, const Expr *&UnsafeArg,
-                                  const unsigned FmtArgIdx, ASTContext &Ctx,
-                                  bool isKprintf = false) {
-  class StringFormatStringHandler
-      : public analyze_format_string::FormatStringHandler {
-    const CallExpr *Call;
-    unsigned FmtArgIdx;
-    const Expr *&UnsafeArg;
-
-  public:
-    StringFormatStringHandler(const CallExpr *Call, unsigned FmtArgIdx,
-                              const Expr *&UnsafeArg)
-        : Call(Call), FmtArgIdx(FmtArgIdx), UnsafeArg(UnsafeArg) {}
-
-    bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
-                               const char *startSpecifier,
-                               unsigned specifierLen,
-                               const TargetInfo &Target) override {
-      if (FS.getConversionSpecifier().getKind() ==
-          analyze_printf::PrintfConversionSpecifier::sArg) {
-        unsigned ArgIdx = FS.getPositionalArgIndex() + FmtArgIdx;
-
-        if (0 < ArgIdx && ArgIdx < Call->getNumArgs())
-          if (!isNullTermPointer(Call->getArg(ArgIdx))) {
-            UnsafeArg = Call->getArg(ArgIdx); // output
-            // returning false stops parsing immediately
-            return false;
-          }
-      }
-      return true; // continue parsing
-    }
-  };
-
-  const Expr *Fmt = Call->getArg(FmtArgIdx);
-
-  if (auto *SL = dyn_cast<StringLiteral>(Fmt->IgnoreParenImpCasts())) {
-    StringRef FmtStr = SL->getString();
-    StringFormatStringHandler Handler(Call, FmtArgIdx, UnsafeArg);
-
-    return analyze_format_string::ParsePrintfString(
-        Handler, FmtStr.begin(), FmtStr.end(), Ctx.getLangOpts(),
-        Ctx.getTargetInfo(), isKprintf);
-  }
-  // If format is not a string literal, we cannot analyze the format string.
-  // In this case, this call is considered unsafe if at least one argument
-  // (including the format argument) is unsafe pointer.
-  return llvm::any_of(
-      llvm::make_range(Call->arg_begin() + FmtArgIdx, Call->arg_end()),
-      [&UnsafeArg](const Expr *Arg) -> bool {
-        if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg)) {
-          UnsafeArg = Arg;
-          return true;
-        }
-        return false;
-      });
-}
-
-// Matches a FunctionDecl node such that
-//  1. It's name, after stripping off predefined prefix and suffix, is
-//     `CoreName`; and
-//  2. `CoreName` or `CoreName[str/wcs]` is one of the `PredefinedNames`, which
-//     is a set of libc function names.
-//
-//  Note: For predefined prefix and suffix, see `LibcFunNamePrefixSuffixParser`.
-//  The notation `CoreName[str/wcs]` means a new name obtained from replace
-//  string "wcs" with "str" in `CoreName`.
-AST_MATCHER(FunctionDecl, isPredefinedUnsafeLibcFunc) {
-  static std::unique_ptr<std::set<StringRef>> PredefinedNames = nullptr;
-  if (!PredefinedNames)
-    PredefinedNames =
-        std::make_unique<std::set<StringRef>, std::set<StringRef>>({
-            // numeric conversion:
-            "atof",
-            "atoi",
-            "atol",
-            "atoll",
-            "strtol",
-            "strtoll",
-            "strtoul",
-            "strtoull",
-            "strtof",
-            "strtod",
-            "strtold",
-            "strtoimax",
-            "strtoumax",
-            // "strfromf",  "strfromd", "strfroml", // C23?
-            // string manipulation:
-            "strcpy",
-            "strncpy",
-            "strlcpy",
-            "strcat",
-            "strncat",
-            "strlcat",
-            "strxfrm",
-            "strdup",
-            "strndup",
-            // string examination:
-            "strlen",
-            "strnlen",
-            "strcmp",
-            "strncmp",
-            "stricmp",
-            "strcasecmp",
-            "strcoll",
-            "strchr",
-            "strrchr",
-            "strspn",
-            "strcspn",
-            "strpbrk",
-            "strstr",
-            "strtok",
-            // "mem-" functions
-            "memchr",
-            "wmemchr",
-            "memcmp",
-            "wmemcmp",
-            "memcpy",
-            "memccpy",
-            "mempcpy",
-            "wmemcpy",
-            "memmove",
-            "wmemmove",
-            "memset",
-            "wmemset",
-            // IO:
-            "fread",
-            "fwrite",
-            "fgets",
-            "fgetws",
-            "gets",
-            "fputs",
-            "fputws",
-            "puts",
-            // others
-            "strerror_s",
-            "strerror_r",
-            "bcopy",
-            "bzero",
-            "bsearch",
-            "qsort",
-        });
-
-  auto *II = Node.getIdentifier();
-
-  if (!II)
-    return false;
-
-  StringRef Name = LibcFunNamePrefixSuffixParser().matchName(
-      II->getName(), Node.getBuiltinID());
-
-  // Match predefined names:
-  if (PredefinedNames->find(Name) != PredefinedNames->end())
-    return true;
-
-  std::string NameWCS = Name.str();
-  size_t WcsPos = NameWCS.find("wcs");
-
-  while (WcsPos != std::string::npos) {
-    NameWCS[WcsPos++] = 's';
-    NameWCS[WcsPos++] = 't';
-    NameWCS[WcsPos++] = 'r';
-    WcsPos = NameWCS.find("wcs", WcsPos);
-  }
-  if (PredefinedNames->find(NameWCS) != PredefinedNames->end())
-    return true;
-  // All `scanf` functions are unsafe (including `sscanf`, `vsscanf`, etc.. They
-  // all should end with "scanf"):
-  return Name.ends_with("scanf");
-}
-
-// Match a call to one of the `v*printf` functions taking `va_list`.  We cannot
-// check safety for these functions so they should be changed to their
-// non-va_list versions.
-AST_MATCHER(FunctionDecl, isUnsafeVaListPrintfFunc) {
-  auto *II = Node.getIdentifier();
-
-  if (!II)
-    return false;
-
-  StringRef Name = LibcFunNamePrefixSuffixParser().matchName(
-      II->getName(), Node.getBuiltinID());
-
-  if (!Name.ends_with("printf"))
-    return false; // neither printf nor scanf
-  return Name.starts_with("v");
-}
-
-// Matches a call to one of the `sprintf` functions as they are always unsafe
-// and should be changed to `snprintf`.
-AST_MATCHER(FunctionDecl, isUnsafeSprintfFunc) {
-  auto *II = Node.getIdentifier();
-
-  if (!II)
-    return false;
-
-  StringRef Name = LibcFunNamePrefixSuffixParser().matchName(
-      II->getName(), Node.getBuiltinID());
-
-  if (!Name.ends_with("printf") ||
-      // Let `isUnsafeVaListPrintfFunc` check for cases with va-list:
-      Name.starts_with("v"))
-    return false;
-
-  StringRef Prefix = Name.drop_back(6);
-
-  if (Prefix.ends_with("w"))
-    Prefix = Prefix.drop_back(1);
-  return Prefix == "s";
-}
-
-// Match function declarations of `printf`, `fprintf`, `snprintf` and their wide
-// character versions.  Calls to these functions can be safe if their arguments
-// are carefully made safe.
-AST_MATCHER(FunctionDecl, isNormalPrintfFunc) {
-  auto *II = Node.getIdentifier();
-
-  if (!II)
-    return false;
-
-  StringRef Name = LibcFunNamePrefixSuffixParser().matchName(
-      II->getName(), Node.getBuiltinID());
-
-  if (!Name.ends_with("printf") || Name.starts_with("v"))
-    return false;
-
-  StringRef Prefix = Name.drop_back(6);
-
-  if (Prefix.ends_with("w"))
-    Prefix = Prefix.drop_back(1);
-
-  return Prefix.empty() || Prefix == "k" || Prefix == "f" || Prefix == "sn";
-}
-
-// This matcher requires that it is known that the callee `isNormalPrintf`.
-// Then if the format string is a string literal, this matcher matches when at
-// least one string argument is unsafe. If the format is not a string literal,
-// this matcher matches when at least one pointer type argument is unsafe.
-AST_MATCHER_P(CallExpr, hasUnsafePrintfStringArg,
-              clang::ast_matchers::internal::Matcher<Expr>,
-              UnsafeStringArgMatcher) {
-  // Determine what printf it is:
-  const Expr *FirstArg = Node.getArg(0);
-  ASTContext &Ctx = Finder->getASTContext();
-
-  if (isa<StringLiteral>(FirstArg->IgnoreParenImpCasts())) {
-    // It is a printf/kprintf. And, the format is a string literal:
-    bool isKprintf = false;
-    const Expr *UnsafeArg;
-
-    if (auto *Callee = Node.getDirectCallee())
-      if (auto *II = Node.getDirectCallee()->getIdentifier())
-        isKprintf = II->getName() == "kprintf";
-    if (hasUnsafeFormatOrSArg(&Node, UnsafeArg, 0, Ctx, isKprintf))
-      return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
-    return false;
-  }
-
-  QualType PtrTy = FirstArg->getType();
-
-  assert(PtrTy->isPointerType());
-
-  QualType PteTy = (cast<PointerType>(PtrTy))->getPointeeType();
-
-  if (!Ctx.getFILEType().isNull() /* If `FILE *` is not ever in the ASTContext,
-                                     there can't be any file pointer then */
-      && PteTy.getCanonicalType() == Ctx.getFILEType().getCanonicalType()) {
-    // It is a fprintf:
-    const Expr *UnsafeArg;
-
-    if (hasUnsafeFormatOrSArg(&Node, UnsafeArg, 1, Ctx, false))
-      return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
-    return false;
-  }
-
-  const Expr *SecondArg = Node.getArg(1);
-
-  if (SecondArg->getType()->isIntegerType()) {
-    // It is a snprintf:
-    const Expr *UnsafeArg;
-
-    if (unsigned UnsafeArgIdx =
-            hasUnsafeFormatOrSArg(&Node, UnsafeArg, 2, Ctx, false))
-      return UnsafeStringArgMatcher.matches(*UnsafeArg, Finder, Builder);
-    return false;
-  }
-  // It is printf but the format string is passed by pointer. The only thing we
-  // can do is to require all pointers to be null-terminated:
-  for (auto Arg : Node.arguments())
-    if (Arg->getType()->isPointerType() && !isNullTermPointer(Arg))
-      if (UnsafeStringArgMatcher.matches(*Arg, Finder, Builder))
-        return true;
-  return false;
-}
-
-// This matcher requires that it is known that the callee `isNormalPrintf`.
-// Then it matches if the first two arguments of the call is a pointer and an
-// integer and they are not in a safe pattern.
-//
-// For the first two arguments: `ptr` and `size`, they are safe if in the
-// following patterns:
-//    ptr := DRE.data();
-//    size:= DRE.size()/DRE.size_bytes()
-// And DRE is a hardened container or view.
-AST_MATCHER(CallExpr, hasUnsafeSnprintfBuffer) {
-  if (Node.getNumArgs() < 3)
-    return false; // not an snprintf call
-
-  const Expr *Buf = Node.getArg(0), *Size = Node.getArg(1);
-
-  if (!Buf->getType()->isPointerType() || !Size->getType()->isIntegerType())
-    return false; // not an snprintf call
-
-  static StringRef SizedObjs[] = {"span", "array", "vector",
-                                  "basic_string_view", "basic_string"};
-  Buf = Buf->IgnoreParenImpCasts();
-  Size = Size->IgnoreParenImpCasts();
-  if (auto *MCEPtr = dyn_cast<CXXMemberCallExpr>(Buf))
-    if (auto *MCESize = dyn_cast<CXXMemberCallExpr>(Size)) {
-      auto *DREOfPtr = dyn_cast<DeclRefExpr>(
-          MCEPtr->getImplicitObjectArgument()->IgnoreParenImpCasts());
-      auto *DREOfSize = dyn_cast<DeclRefExpr>(
-          MCESize->getImplicitObjectArgument()->IgnoreParenImpCasts());
-
-      if (!DREOfPtr || !DREOfSize)
-        return true; // not in safe pattern
-      if (DREOfPtr->getDecl() != DREOfSize->getDecl())
-        return true; // not in safe pattern
-      if (MCEPtr->getMethodDecl()->getName() != "data")
-        return true; // not in safe pattern
-
-      if (MCESize->getMethodDecl()->getName() == "size_bytes" ||
-          // Note here the pointer must be a pointer-to-char type unless there
-          // is explicit casting.  If there is explicit casting, this branch
-          // is unreachable. Thus, at this branch "size" and "size_bytes" are
-          // equivalent as the pointer is a char pointer:
-          MCESize->getMethodDecl()->getName() == "size")
-        for (StringRef SizedObj : SizedObjs)
-          if (MCEPtr->getRecordDecl()->isInStdNamespace() &&
-              MCEPtr->getRecordDecl()->getCanonicalDecl()->getName() ==
-                  SizedObj)
-            return false; // It is in fact safe
-    }
-  return true; // ptr and size are not in safe pattern
-}
-} // namespace libc_func_matchers
 } // namespace clang::ast_matchers
 
 namespace {
@@ -1450,97 +1030,6 @@ class DataInvocationGadget : public WarningGadget {
   DeclUseList getClaimedVarUseSites() const override { return {}; }
 };
 
-class UnsafeLibcFunctionCallGadget : public WarningGadget {
-  const CallExpr *const Call;
-  const Expr *UnsafeArg = nullptr;
-  constexpr static const char *const Tag = "UnsafeLibcFunctionCall";
-  // Extra tags for additional information:
-  constexpr static const char *const UnsafeSprintfTag =
-      "UnsafeLibcFunctionCall_sprintf";
-  constexpr static const char *const UnsafeSizedByTag =
-      "UnsafeLibcFunctionCall_sized_by";
-  constexpr static const char *const UnsafeStringTag =
-      "UnsafeLibcFunctionCall_string";
-  constexpr static const char *const UnsafeVaListTag =
-      "UnsafeLibcFunctionCall_va_list";
-
-  enum UnsafeKind {
-    OTHERS = 0,  // no specific information, the callee function is unsafe
-    SPRINTF = 1, // never call `-sprintf`s, call `-snprintf`s instead.
-    SIZED_BY =
-        2, // the first two arguments of `snprintf` function have
-           // "__sized_by" relation but they do not conform to safe patterns
-    STRING = 3,  // an argument is a pointer-to-char-as-string but does not
-                 // guarantee null-termination
-    VA_LIST = 4, // one of the `-printf`s function that take va_list, which is
-                 // considered unsafe as it is not compile-time check
-  } WarnedFunKind = OTHERS;
-
-public:
-  UnsafeLibcFunctionCallGadget(const MatchFinder::MatchResult &Result)
-      : WarningGadget(Kind::UnsafeLibcFunctionCall),
-        Call(Result.Nodes.getNodeAs<CallExpr>(Tag)) {
-    if (Result.Nodes.getNodeAs<Decl>(UnsafeSprintfTag))
-      WarnedFunKind = SPRINTF;
-    else if (auto *E = Result.Nodes.getNodeAs<Expr>(UnsafeStringTag)) {
-      WarnedFunKind = STRING;
-      UnsafeArg = E;
-    } else if (Result.Nodes.getNodeAs<CallExpr>(UnsafeSizedByTag)) {
-      WarnedFunKind = SIZED_BY;
-      UnsafeArg = Call->getArg(0);
-    } else if (Result.Nodes.getNodeAs<Decl>(UnsafeVaListTag))
-      WarnedFunKind = VA_LIST;
-  }
-
-  static Matcher matcher() {
-    return stmt(anyOf(
-        callExpr(
-            callee(functionDecl(anyOf(
-                // Match a predefined unsafe libc
-                // function:
-                functionDecl(libc_func_matchers::isPredefinedUnsafeLibcFunc()),
-                // Match a call to one of the `v*printf` functions
-                // taking va-list, which cannot be checked at
-                // compile-time:
-                functionDecl(libc_func_matchers::isUnsafeVaListPrintfFunc())
-                    .bind(UnsafeVaListTag),
-                // Match a call to a `sprintf` function, which is never
-                // safe:
-                functionDecl(libc_func_matchers::isUnsafeSprintfFunc())
-                    .bind(UnsafeSprintfTag)))),
-            //  (unless the call has a sole string literal argument):
-            unless(
-                allOf(hasArgument(0, expr(stringLiteral())), hasNumArgs(1)))),
-
-        // The following two cases require checking against actual
-        // arguments of the call:
-
-        // Match a call to an `snprintf` function. And first two
-        // arguments of the call (that describe a buffer) are not in
-        // safe patterns:
-        callExpr(callee(functionDecl(libc_func_matchers::isNormalPrintfFunc())),
-                 libc_func_matchers::hasUnsafeSnprintfBuffer())
-            .bind(UnsafeSizedByTag),
-        // Match a call to a `printf` function, which can be safe if
-        // all arguments are null-terminated:
-        callExpr(callee(functionDecl(libc_func_matchers::isNormalPrintfFunc())),
-                 libc_func_matchers::hasUnsafePrintfStringArg(
-                     expr().bind(UnsafeStringTag)))));
-  }
-
-  const Stmt *getBaseStmt() const { return Call; }
-
-  SourceLocation getSourceLoc() const override { return Call->getBeginLoc(); }
-
-  void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
-                             bool IsRelatedToDecl,
-                             ASTContext &Ctx) const override {
-    Handler.handleUnsafeLibcCall(Call, WarnedFunKind, Ctx, UnsafeArg);
-  }
-
-  DeclUseList getClaimedVarUseSites() const override { return {}; }
-};
-
 // Represents expressions of the form `DRE[*]` in the Unspecified Lvalue
 // Context (see `isInUnspecifiedLvalueContext`).
 // Note here `[]` is the built-in subscript operator.

diff  --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 72078ae1534b07..e6ce89dc7ec406 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2304,20 +2304,6 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
     }
   }
 
-  void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo,
-                            ASTContext &Ctx,
-                            const Expr *UnsafeArg = nullptr) override {
-    S.Diag(Call->getBeginLoc(), diag::warn_unsafe_buffer_libc_call)
-        << Call->getDirectCallee() // We've checked there is a direct callee
-        << Call->getSourceRange();
-    if (PrintfInfo > 0) {
-      SourceRange R =
-          UnsafeArg ? UnsafeArg->getSourceRange() : Call->getSourceRange();
-      S.Diag(R.getBegin(), diag::note_unsafe_buffer_printf_call)
-          << PrintfInfo << R;
-    }
-  }
-
   void handleUnsafeOperationInContainer(const Stmt *Operation,
                                         bool IsRelatedToDecl,
                                         ASTContext &Ctx) override {

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions-inline-namespace.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions-inline-namespace.cpp
deleted file mode 100644
index 2bd12db93fd526..00000000000000
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions-inline-namespace.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \
-// RUN:            -verify %s
-
-namespace std {
-  inline namespace __1 {
-  template< class InputIt, class OutputIt >
-  OutputIt copy( InputIt first, InputIt last,
-		 OutputIt d_first );
-
-  struct iterator{};
-  template<typename T>
-  struct span {
-    T * ptr;
-    T * data();
-    unsigned size_bytes();
-    unsigned size();
-    iterator begin() const noexcept;
-    iterator end() const noexcept;
-  };
-
-  template<typename T>
-  struct basic_string {
-    T* p;
-    T *c_str();
-    T *data();
-    unsigned size_bytes();
-  };
-
-  typedef basic_string<char> string;
-  typedef basic_string<wchar_t> wstring;
-
-  // C function under std:
-  void memcpy();
-  void strcpy();
-  int snprintf( char* buffer, unsigned buf_size, const char* format, ... );
-  }
-}
-
-void f(char * p, char * q, std::span<char> s) {
-  std::memcpy();              // expected-warning{{function 'memcpy' is unsafe}}
-  std::strcpy();              // expected-warning{{function 'strcpy' is unsafe}}
-  std::__1::memcpy();              // expected-warning{{function 'memcpy' is unsafe}}
-  std::__1::strcpy();              // expected-warning{{function 'strcpy' is unsafe}}
-
-  /* Test printfs */
-  std::snprintf(s.data(), 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
-  std::__1::snprintf(s.data(), 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
-  std::snprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // no warn
-  std::__1::snprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // no warn
-}
-
-void v(std::string s1) {
-  std::snprintf(s1.data(), s1.size_bytes(), "%s%d", s1.c_str(), 0); // no warn
-  std::__1::snprintf(s1.data(), s1.size_bytes(), "%s%d", s1.c_str(), 0); // no warn
-}
-
-void g(char *begin, char *end, char *p, std::span<char> s) {
-  std::copy(begin, end, p); // no warn
-  std::copy(s.begin(), s.end(), s.begin()); // no warn
-}

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
deleted file mode 100644
index 1a29654f660c97..00000000000000
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \
-// RUN:            -verify %s
-
-typedef struct {} FILE;
-void memcpy();
-void __asan_memcpy();
-void strcpy();
-void strcpy_s();
-void wcscpy_s();
-unsigned strlen( const char* str );
-int fprintf( FILE* stream, const char* format, ... );
-int printf( const char* format, ... );
-int sprintf( char* buffer, const char* format, ... );
-int swprintf( char* buffer, const char* format, ... );
-int snprintf( char* buffer, unsigned buf_size, const char* format, ... );
-int snwprintf( char* buffer, unsigned buf_size, const char* format, ... );
-int snwprintf_s( char* buffer, unsigned buf_size, const char* format, ... );
-int vsnprintf( char* buffer, unsigned buf_size, const char* format, ... );
-int sscanf_s(const char * buffer, const char * format, ...);
-int sscanf(const char * buffer, const char * format, ... );
-
-namespace std {
-  template< class InputIt, class OutputIt >
-  OutputIt copy( InputIt first, InputIt last,
-		 OutputIt d_first );
-
-  struct iterator{};
-  template<typename T>
-  struct span {
-    T * ptr;
-    T * data();
-    unsigned size_bytes();
-    unsigned size();
-    iterator begin() const noexcept;
-    iterator end() const noexcept;
-  };
-
-  template<typename T>
-  struct basic_string {
-    T* p;
-    T *c_str();
-    T *data();
-    unsigned size_bytes();
-  };
-
-  typedef basic_string<char> string;
-  typedef basic_string<wchar_t> wstring;
-
-  // C function under std:
-  void memcpy();
-  void strcpy();
-}
-
-void f(char * p, char * q, std::span<char> s, std::span<char> s2) {
-  memcpy();                   // expected-warning{{function 'memcpy' is unsafe}}
-  std::memcpy();              // expected-warning{{function 'memcpy' is unsafe}}
-  __builtin_memcpy(p, q, 64); // expected-warning{{function '__builtin_memcpy' is unsafe}}
-  __builtin___memcpy_chk(p, q, 8, 64);  // expected-warning{{function '__builtin___memcpy_chk' is unsafe}}
-  __asan_memcpy();                      // expected-warning{{function '__asan_memcpy' is unsafe}}
-  strcpy();                   // expected-warning{{function 'strcpy' is unsafe}}
-  std::strcpy();              // expected-warning{{function 'strcpy' is unsafe}}
-  strcpy_s();                 // expected-warning{{function 'strcpy_s' is unsafe}}
-  wcscpy_s();                 // expected-warning{{function 'wcscpy_s' is unsafe}}
-
-
-  /* Test printfs */
-  fprintf((FILE*)p, "%s%d", p, *p);  // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
-  printf("%s%d", // expected-warning{{function 'printf' is unsafe}}
-	 p,    // expected-note{{string argument is not guaranteed to be null-terminated}} note attached to the unsafe argument
-	 *p);
-  sprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'sprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}}
-  swprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'swprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}}
-  snprintf(q, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
-  snprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
-  snwprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snwprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
-  snwprintf_s(                      // expected-warning{{function 'snwprintf_s' is unsafe}}
-	      s.data(),             // expected-note{{buffer pointer and size may not match}} // note attached to the buffer
-	      s2.size(),
-	      "%s%d", "hello", *p);
-  vsnprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // expected-warning{{function 'vsnprintf' is unsafe}} expected-note{{'va_list' is unsafe}}
-  sscanf(p, "%s%d", "hello", *p);    // expected-warning{{function 'sscanf' is unsafe}}
-  sscanf_s(p, "%s%d", "hello", *p);  // expected-warning{{function 'sscanf_s' is unsafe}}
-  fprintf((FILE*)p, "%P%d%p%i hello world %32s", *p, *p, p, *p, p); // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
-  fprintf((FILE*)p, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn
-  printf("%s%d", "hello", *p); // no warn
-  snprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // no warn
-  snprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
-  snwprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
-  snwprintf_s(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
-  strlen("hello");// no warn
-}
-
-void v(std::string s1, int *p) {
-  snprintf(s1.data(), s1.size_bytes(), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn
-  snprintf(s1.data(), s1.size_bytes(), s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str());      // no warn
-  printf("%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str());              // no warn
-  printf(s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str());                   // no warn
-  fprintf((FILE*)0, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str());   // no warn
-  fprintf((FILE*)0, s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str());        // no warn
-}
-
-
-void g(char *begin, char *end, char *p, std::span<char> s) {
-  std::copy(begin, end, p); // no warn
-  std::copy(s.begin(), s.end(), s.begin()); // no warn
-}

diff  --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp
index 989931e41c0cc1..844311c3a51a58 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-test-unreachable.cpp
@@ -1,6 +1,8 @@
 // RUN: %clang_cc1 -std=c++20 -Wunsafe-buffer-usage -fsafe-buffer-usage-suggestions -verify %s
 
+// expected-no-diagnostics
+
 typedef unsigned __darwin_size_t;
 typedef __darwin_size_t size_t;
  #define bzero(s, n) __builtin_bzero(s, n)
-void __nosan_bzero(void *dst, size_t sz) { bzero(dst, sz); } // expected-warning{{function '__builtin_bzero' is unsafe}}
+void __nosan_bzero(void *dst, size_t sz) { bzero(dst, sz); }


        


More information about the cfe-commits mailing list