Author: aaronballman Date: Sun Apr 24 08:30:21 2016 New Revision: 267338 URL: http://llvm.org/viewvc/llvm-project?rev=267338&view=rev Log: Improve diagnostic checking for va_start to also warn on other instances of undefined behavior, such as a parameter declared with the register keyword in C, or a parameter of a type that undergoes default argument promotion.
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). Added: cfe/trunk/test/SemaCXX/varargs.cpp Removed: cfe/trunk/test/Sema/varargs.cpp Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/test/Sema/varargs-x86-64.c cfe/trunk/test/Sema/varargs.c Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=267338&r1=267337&r2=267338&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Apr 24 08:30:21 2016 @@ -7435,8 +7435,10 @@ def err_ms_va_start_used_in_sysv_functio 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< Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=267338&r1=267337&r2=267338&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Sun Apr 24 08:30:21 2016 @@ -2702,6 +2702,7 @@ bool Sema::SemaBuiltinVAStartImpl(CallEx // 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())) { @@ -2718,15 +2719,21 @@ bool Sema::SemaBuiltinVAStartImpl(CallEx 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; } Modified: cfe/trunk/test/Sema/varargs-x86-64.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/varargs-x86-64.c?rev=267338&r1=267337&r2=267338&view=diff ============================================================================== --- cfe/trunk/test/Sema/varargs-x86-64.c (original) +++ cfe/trunk/test/Sema/varargs-x86-64.c Sun Apr 24 08:30:21 2016 @@ -26,11 +26,11 @@ void __attribute__((ms_abi)) g2(int a, i __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() { Modified: cfe/trunk/test/Sema/varargs.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/varargs.c?rev=267338&r1=267337&r2=267338&view=diff ============================================================================== --- cfe/trunk/test/Sema/varargs.c (original) +++ cfe/trunk/test/Sema/varargs.c Sun Apr 24 08:30:21 2016 @@ -18,12 +18,11 @@ void f2(int a, int b, ...) __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}} } @@ -83,3 +82,15 @@ void f10(int a, ...) { 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); +} Removed: cfe/trunk/test/Sema/varargs.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/varargs.cpp?rev=267337&view=auto ============================================================================== --- cfe/trunk/test/Sema/varargs.cpp (original) +++ cfe/trunk/test/Sema/varargs.cpp (removed) @@ -1,7 +0,0 @@ -// 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}} -} Added: cfe/trunk/test/SemaCXX/varargs.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/varargs.cpp?rev=267338&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/varargs.cpp (added) +++ cfe/trunk/test/SemaCXX/varargs.cpp Sun Apr 24 08:30:21 2016 @@ -0,0 +1,12 @@ +// 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 +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits