Sema: Windows/ARM __va_start is not const correct
authorSaleem Abdulrasool <compnerd@compnerd.org>
Tue, 26 Sep 2017 17:44:10 +0000 (17:44 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Tue, 26 Sep 2017 17:44:10 +0000 (17:44 +0000)
The `__va_start` intrinsic for Windows ARM does not account for const
correctness when performing a check.  All local qualifiers are ignored
when validating the invocation.  This was exposed by building the swift
stdlib against the Windows 10586 SDK for ARM.  Simply expand out the
check for the two parameters and ignore the qualifiers for the check.

llvm-svn: 314226

clang/lib/Sema/SemaChecking.cpp
clang/test/SemaCXX/microsoft-varargs.cpp

index 1828dc6..962eb5d 100644 (file)
@@ -3943,23 +3943,33 @@ bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
   if (checkVAStartIsInVariadicFunction(*this, Func))
     return true;
 
-  const struct {
-    unsigned ArgNo;
-    QualType Type;
-  } ArgumentTypes[] = {
-    { 1, Context.getPointerType(Context.CharTy.withConst()) },
-    { 2, Context.getSizeType() },
-  };
-
-  for (const auto &AT : ArgumentTypes) {
-    const Expr *Arg = Call->getArg(AT.ArgNo)->IgnoreParens();
-    if (Arg->getType().getCanonicalType() == AT.Type.getCanonicalType())
-      continue;
-    Diag(Arg->getLocStart(), diag::err_typecheck_convert_incompatible)
-      << Arg->getType() << AT.Type << 1 /* different class */
-      << 0 /* qualifier difference */ << 3 /* parameter mismatch */
-      << AT.ArgNo + 1 << Arg->getType() << AT.Type;
-  }
+  // __va_start on Windows does not validate the parameter qualifiers
+
+  const Expr *Arg1 = Call->getArg(1)->IgnoreParens();
+  const Type *Arg1Ty = Arg1->getType().getCanonicalType().getTypePtr();
+
+  const Expr *Arg2 = Call->getArg(2)->IgnoreParens();
+  const Type *Arg2Ty = Arg2->getType().getCanonicalType().getTypePtr();
+
+  const QualType &ConstCharPtrTy =
+      Context.getPointerType(Context.CharTy.withConst());
+  if (!Arg1Ty->isPointerType() ||
+      Arg1Ty->getPointeeType().withoutLocalFastQualifiers() != Context.CharTy)
+    Diag(Arg1->getLocStart(), diag::err_typecheck_convert_incompatible)
+        << Arg1->getType() << ConstCharPtrTy
+        << 1 /* different class */
+        << 0 /* qualifier difference */
+        << 3 /* parameter mismatch */
+        << 2 << Arg1->getType() << ConstCharPtrTy;
+
+  const QualType SizeTy = Context.getSizeType();
+  if (Arg2Ty->getCanonicalTypeInternal().withoutLocalFastQualifiers() != SizeTy)
+    Diag(Arg2->getLocStart(), diag::err_typecheck_convert_incompatible)
+        << Arg2->getType() << SizeTy
+        << 1 /* different class */
+        << 0 /* qualifier difference */
+        << 3 /* parameter mismatch */
+        << 3 << Arg2->getType() << SizeTy;
 
   return false;
 }
index 35f31a9..5b0f90e 100644 (file)
@@ -20,3 +20,8 @@ int builtin(int i, ...) {
   return __builtin_va_arg(ap, int);
 }
 
+void test___va_start_ignore_const(const char *format, ...) {
+  va_list args;
+  ((void)(__va_start(&args, (&const_cast<char &>(reinterpret_cast<const volatile char &>(format))), ((sizeof(format) + 4 - 1) & ~(4 - 1)), (&const_cast<char &>(reinterpret_cast<const volatile char &>(format))))));
+}
+