Skip to content

Commit c2e9baf

Browse files
committed
[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
1 parent 34593ae commit c2e9baf

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeVarargCheck.cpp

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "clang/AST/ASTContext.h"
1111
#include "clang/ASTMatchers/ASTMatchFinder.h"
1212
#include "clang/ASTMatchers/ASTMatchers.h"
13+
#include "clang/Basic/TargetInfo.h"
1314

1415
using namespace clang::ast_matchers;
1516

@@ -60,8 +61,45 @@ namespace {
6061
AST_MATCHER(QualType, isVAList) {
6162
ASTContext &Context = Finder->getASTContext();
6263
QualType Desugar = Node.getDesugaredType(Context);
63-
return Context.getBuiltinVaListType().getDesugaredType(Context) == Desugar ||
64-
Context.getBuiltinMSVaListType().getDesugaredType(Context) == Desugar;
64+
QualType NodeTy = Node.getUnqualifiedType();
65+
66+
auto CheckVaList = [](QualType NodeTy, QualType Expected,
67+
const ASTContext &Context) {
68+
if (NodeTy == Expected)
69+
return true;
70+
QualType Desugar = NodeTy;
71+
QualType Ty;
72+
do {
73+
Ty = Desugar;
74+
Desugar = Ty.getSingleStepDesugaredType(Context);
75+
if (Desugar == Expected)
76+
return true;
77+
} while (Desugar != Ty);
78+
return false;
79+
};
80+
81+
// The internal implementation of __builtin_va_list depends on the target
82+
// type. Some targets implements va_list as 'char *' or 'void *'.
83+
// In these cases we need to remove all typedefs one by one to check this.
84+
using BuiltinVaListKind = TargetInfo::BuiltinVaListKind;
85+
BuiltinVaListKind VaListKind = Context.getTargetInfo().getBuiltinVaListKind();
86+
if (VaListKind == BuiltinVaListKind::CharPtrBuiltinVaList ||
87+
VaListKind == BuiltinVaListKind::VoidPtrBuiltinVaList) {
88+
if (CheckVaList(NodeTy, Context.getBuiltinVaListType(), Context))
89+
return true;
90+
} else if (Desugar ==
91+
Context.getBuiltinVaListType().getDesugaredType(Context)) {
92+
return true;
93+
}
94+
95+
// We also need to check the implementation of __builtin_ms_va_list in the
96+
// same way, because it may differ from the va_list implementation.
97+
if (Desugar == Context.getBuiltinMSVaListType().getDesugaredType(Context) &&
98+
CheckVaList(NodeTy, Context.getBuiltinMSVaListType(), Context)) {
99+
return true;
100+
}
101+
102+
return false;
65103
}
66104

67105
AST_MATCHER_P(AdjustedType, hasOriginalType,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Purpose:
2+
// Ensure that the 'cppcoreguidelines-pro-type-vararg' check works with the
3+
// built-in va_list on Windows systems.
4+
5+
// REQUIRES: system-windows
6+
7+
// RUN: %check_clang_tidy %s cppcoreguidelines-pro-type-vararg %t
8+
9+
void test_ms_va_list(int a, ...) {
10+
__builtin_ms_va_list ap;
11+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead
12+
__builtin_ms_va_start(ap, a);
13+
int b = __builtin_va_arg(ap, int);
14+
// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: do not use va_arg to define c-style vararg functions; use variadic templates instead
15+
__builtin_ms_va_end(ap);
16+
}
17+
18+
void test_typedefs(int a, ...) {
19+
typedef __builtin_ms_va_list my_va_list1;
20+
my_va_list1 ap1;
21+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead
22+
23+
using my_va_list2 = __builtin_ms_va_list;
24+
my_va_list2 ap2;
25+
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not declare variables of type va_list; use variadic templates instead
26+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,11 @@ void ignoredBuiltinsTest() {
5858
(void)__builtin_isinf_sign(0.f);
5959
(void)__builtin_prefetch(nullptr);
6060
}
61+
62+
// Some implementations of __builtin_va_list and __builtin_ms_va_list desugared
63+
// as 'char *' or 'void *'. This test checks whether we are handling this case
64+
// correctly and not generating false positives.
65+
void no_false_positive_desugar_va_list(char *in) {
66+
char *tmp1 = in;
67+
void *tmp2 = in;
68+
}

0 commit comments

Comments
 (0)