aaron.ballman created this revision.
aaron.ballman added reviewers: rsmith, dblaikie.
aaron.ballman added a subscriber: cfe-commits.
Herald added a subscriber: aemerson.

The va_start macro currently diagnoses passing a reference as the second 
argument (the one representing the parameter before the ellipsis) because this 
is undefined behavior in C++. This patch extends the checking to cover 
additional cases of undefined behavior in both C and C++. The C11 Standard, 
7.16.1.4p4 states, in part:

If the parameter parmN is declared with the register storage class, with a 
function or array type, or with a type that is not compatible with the type 
that results after application of the default argument promotions, the behavior 
is undefined.

(This is picked up by reference in C++ under [support.runtime]p3.)

This patch adds a check for default argument promotions as well as parameters 
declared with the register storage class. This helps cover some more of the 
CERT secure coding rule EXP58-CPP. Pass an object of the correct type to 
va_start 
(https://www.securecoding.cert.org/confluence/display/cplusplus/EXP58-CPP.+Pass+an+object+of+the+correct+type+to+va_start).

http://reviews.llvm.org/D19244

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaChecking.cpp
  test/Sema/varargs-x86-64.c
  test/Sema/varargs.c

Index: test/Sema/varargs.c
===================================================================
--- test/Sema/varargs.c
+++ test/Sema/varargs.c
@@ -18,12 +18,11 @@
     __builtin_va_start(ap, b);
 }
 
-void f3(float a, ...)
-{
+void f3(float a, ...) { // expected-note 2{{parameter of type 'float' is declared here}}
     __builtin_va_list ap;
 
-    __builtin_va_start(ap, a);
-    __builtin_va_start(ap, (a));
+    __builtin_va_start(ap, a); // expected-warning {{'va_start' has undefined behavior with types that undergo default argument promotion}}
+    __builtin_va_start(ap, (a)); // expected-warning {{'va_start' has undefined behavior with types that undergo default argument promotion}}
 }
 
 
@@ -83,3 +82,21 @@
   i = __builtin_va_start(ap, a); // expected-error {{assigning to 'int' from incompatible type 'void'}}
   __builtin_va_end(ap);
 }
+
+void f11(float f, ...) {  // expected-note {{parameter of type 'float' is declared here}}
+  __builtin_va_list ap;
+  __builtin_va_start(ap, f); // expected-warning {{'va_start' has undefined behavior with types that undergo default argument promotion}}
+  __builtin_va_end(ap);
+}
+
+void f12(short s, ...) {  // expected-note {{parameter of type 'short' is declared here}}
+  __builtin_va_list ap;
+  __builtin_va_start(ap, s); // expected-warning {{'va_start' has undefined behavior with types that undergo default argument promotion}}
+  __builtin_va_end(ap);
+}
+
+void f13(register int i, ...) {  // expected-note {{parameter of type 'int' is declared here}}
+  __builtin_va_list ap;
+  __builtin_va_start(ap, i); // expected-warning {{'va_start' has undefined behavior with an object declared with the register storage class}}
+  __builtin_va_end(ap);
+}
Index: test/Sema/varargs-x86-64.c
===================================================================
--- test/Sema/varargs-x86-64.c
+++ test/Sema/varargs-x86-64.c
@@ -26,11 +26,11 @@
   __builtin_ms_va_start(ap, b);
 }
 
-void __attribute__((ms_abi)) g3(float a, ...) {
+void __attribute__((ms_abi)) g3(float a, ...) { // expected-note 2{{parameter of type 'float' is declared here}}
   __builtin_ms_va_list ap;
 
-  __builtin_ms_va_start(ap, a);
-  __builtin_ms_va_start(ap, (a));
+  __builtin_ms_va_start(ap, a); // expected-warning {{'va_start' has undefined behavior with types that undergo default argument promotion}}
+  __builtin_ms_va_start(ap, (a)); // expected-warning {{'va_start' has undefined behavior with types that undergo default argument promotion}}
 }
 
 void __attribute__((ms_abi)) g5() {
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -2702,6 +2702,7 @@
   // block.
   QualType Type;
   SourceLocation ParamLoc;
+  bool IsRegister = false;
 
   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
     if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
@@ -2718,6 +2719,7 @@
 
       Type = PV->getType();
       ParamLoc = PV->getLocation();
+      IsRegister = PV->getStorageClass() == SC_Register;
     }
   }
 
@@ -2724,9 +2726,13 @@
   if (!SecondArgIsLastNamedArgument)
     Diag(TheCall->getArg(1)->getLocStart(),
          diag::warn_second_arg_of_va_start_not_last_named_param);
-  else if (Type->isReferenceType()) {
-    Diag(Arg->getLocStart(),
-         diag::warn_va_start_of_reference_type_is_undefined);
+  else if (IsRegister || Type->isReferenceType() ||
+           Type->isPromotableIntegerType() ||
+           Type->isSpecificBuiltinType(BuiltinType::Float)) {
+    unsigned Reason = 0;
+    if (Type->isReferenceType())  Reason = 1;
+    else if (IsRegister)          Reason = 2;
+    Diag(Arg->getLocStart(), diag::warn_va_start_type_is_undefined) << Reason;
     Diag(ParamLoc, diag::note_parameter_type) << Type;
   }
 
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7414,8 +7414,11 @@
 def warn_second_arg_of_va_start_not_last_named_param : Warning<
   "second argument to 'va_start' is not the last named parameter">,
   InGroup<Varargs>;
-def warn_va_start_of_reference_type_is_undefined : Warning<
-  "'va_start' has undefined behavior with reference types">, InGroup<Varargs>;
+def warn_va_start_type_is_undefined : Warning<
+  "'va_start' has undefined behavior with "
+  "%select{types that undergo default argument promotion|reference types|"
+  "an object declared with the register storage class}0">,
+  InGroup<Varargs>;
 def err_first_argument_to_va_arg_not_of_type_va_list : Error<
   "first argument to 'va_arg' is of type %0 and not 'va_list'">;
 def err_second_parameter_to_va_arg_incomplete: Error<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to