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).
llvm-svn: 267338
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<
+ "passing %select{an object that undergoes default argument promotion|"
+ "an object of reference type|a parameter declared with the 'register' "
+ "keyword}0 to 'va_start' has undefined behavior">, 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<
// block.
QualType Type;
SourceLocation ParamLoc;
+ bool IsCRegister = false;
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
Type = PV->getType();
ParamLoc = PV->getLocation();
+ IsCRegister =
+ PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus;
}
}
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 (IsCRegister || Type->isReferenceType() ||
+ Type->isPromotableIntegerType() ||
+ Type->isSpecificBuiltinType(BuiltinType::Float)) {
+ unsigned Reason = 0;
+ if (Type->isReferenceType()) Reason = 1;
+ else if (IsCRegister) Reason = 2;
+ Diag(Arg->getLocStart(), diag::warn_va_start_type_is_undefined) << Reason;
Diag(ParamLoc, diag::note_parameter_type) << Type;
}
__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 {{passing an object that undergoes default argument promotion to 'va_start' has undefined behavior}}
+ __builtin_ms_va_start(ap, (a)); // expected-warning {{passing an object that undergoes default argument promotion to 'va_start' has undefined behavior}}
}
void __attribute__((ms_abi)) g5() {
__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 {{passing an object that undergoes default argument promotion to 'va_start' has undefined behavior}}
+ __builtin_va_start(ap, (a)); // expected-warning {{passing an object that undergoes default argument promotion to 'va_start' has undefined behavior}}
}
i = __builtin_va_start(ap, a); // expected-error {{assigning to 'int' from incompatible type 'void'}}
__builtin_va_end(ap);
}
+
+void f11(short s, ...) { // expected-note {{parameter of type 'short' is declared here}}
+ __builtin_va_list ap;
+ __builtin_va_start(ap, s); // expected-warning {{passing an object that undergoes default argument promotion to 'va_start' has undefined behavior}}
+ __builtin_va_end(ap);
+}
+
+void f12(register int i, ...) { // expected-note {{parameter of type 'int' is declared here}}
+ __builtin_va_list ap;
+ __builtin_va_start(ap, i); // expected-warning {{passing a parameter declared with the 'register' keyword to 'va_start' has undefined behavior}}
+ __builtin_va_end(ap);
+}
+++ /dev/null
-// RUN: %clang_cc1 -fsyntax-only -verify %s
-
-class string;
-void f(const string& s, ...) { // expected-note {{parameter of type 'const string &' is declared here}}
- __builtin_va_list ap;
- __builtin_va_start(ap, s); // expected-warning {{'va_start' has undefined behavior with reference types}}
-}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -std=c++03 -verify %s
+
+class string;
+void f(const string& s, ...) { // expected-note {{parameter of type 'const string &' is declared here}}
+ __builtin_va_list ap;
+ __builtin_va_start(ap, s); // expected-warning {{passing an object of reference type to 'va_start' has undefined behavior}}
+}
+
+void g(register int i, ...) {
+ __builtin_va_list ap;
+ __builtin_va_start(ap, i); // okay
+}