[clang-tools-extra] [clang-tidy] Add deprecated-posix-functions check (PR #195641)

via cfe-commits cfe-commits at lists.llvm.org
Mon May 4 05:29:34 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-tidy

Author: Zeyi Xu (zeyi2)

<details>
<summary>Changes</summary>

In the discussion of #<!-- -->187830, we decided to split the original option in `bugprone-unsafe-functions` to a separate check. This commit implements it.

Currently these functions are checked:

```
bcmp  [deprecated]         -> memcmp 
bcopy [deprecated]         -> memmove
bzero [deprecated]         -> memset
getpw [deprecated, unsafe] -> getpwuid
vfork [deprecated]         -> posix_spawn
```

Also, the suggestion of `bcopy` is changed from `memcpy` to `memmove`, as `memcpy` might cause UB.

This is safe given the manpage:

> Marked as LEGACY in POSIX.1-2001: use memcpy(3) or memmove(3) in new programs. Note that the first two arguments are interchanged for memcpy(3) and memmove(3). POSIX.1-2008 removes the specification of bcopy().

As of AI Usage: Test cases helped by Claude.

Part of #<!-- -->187830

---
Full diff: https://github.com/llvm/llvm-project/pull/195641.diff


9 Files Affected:

- (modified) clang-tools-extra/clang-tidy/portability/CMakeLists.txt (+1) 
- (added) clang-tools-extra/clang-tidy/portability/DeprecatedPosixFunctionsCheck.cpp (+56) 
- (added) clang-tools-extra/clang-tidy/portability/DeprecatedPosixFunctionsCheck.h (+31) 
- (modified) clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp (+3) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+6) 
- (modified) clang-tools-extra/docs/clang-tidy/checks/list.rst (+1) 
- (added) clang-tools-extra/docs/clang-tidy/checks/portability/deprecated-posix-functions.rst (+15) 
- (added) clang-tools-extra/test/clang-tidy/checkers/portability/deprecated-posix-functions.c (+68) 
- (added) clang-tools-extra/test/clang-tidy/checkers/portability/deprecated-posix-functions.cpp (+91) 


``````````diff
diff --git a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
index 170fedf52130e..6723e4a727b21 100644
--- a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
 
 add_clang_library(clangTidyPortabilityModule STATIC
   AvoidPragmaOnceCheck.cpp
+  DeprecatedPosixFunctionsCheck.cpp
   NoAssemblerCheck.cpp
   PortabilityTidyModule.cpp
   RestrictSystemIncludesCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/portability/DeprecatedPosixFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/portability/DeprecatedPosixFunctionsCheck.cpp
new file mode 100644
index 0000000000000..74a8cfe94d813
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/portability/DeprecatedPosixFunctionsCheck.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeprecatedPosixFunctionsCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/StringSwitch.h"
+
+using namespace clang::ast_matchers;
+using namespace llvm;
+
+namespace clang::tidy::portability {
+
+static constexpr StringRef DeprecatedFunctionId = "DeprecatedFunctions";
+static constexpr StringRef DeclRefId = "DRE";
+
+static StringRef getReplacementFor(StringRef FunctionName) {
+  // TODO: Suggest Annex K replacements when available.
+  return StringSwitch<StringRef>(FunctionName)
+      .Case("bcmp", "memcmp")
+      .Case("bcopy", "memmove")
+      .Case("bzero", "memset")
+      .Case("getpw", "getpwuid")
+      .Case("vfork", "posix_spawn")
+      .Default({});
+}
+
+void DeprecatedPosixFunctionsCheck::registerMatchers(MatchFinder *Finder) {
+  const auto FunctionNamesMatcher =
+      hasAnyName("::bcmp", "::bcopy", "::bzero", "::getpw", "::vfork");
+  Finder->addMatcher(
+      declRefExpr(
+          to(functionDecl(FunctionNamesMatcher).bind(DeprecatedFunctionId)))
+          .bind(DeclRefId),
+      this);
+}
+
+void DeprecatedPosixFunctionsCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *SourceExpr = Result.Nodes.getNodeAs<DeclRefExpr>(DeclRefId);
+  const auto *FuncDecl =
+      Result.Nodes.getNodeAs<FunctionDecl>(DeprecatedFunctionId);
+  if (!SourceExpr || !FuncDecl)
+    return;
+
+  const StringRef FunctionName = FuncDecl->getName();
+  diag(SourceExpr->getBeginLoc(),
+       "function '%0' is deprecated; '%1' should be used instead")
+      << FunctionName << getReplacementFor(FunctionName);
+}
+
+} // namespace clang::tidy::portability
diff --git a/clang-tools-extra/clang-tidy/portability/DeprecatedPosixFunctionsCheck.h b/clang-tools-extra/clang-tidy/portability/DeprecatedPosixFunctionsCheck.h
new file mode 100644
index 0000000000000..af1d97e07dc3c
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/portability/DeprecatedPosixFunctionsCheck.h
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_DEPRECATEDPOSIXFUNCTIONSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_DEPRECATEDPOSIXFUNCTIONSCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::portability {
+
+/// Finds uses of deprecated or obsolete POSIX functions and suggests modern
+/// replacements.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/portability/deprecated-posix-functions.html
+class DeprecatedPosixFunctionsCheck : public ClangTidyCheck {
+public:
+  DeprecatedPosixFunctionsCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::portability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_DEPRECATEDPOSIXFUNCTIONSCHECK_H
diff --git a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
index 1f2340502f685..962a5337c5c35 100644
--- a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp
@@ -9,6 +9,7 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyModule.h"
 #include "AvoidPragmaOnceCheck.h"
+#include "DeprecatedPosixFunctionsCheck.h"
 #include "NoAssemblerCheck.h"
 #include "RestrictSystemIncludesCheck.h"
 #include "SIMDIntrinsicsCheck.h"
@@ -24,6 +25,8 @@ class PortabilityModule : public ClangTidyModule {
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
     CheckFactories.registerCheck<AvoidPragmaOnceCheck>(
         "portability-avoid-pragma-once");
+    CheckFactories.registerCheck<DeprecatedPosixFunctionsCheck>(
+        "portability-deprecated-posix-functions");
     CheckFactories.registerCheck<NoAssemblerCheck>("portability-no-assembler");
     CheckFactories.registerCheck<RestrictSystemIncludesCheck>(
         "portability-restrict-system-includes");
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index c9749df481bcd..cc3ace2c74200 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -175,6 +175,12 @@ New checks
   Suggests insertion of ``std::move(...)`` to turn copy assignment operator
   calls into move assignment ones, when deemed valid and profitable.
 
+- New :doc:`portability-deprecated-posix-functions
+  <clang-tidy/checks/portability/deprecated-posix-functions>` check.
+
+  Finds uses of deprecated or obsolete POSIX functions and suggests modern
+  replacements.
+
 - New :doc:`readability-redundant-lambda-parameter-list
   <clang-tidy/checks/readability/redundant-lambda-parameter-list>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 053ce6f0779d9..d19cbfff4598a 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -371,6 +371,7 @@ Clang-Tidy Checks
    :doc:`performance-unnecessary-value-param <performance/unnecessary-value-param>`, "Yes"
    :doc:`performance-use-std-move <performance/use-std-move>`, "Yes"
    :doc:`portability-avoid-pragma-once <portability/avoid-pragma-once>`,
+   :doc:`portability-deprecated-posix-functions <portability/deprecated-posix-functions>`,
    :doc:`portability-no-assembler <portability/no-assembler>`,
    :doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes"
    :doc:`portability-simd-intrinsics <portability/simd-intrinsics>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/deprecated-posix-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/deprecated-posix-functions.rst
new file mode 100644
index 0000000000000..c02dac67c8fd8
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/portability/deprecated-posix-functions.rst
@@ -0,0 +1,15 @@
+.. title:: clang-tidy - portability-deprecated-posix-functions
+
+portability-deprecated-posix-functions
+======================================
+
+Finds uses of deprecated or obsolete POSIX functions and suggests modern
+replacements.
+
+The following functions are checked:
+
+- ``bcmp``, suggested replacement: ``memcmp``
+- ``bcopy``, suggested replacement: ``memmove``
+- ``bzero``, suggested replacement: ``memset``
+- ``getpw``, suggested replacement: ``getpwuid``
+- ``vfork``, suggested replacement: ``posix_spawn``
diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/deprecated-posix-functions.c b/clang-tools-extra/test/clang-tidy/checkers/portability/deprecated-posix-functions.c
new file mode 100644
index 0000000000000..a286db0559753
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/portability/deprecated-posix-functions.c
@@ -0,0 +1,68 @@
+// RUN: %check_clang_tidy %s portability-deprecated-posix-functions %t
+
+typedef __SIZE_TYPE__ size_t;
+typedef int pid_t;
+typedef int uid_t;
+
+int bcmp(const void *S1, const void *S2, size_t N);
+void bcopy(const void *Src, void *Dest, size_t N);
+void bzero(void *S, size_t N);
+int getpw(uid_t UId, char *Buf);
+pid_t vfork(void);
+
+#define CALL_BZERO(Buffer, Size) bzero(Buffer, Size)
+#define DEPRECATED_BCMP bcmp
+
+void deprecated_posix_functions(void) {
+  char Buf1[128] = {0};
+  char Buf2[128] = {0};
+
+  bcmp(Buf1, Buf2, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+
+  bcopy(Buf1, Buf2, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bcopy' is deprecated; 'memmove' should be used instead [portability-deprecated-posix-functions]
+
+  bzero(Buf1, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bzero' is deprecated; 'memset' should be used instead [portability-deprecated-posix-functions]
+
+  getpw(0, Buf1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'getpw' is deprecated; 'getpwuid' should be used instead [portability-deprecated-posix-functions]
+
+  vfork();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'vfork' is deprecated; 'posix_spawn' should be used instead [portability-deprecated-posix-functions]
+
+  int (*BcmpPtr)(const void *, const void *, size_t) = bcmp;
+  // CHECK-MESSAGES: :[[@LINE-1]]:56: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+
+  CALL_BZERO(Buf1, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bzero' is deprecated; 'memset' should be used instead [portability-deprecated-posix-functions]
+
+  DEPRECATED_BCMP(Buf1, Buf2, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+}
+
+void deprecated_posix_functions_in_control_flow(int Flag) {
+  char Buf1[128] = {0};
+  char Buf2[128] = {0};
+
+  if (bcmp(Buf1, Buf2, sizeof(Buf1)) == 0)
+    return;
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+
+  for (int I = 0; I < 2; ++I)
+    bzero(Buf1, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'bzero' is deprecated; 'memset' should be used instead [portability-deprecated-posix-functions]
+
+  while (getpw(0, Buf1) == 0)
+    break;
+  // CHECK-MESSAGES: :[[@LINE-2]]:10: warning: function 'getpw' is deprecated; 'getpwuid' should be used instead [portability-deprecated-posix-functions]
+
+  Flag ? bcopy(Buf1, Buf2, sizeof(Buf1)) : bzero(Buf2, sizeof(Buf2));
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: function 'bcopy' is deprecated; 'memmove' should be used instead [portability-deprecated-posix-functions]
+  // CHECK-MESSAGES: :[[@LINE-2]]:44: warning: function 'bzero' is deprecated; 'memset' should be used instead [portability-deprecated-posix-functions]
+
+  if (Flag && vfork() == 0)
+    return;
+  // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: function 'vfork' is deprecated; 'posix_spawn' should be used instead [portability-deprecated-posix-functions]
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/deprecated-posix-functions.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/deprecated-posix-functions.cpp
new file mode 100644
index 0000000000000..a0f04be5675bf
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/portability/deprecated-posix-functions.cpp
@@ -0,0 +1,91 @@
+// RUN: %check_clang_tidy %s portability-deprecated-posix-functions %t
+
+typedef __SIZE_TYPE__ size_t;
+typedef int pid_t;
+typedef int uid_t;
+
+int bcmp(const void *S1, const void *S2, size_t N);
+void bcopy(const void *Src, void *Dest, size_t N);
+void bzero(void *S, size_t N);
+int getpw(uid_t UId, char *Buf);
+pid_t vfork(void);
+
+#define CALL_BZERO(Buffer, Size) bzero(Buffer, Size)
+#define DEPRECATED_BCMP bcmp
+
+void deprecated_posix_functions() {
+  char Buf1[128] = {0};
+  char Buf2[128] = {0};
+
+  bcmp(Buf1, Buf2, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+
+  bcopy(Buf1, Buf2, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bcopy' is deprecated; 'memmove' should be used instead [portability-deprecated-posix-functions]
+
+  bzero(Buf1, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bzero' is deprecated; 'memset' should be used instead [portability-deprecated-posix-functions]
+
+  getpw(0, Buf1);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'getpw' is deprecated; 'getpwuid' should be used instead [portability-deprecated-posix-functions]
+
+  vfork();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'vfork' is deprecated; 'posix_spawn' should be used instead [portability-deprecated-posix-functions]
+
+  auto BcmpPtr = &bcmp;
+  // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+
+  CALL_BZERO(Buf1, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bzero' is deprecated; 'memset' should be used instead [portability-deprecated-posix-functions]
+
+  DEPRECATED_BCMP(Buf1, Buf2, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+
+  ::bcmp(Buf1, Buf2, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+}
+
+void deprecated_posix_functions_in_control_flow(bool Flag) {
+  char Buf1[128] = {0};
+  char Buf2[128] = {0};
+
+  if (bcmp(Buf1, Buf2, sizeof(Buf1)) == 0)
+    return;
+  // CHECK-MESSAGES: :[[@LINE-2]]:7: warning: function 'bcmp' is deprecated; 'memcmp' should be used instead [portability-deprecated-posix-functions]
+
+  for (int I = 0; I < 2; ++I)
+    bzero(Buf1, sizeof(Buf1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'bzero' is deprecated; 'memset' should be used instead [portability-deprecated-posix-functions]
+
+  while (getpw(0, Buf1) == 0)
+    break;
+  // CHECK-MESSAGES: :[[@LINE-2]]:10: warning: function 'getpw' is deprecated; 'getpwuid' should be used instead [portability-deprecated-posix-functions]
+
+  Flag ? bcopy(Buf1, Buf2, sizeof(Buf1)) : bzero(Buf2, sizeof(Buf2));
+  // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: function 'bcopy' is deprecated; 'memmove' should be used instead [portability-deprecated-posix-functions]
+  // CHECK-MESSAGES: :[[@LINE-2]]:44: warning: function 'bzero' is deprecated; 'memset' should be used instead [portability-deprecated-posix-functions]
+
+  if (Flag && vfork() == 0)
+    return;
+  // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: function 'vfork' is deprecated; 'posix_spawn' should be used instead [portability-deprecated-posix-functions]
+}
+
+namespace non_posix {
+int bcmp(const void *S1, const void *S2, size_t N);
+void bcopy(const void *Src, void *Dest, size_t N);
+void bzero(void *S, size_t N);
+int getpw(uid_t UId, char *Buf);
+pid_t vfork(void);
+
+void same_unqualified_names() {
+  char Buf1[128] = {0};
+  char Buf2[128] = {0};
+
+  // No warnings for functions with the same unqualified names outside the global namespace.
+  bcmp(Buf1, Buf2, sizeof(Buf1));
+  bcopy(Buf1, Buf2, sizeof(Buf1));
+  bzero(Buf1, sizeof(Buf1));
+  getpw(0, Buf1);
+  vfork();
+}
+} // namespace non_posix

``````````

</details>


https://github.com/llvm/llvm-project/pull/195641


More information about the cfe-commits mailing list