[clang] 96d3319 - Sema: relax va_start checking further for Windows AArch64

Saleem Abdulrasool via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 20 14:24:09 PDT 2021


Author: Saleem Abdulrasool
Date: 2021-09-20T21:23:33Z
New Revision: 96d3319d6f024b17ac725d9595548acc4787003c

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

LOG: Sema: relax va_start checking further for Windows AArch64

When building in C mode, the VC runtime assumes that it can use pointer
aliasing through `char *` for the parameter to `__va_start`.  Relax the
checks further.  In theory we could keep the tests strict for non-system
header code, but this takes the less strict approach as the additional
check doesn't particularly end up being too much more helpful for
correctness.  The C++ type system is a bit stricter and requires the
explicit cast which we continue to verify.

Added: 
    clang/test/Sema/microsoft-varargs.c

Modified: 
    clang/lib/Sema/SemaChecking.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 99cd2b2278f1..0c47fb040d60 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -6413,6 +6413,21 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) {
 }
 
 bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) {
+  auto IsSuitablyTypedFormatArgument = [this](const Expr *Arg) -> bool {
+    const LangOptions &LO = getLangOpts();
+
+    if (LO.CPlusPlus)
+      return Arg->getType()
+                 .getCanonicalType()
+                 .getTypePtr()
+                 ->getPointeeType()
+                 .withoutLocalFastQualifiers() == Context.CharTy;
+
+    // In C, allow aliasing through `char *`, this is required for AArch64 at
+    // least.
+    return true;
+  };
+
   // void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
   //                 const char *named_addr);
 
@@ -6441,8 +6456,7 @@ bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) {
 
   const QualType &ConstCharPtrTy =
       Context.getPointerType(Context.CharTy.withConst());
-  if (!Arg1Ty->isPointerType() ||
-      Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy)
+  if (!Arg1Ty->isPointerType() || !IsSuitablyTypedFormatArgument(Arg1))
     Diag(Arg1->getBeginLoc(), diag::err_typecheck_convert_incompatible)
         << Arg1->getType() << ConstCharPtrTy << 1 /* 
diff erent class */
         << 0                                      /* qualifier 
diff erence */

diff  --git a/clang/test/Sema/microsoft-varargs.c b/clang/test/Sema/microsoft-varargs.c
new file mode 100644
index 000000000000..979875e8cbae
--- /dev/null
+++ b/clang/test/Sema/microsoft-varargs.c
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -fsyntax-only -x c %s -verify
+// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -fsyntax-only -x c %s -verify
+// RUN: %clang_cc1 -triple thumbv7-unknown-windows-msvc -fsyntax-only -x c++ %s -verify
+// RUN: %clang_cc1 -triple aarch64-unknown-windows-msvc -fsyntax-only -x c++ %s -verify
+// expected-no-diagnostics
+
+#if defined _NO_CRT_STDIO_INLINE
+#  undef _CRT_STDIO_INLINE
+#  define _CRT_STDIO_INLINE
+#elif !defined _CRT_STDIO_INLINE
+#  define _CRT_STDIO_INLINE __inline
+#endif
+
+#ifndef _VA_LIST_DEFINED
+#define _VA_LIST_DEFINED
+typedef char *va_list;
+#endif
+
+#if !defined __cplusplus
+// Workaround for /Zc:wchar_t
+typedef  __WCHAR_TYPE__ wchar_t;
+#endif
+
+#if defined __cplusplus
+#  define _ADDRESSOF(v) (&const_cast<char&>(reinterpret_cast<const volatile char&>(v)))
+#else
+#  define _ADDRESSOF(v) (&(v))
+#endif
+
+#if defined _M_ARM
+#  define _VA_ALIGN      4
+#  define _SLOTSIZEOF(t) ((sizeof(t) + _VA_ALIGN - 1) & ~(_VA_ALIGN - 1))
+#  define _APALIGN(t,ap) (((va_list)0 - (ap)) & (__alignof(t) - 1))
+#elif defined _M_ARM64
+#  define _VA_ALIGN      8
+#  define _SLOTSIZEOF(t) ((sizeof(t) + _VA_ALIGN - 1) & ~(_VA_ALIGN - 1))
+#  define _APALIGN(t,ap) (((va_list)0 - (ap)) & (__alignof(t) - 1))
+#endif
+
+#if defined _M_ARM
+void __cdecl __va_start(va_list*, ...);
+#  if defined __cplusplus
+#    define __crt_va_start_a(ap, v) ((void)(__va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), _ADDRESSOF(v))))
+#  else
+#    define __crt_va_start_a(ap, v) ((void)(ap = (va_list)_ADDRESSOF(v) + _SLOTSIZEOF(v)))
+#  endif
+
+#  define __crt_va_arg(ap, t) (*(t*)((ap += _SLOTSIZEOF(t) + _APALIGN(t,ap)) - _SLOTSIZEOF(t)))
+#  define __crt_va_end(ap)    ((void)(ap = (va_list)0))
+#elif defined _M_ARM64
+void __cdecl __va_start(va_list*, ...);
+#  define __crt_va_start_a(ap,v) ((void)(__va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), __alignof(v), _ADDRESSOF(v))))
+#  define __crt_va_arg(ap, t)                                                   \
+    ((sizeof(t) > (2 * sizeof(__int64)))                                        \
+       ? **(t**)((ap += sizeof(__int64)) - sizeof(__int64))                     \
+       : *(t*)((ap ++ _SLOTSIZEOF(t) + _APALIGN(t,ap)) - _SLOTSIZEOF(t)))
+#  define __crt_va_end(ap)       ((void)(ap = (va_list)0))
+#endif
+
+#if defined __cplusplus
+extern "C++" {
+template <typename _T>
+struct __vcrt_va_list_is_reference {
+  enum : bool { __the_value = false };
+};
+
+template <typename _T>
+struct __vcrt_va_list_is_reference<_T&> {
+  enum : bool { __the_value = true };
+};
+
+template <typename _T>
+struct __vcrt_va_list_is_reference<_T&&> {
+  enum : bool { __the_value = true };
+};
+
+template <typename _T>
+struct __vcrt_assert_va_start_is_not_reference {
+  static_assert(!__vcrt_va_list_is_reference<_T>::__the_value,
+                "va_start argument must not have reference type and must not be parenthesized");
+};
+}
+
+#  define __crt_va_start(ap, x) ((void)(__vcrt_assert_va_start_is_not_reference<decltype(x)>(), __crt_va_start_a(ap, x)))
+#else
+#  define __crt_va_start(ap, x) __crt_va_start_a(ap, x)
+#endif
+
+/*_Check_return_opt_*/ _CRT_STDIO_INLINE int __cdecl
+wprintf(/*_In_z_ _Printf_format_string_*/ wchar_t const * const _Format, ...) {
+  int _Result;
+  va_list _ArgList;
+  __crt_va_start(_ArgList, _Format);
+  // _Result = _vfwprintf_l(stdout, _Format, NULL, _ArgList);
+  __crt_va_end(_ArgList);
+  return _Result;
+}


        


More information about the cfe-commits mailing list