[clang-tools-extra] c2e9baf - [clang-tidy] Fix cppcoreguidelines-pro-type-vararg false positives with __builtin_ms_va_list

Georgy Komarov via cfe-commits cfe-commits at lists.llvm.org
Tue May 4 03:49:29 PDT 2021


Author: Georgy Komarov
Date: 2021-05-04T13:49:20+03:00
New Revision: c2e9baf2e8dafe92f57fe4171d4b6a5f50d5999e

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

LOG: [clang-tidy] Fix cppcoreguidelines-pro-type-vararg false positives with __builtin_ms_va_list

This commit fixes cppcoreguidelines-pro-type-vararg false positives on
'char *' variables.

The incorrect warnings generated by clang-tidy can be illustrated with
the following minimal example:

```
goid foo(char* in) {
  char *tmp = in;
}
```

The problem is that __builtin_ms_va_list desugared as 'char *', which
leads to false positives.

Fixes bugzilla issue 48042.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D101259

Added: 
    clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg-ms.cpp

Modified: 
    clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp
    clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp

Removed: 
    


################################################################################
diff  --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp
index ec0e87ae22c05..b26cd59fd672a 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp
@@ -10,6 +10,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/TargetInfo.h"
 
 using namespace clang::ast_matchers;
 
@@ -60,8 +61,45 @@ namespace {
 AST_MATCHER(QualType, isVAList) {
   ASTContext &Context = Finder->getASTContext();
   QualType Desugar = Node.getDesugaredType(Context);
-  return Context.getBuiltinVaListType().getDesugaredType(Context) == Desugar ||
-         Context.getBuiltinMSVaListType().getDesugaredType(Context) == Desugar;
+  QualType NodeTy = Node.getUnqualifiedType();
+
+  auto CheckVaList = [](QualType NodeTy, QualType Expected,
+                        const ASTContext &Context) {
+    if (NodeTy == Expected)
+      return true;
+    QualType Desugar = NodeTy;
+    QualType Ty;
+    do {
+      Ty = Desugar;
+      Desugar = Ty.getSingleStepDesugaredType(Context);
+      if (Desugar == Expected)
+        return true;
+    } while (Desugar != Ty);
+    return false;
+  };
+
+  // The internal implementation of __builtin_va_list depends on the target
+  // type. Some targets implements va_list as 'char *' or 'void *'.
+  // In these cases we need to remove all typedefs one by one to check this.
+  using BuiltinVaListKind = TargetInfo::BuiltinVaListKind;
+  BuiltinVaListKind VaListKind = Context.getTargetInfo().getBuiltinVaListKind();
+  if (VaListKind == BuiltinVaListKind::CharPtrBuiltinVaList ||
+      VaListKind == BuiltinVaListKind::VoidPtrBuiltinVaList) {
+    if (CheckVaList(NodeTy, Context.getBuiltinVaListType(), Context))
+      return true;
+  } else if (Desugar ==
+             Context.getBuiltinVaListType().getDesugaredType(Context)) {
+    return true;
+  }
+
+  // We also need to check the implementation of __builtin_ms_va_list in the
+  // same way, because it may 
diff er from the va_list implementation.
+  if (Desugar == Context.getBuiltinMSVaListType().getDesugaredType(Context) &&
+      CheckVaList(NodeTy, Context.getBuiltinMSVaListType(), Context)) {
+    return true;
+  }
+
+  return false;
 }
 
 AST_MATCHER_P(AdjustedType, hasOriginalType,

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg-ms.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg-ms.cpp
new file mode 100644
index 0000000000000..9cb82497a3aec
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg-ms.cpp
@@ -0,0 +1,26 @@
+// Purpose:
+// Ensure that the 'cppcoreguidelines-pro-type-vararg' check works with the
+// built-in va_list on Windows systems.
+
+// REQUIRES: system-windows
+
+// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-vararg %t
+
+void test_ms_va_list(int a, ...) {
+  __builtin_ms_va_list ap;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead
+  __builtin_ms_va_start(ap, a);
+  int b = __builtin_va_arg(ap, int);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use va_arg to define c-style vararg functions; use variadic templates instead
+  __builtin_ms_va_end(ap);
+}
+
+void test_typedefs(int a, ...) {
+  typedef __builtin_ms_va_list my_va_list1;
+  my_va_list1 ap1;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead
+
+  using my_va_list2 = __builtin_ms_va_list;
+  my_va_list2 ap2;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead
+}

diff  --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp
index 1e3b5ee036ca1..e5bf98f02d8b3 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines-pro-type-vararg.cpp
@@ -58,3 +58,11 @@ void ignoredBuiltinsTest() {
   (void)__builtin_isinf_sign(0.f);
   (void)__builtin_prefetch(nullptr);
 }
+
+// Some implementations of __builtin_va_list and __builtin_ms_va_list desugared
+// as 'char *' or 'void *'. This test checks whether we are handling this case
+// correctly and not generating false positives.
+void no_false_positive_desugar_va_list(char *in) {
+  char *tmp1 = in;
+  void *tmp2 = in;
+}


        


More information about the cfe-commits mailing list