From 8423e57caae976cddbc1f9f68ebf6fef595cae83 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Sun, 2 Aug 2015 23:14:18 +0000 Subject: [PATCH] c.opt (-Wframe-address): New warning option. gcc/ChangeLog 2015-07-28 Martin Sebor * c-family/c.opt (-Wframe-address): New warning option. * doc/invoke.texi (Wframe-address): Document it. * doc/extend.texi (__builtin_frame_address, __builtin_return_address): Clarify possible effects of calling the functions with non-zero arguments and mention -Wframe-address. * builtins.c (expand_builtin_frame_address): Handle -Wframe-address. gcc/testsuite/ChangeLog 2015-07-28 Martin Sebor * g++.dg/Wframe-address-in-Wall.C: New test. * g++.dg/Wframe-address.C: New test. * g++.dg/Wno-frame-address.C: New test. * gcc.dg/Wframe-address-in-Wall.c: New test. * gcc.dg/Wframe-address.c: New test. * gcc.dg/Wno-frame-address.c: New test. From-SVN: r226480 --- gcc/ChangeLog | 9 +++ gcc/builtins.c | 28 ++++---- gcc/c-family/c.opt | 4 ++ gcc/doc/extend.texi | 14 ++-- gcc/doc/invoke.texi | 9 ++- gcc/testsuite/ChangeLog | 9 +++ gcc/testsuite/g++.dg/Wframe-address-in-Wall.C | 14 ++++ gcc/testsuite/g++.dg/Wframe-address.C | 70 +++++++++++++++++++ gcc/testsuite/g++.dg/Wno-frame-address.C | 6 ++ gcc/testsuite/gcc.dg/Wframe-address-in-Wall.c | 14 ++++ gcc/testsuite/gcc.dg/Wframe-address.c | 54 ++++++++++++++ gcc/testsuite/gcc.dg/Wno-frame-address.c | 6 ++ 12 files changed, 220 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/g++.dg/Wframe-address-in-Wall.C create mode 100644 gcc/testsuite/g++.dg/Wframe-address.C create mode 100644 gcc/testsuite/g++.dg/Wno-frame-address.C create mode 100644 gcc/testsuite/gcc.dg/Wframe-address-in-Wall.c create mode 100644 gcc/testsuite/gcc.dg/Wframe-address.c create mode 100644 gcc/testsuite/gcc.dg/Wno-frame-address.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c565bfc1b41..25cb049708e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2015-08-02 Martin Sebor + + * c-family/c.opt (-Wframe-address): New warning option. + * doc/invoke.texi (Wframe-address): Document it. + * doc/extend.texi (__builtin_frame_address, __builtin_return_address): + Clarify possible effects of calling the functions with non-zero + arguments and mention -Wframe-address. + * builtins.c (expand_builtin_frame_address): Handle -Wframe-address. + 2015-08-01 Michael Collison diff --git a/gcc/builtins.c b/gcc/builtins.c index d7eb65f930b..eb7b7b2bbac 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -4551,34 +4551,38 @@ expand_builtin_frame_address (tree fndecl, tree exp) { /* The argument must be a nonnegative integer constant. It counts the number of frames to scan up the stack. - The value is the return address saved in that frame. */ + The value is either the frame pointer value or the return + address saved in that frame. */ if (call_expr_nargs (exp) == 0) /* Warning about missing arg was already issued. */ return const0_rtx; else if (! tree_fits_uhwi_p (CALL_EXPR_ARG (exp, 0))) { - if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) - error ("invalid argument to %<__builtin_frame_address%>"); - else - error ("invalid argument to %<__builtin_return_address%>"); + error ("invalid argument to %qD", fndecl); return const0_rtx; } else { - rtx tem - = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl), - tree_to_uhwi (CALL_EXPR_ARG (exp, 0))); + /* Number of frames to scan up the stack. */ + unsigned HOST_WIDE_INT count = tree_to_uhwi (CALL_EXPR_ARG (exp, 0)); + + rtx tem = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl), count); /* Some ports cannot access arbitrary stack frames. */ if (tem == NULL) { - if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) - warning (0, "unsupported argument to %<__builtin_frame_address%>"); - else - warning (0, "unsupported argument to %<__builtin_return_address%>"); + warning (0, "unsupported argument to %qD", fndecl); return const0_rtx; } + if (count) + { + /* Warn since no effort is made to ensure that any frame + beyond the current one exists or can be safely reached. */ + warning (OPT_Wframe_address, "calling %qD with " + "a nonzero argument is unsafe", fndecl); + } + /* For __builtin_frame_address, return what we've got. */ if (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_FRAME_ADDRESS) return tem; diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index cb3af48dc47..4679038c90b 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -295,6 +295,10 @@ Wbool-compare C ObjC C++ ObjC++ Var(warn_bool_compare) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn about boolean expression compared with an integer value different from true/false +Wframe-address +C ObjC C++ ObjC++ Var(warn_frame_address) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) +Warn when __builtin_frame_address or __builtin_return_address is used unsafely + Wbuiltin-macro-redefined C ObjC C++ ObjC++ CPP(warn_builtin_macro_redefined) CppReason(CPP_W_BUILTIN_MACRO_REDEFINED) Var(cpp_warn_builtin_macro_redefined) Init(1) Warning Warn when a built-in preprocessor macro is undefined or redefined diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index b18d8fb11e0..9bf292ecdef 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -8652,8 +8652,11 @@ to determine if the top of the stack has been reached. Additional post-processing of the returned value may be needed, see @code{__builtin_extract_return_addr}. -This function should only be used with a nonzero argument for debugging -purposes. +Calling this function with a nonzero argument can have unpredictable +effects, including crashing the calling program. As a result, calls +that are considered unsafe are diagnosed when the @option{-Wframe-address} +option is in effect. Such calls should only be made in debugging +situations. @end deftypefn @deftypefn {Built-in Function} {void *} __builtin_extract_return_addr (void *@var{addr}) @@ -8691,8 +8694,11 @@ any function other than the current one; in such cases, or when the top of the stack has been reached, this function returns @code{0} if the first frame pointer is properly initialized by the startup code. -This function should only be used with a nonzero argument for debugging -purposes. +Calling this function with a nonzero argument can have unpredictable +effects, including crashing the calling program. As a result, calls +that are considered unsafe are diagnosed when the @option{-Wframe-address} +option is in effect. Such calls should only be made in debugging +situations. @end deftypefn @node Vector Extensions diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 7b5d86b62bb..f7daa02d658 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -241,7 +241,7 @@ Objective-C and Objective-C++ Dialects}. -pedantic-errors @gol -w -Wextra -Wall -Waddress -Waggregate-return @gol -Waggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol --Wbool-compare @gol +-Wbool-compare -Wframe-address @gol -Wno-attributes -Wno-builtin-macro-redefined @gol -Wc90-c99-compat -Wc99-c11-compat @gol -Wc++-compat -Wc++11-compat -Wc++14-compat -Wcast-align -Wcast-qual @gol @@ -4462,6 +4462,13 @@ if ((n > 1) == 2) @{ @dots{} @} @end smallexample This warning is enabled by @option{-Wall}. +@item -Wframe-address +@opindex Wno-frame-address +@opindex Wframe-address +Warn when the @samp{__builtin_frame_address} or @samp{__builtin_return_address} +is called with an argument greater than 0. Such calls may return indeterminate +values or crash the program. The warning is included in @option{-Wall}. + @item -Wno-discarded-qualifiers @r{(C and Objective-C only)} @opindex Wno-discarded-qualifiers @opindex Wdiscarded-qualifiers diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 82aa654a8bc..55bfb355cd8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2015-08-02 Martin Sebor + + * g++.dg/Wframe-address-in-Wall.C: New test. + * g++.dg/Wframe-address.C: New test. + * g++.dg/Wno-frame-address.C: New test. + * gcc.dg/Wframe-address-in-Wall.c: New test. + * gcc.dg/Wframe-address.c: New test. + * gcc.dg/Wno-frame-address.c: New test. + 2015-08-02 Patrick Palka * c-c++-common/Wmisleading-indentation.c: Add more tests. diff --git a/gcc/testsuite/g++.dg/Wframe-address-in-Wall.C b/gcc/testsuite/g++.dg/Wframe-address-in-Wall.C new file mode 100644 index 00000000000..2d945e56405 --- /dev/null +++ b/gcc/testsuite/g++.dg/Wframe-address-in-Wall.C @@ -0,0 +1,14 @@ +// { dg-do compile } +// { dg-options "-Wall" } + +// Verify that -Wframe-address is included in -Wall. + +void* test_builtin_address (unsigned i) +{ + void* const ba[] = { + __builtin_frame_address (4), // { dg-warning "builtin_frame_address" } + __builtin_return_address (4) // { dg-warning "builtin_return_address" } + }; + + return ba [i]; +} diff --git a/gcc/testsuite/g++.dg/Wframe-address.C b/gcc/testsuite/g++.dg/Wframe-address.C new file mode 100644 index 00000000000..229004ee6a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/Wframe-address.C @@ -0,0 +1,70 @@ +// { dg-do compile } +// { dg-options "-Wframe-address" } + +static void* const fa[] = { + __builtin_frame_address (0), + __builtin_frame_address (1), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (2), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (3), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (4) // { dg-warning "builtin_frame_address" } +}; + + +static void* const ra[] = { + __builtin_return_address (0), + __builtin_return_address (1), // { dg-warning "builtin_return_address" } + __builtin_return_address (2), // { dg-warning "builtin_return_address" } + __builtin_return_address (3), // { dg-warning "builtin_return_address" } + __builtin_return_address (4) // { dg-warning "builtin_return_address" } +}; + + +void* __attribute__ ((noclone, noinline)) +test_builtin_frame_address (unsigned i) +{ + void* const fa[] = { + __builtin_frame_address (0), + __builtin_frame_address (1), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (2), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (3), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (4) // { dg-warning "builtin_frame_address" } + }; + + return fa [i]; +} + + +void* __attribute__ ((noclone, noinline)) +test_builtin_return_address (unsigned i) +{ + void* const ra[] = { + __builtin_return_address (0), + __builtin_return_address (1), // { dg-warning "builtin_return_address" } + __builtin_return_address (2), // { dg-warning "builtin_return_address" } + __builtin_return_address (3), // { dg-warning "builtin_return_address" } + __builtin_return_address (4) // { dg-warning "builtin_return_address" } + }; + return ra [i]; +} + + +int main () +{ + test_builtin_frame_address (0); + + test_builtin_return_address (0); + + void* const a[] = { + __builtin_frame_address (0), + __builtin_frame_address (1), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (2), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (3), // { dg-warning "builtin_frame_address" } + __builtin_frame_address (4), // { dg-warning "builtin_frame_address" } + + __builtin_return_address (0), + __builtin_return_address (1), // { dg-warning "builtin_return_address" } + __builtin_return_address (2), // { dg-warning "builtin_return_address" } + __builtin_return_address (3), // { dg-warning "builtin_return_address" } + __builtin_return_address (4) // { dg-warning "builtin_return_address" } + }; +} diff --git a/gcc/testsuite/g++.dg/Wno-frame-address.C b/gcc/testsuite/g++.dg/Wno-frame-address.C new file mode 100644 index 00000000000..b19cb4334e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/Wno-frame-address.C @@ -0,0 +1,6 @@ +// { dg-do compile } +// { dg-options "-Werror" } + +// Verify that -Wframe-address is not enabled by default by enabling +// -Werror and verifying the test still compiles. +#include "Wframe-address.C" diff --git a/gcc/testsuite/gcc.dg/Wframe-address-in-Wall.c b/gcc/testsuite/gcc.dg/Wframe-address-in-Wall.c new file mode 100644 index 00000000000..70da9c80483 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wframe-address-in-Wall.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall" } */ + +/* Verify that -Wframe-address is included in -Wall. */ + +void* test_builtin_address (unsigned i) +{ + void* const ba[] = { + __builtin_frame_address (4), /* { dg-warning "builtin_frame_address" } */ + __builtin_return_address (4) /* { dg-warning "builtin_return_address" } */ + }; + + return ba [i]; +} diff --git a/gcc/testsuite/gcc.dg/Wframe-address.c b/gcc/testsuite/gcc.dg/Wframe-address.c new file mode 100644 index 00000000000..7481baf9acd --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wframe-address.c @@ -0,0 +1,54 @@ +/* { dg-do compile } */ +/* { dg-options "-Wframe-address" } */ + +void* __attribute__ ((noclone, noinline)) +test_builtin_frame_address (unsigned i) +{ + void* const fa[] = { + __builtin_frame_address (0), + __builtin_frame_address (1), /* { dg-warning "builtin_frame_address" } */ + __builtin_frame_address (2), /* { dg-warning "builtin_frame_address" } */ + __builtin_frame_address (3), /* { dg-warning "builtin_frame_address" } */ + __builtin_frame_address (4) /* { dg-warning "builtin_frame_address" } */ + }; + + return fa [i]; +} + + +void* __attribute__ ((noclone, noinline)) +test_builtin_return_address (unsigned i) +{ + void* const ra[] = { + __builtin_return_address (0), + __builtin_return_address (1), /* { dg-warning "builtin_return_address" } */ + __builtin_return_address (2), /* { dg-warning "builtin_return_address" } */ + __builtin_return_address (3), /* { dg-warning "builtin_return_address" } */ + __builtin_return_address (4) /* { dg-warning "builtin_return_address" } */ + }; + return ra [i]; +} + + +int main (void) +{ + test_builtin_frame_address (0); + + test_builtin_return_address (0); + + void* const a[] = { + __builtin_frame_address (0), + __builtin_frame_address (1), /* { dg-warning "builtin_frame_address" } */ + __builtin_frame_address (2), /* { dg-warning "builtin_frame_address" } */ + __builtin_frame_address (3), /* { dg-warning "builtin_frame_address" } */ + __builtin_frame_address (4), /* { dg-warning "builtin_frame_address" } */ + + __builtin_return_address (0), + __builtin_return_address (1), /* { dg-warning "builtin_return_address" } */ + __builtin_return_address (2), /* { dg-warning "builtin_return_address" } */ + __builtin_return_address (3), /* { dg-warning "builtin_return_address" } */ + __builtin_return_address (4) /* { dg-warning "builtin_return_address" } */ + }; + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/Wno-frame-address.c b/gcc/testsuite/gcc.dg/Wno-frame-address.c new file mode 100644 index 00000000000..f48b91a2bcb --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wno-frame-address.c @@ -0,0 +1,6 @@ +/* { dg-do compile } */ +/* { dg-options "-Werror" } */ + +/* Verify that -Wframe-address is not enabled by default by enabling + -Werror and verifying the test still compiles. */ +#include "Wframe-address.c" -- 2.30.2