From patchwork Tue Jul 28 15:44:40 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 501292 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id D0A51140D15 for ; Wed, 29 Jul 2015 01:44:56 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=L0PSQ0wI; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; q=dns; s=default; b=hyyJtwKXEl3R2n2aB Yo1ljsShYWOObZmJPUuDOHJSQGLmXDCOdLTb8ggodrdMa2TFkQXNZZiLuS5TtBPi ef4gaQsmFJ5/+CCpOuYSIufqjupuS1pUw/nVGlpJxyPyXp7wLdspwc+UQR00Jdvr Vq+bvG41niN+2KKqhefu8WkpTE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:references :in-reply-to:content-type; s=default; bh=tpURV+MhSBokIyVvNK1KJuK uQDQ=; b=L0PSQ0wI5ntTxssrLSF+H9oWYjZ8H0zGjFAqRqf9ULU6/c8MMUXSuCV AYmRb1sDUQ2CJthPv1qXWnGk6kobta93CXd+oIXeZ6UIjttOExLVXB/K6Lc2Fyo4 g9Qe0qx2lQ9VnlV4WD45mRPf0RhPoNufvyUo8fb/9ZmgwXtkts0I= Received: (qmail 18863 invoked by alias); 28 Jul 2015 15:44:49 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 18853 invoked by uid 89); 28 Jul 2015 15:44:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.6 required=5.0 tests=BAYES_00, FREEMAIL_FROM, RCVD_IN_DNSWL_LOW, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-qg0-f41.google.com Received: from mail-qg0-f41.google.com (HELO mail-qg0-f41.google.com) (209.85.192.41) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Tue, 28 Jul 2015 15:44:46 +0000 Received: by qged69 with SMTP id d69so77592862qge.0 for ; Tue, 28 Jul 2015 08:44:44 -0700 (PDT) X-Received: by 10.140.218.198 with SMTP id o189mr52280374qhb.47.1438098284160; Tue, 28 Jul 2015 08:44:44 -0700 (PDT) Received: from [192.168.0.26] (71-215-74-68.hlrn.qwest.net. [71.215.74.68]) by smtp.gmail.com with ESMTPSA id e10sm11325951qka.40.2015.07.28.08.44.42 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 28 Jul 2015 08:44:43 -0700 (PDT) Message-ID: <55B7A368.3060200@gmail.com> Date: Tue, 28 Jul 2015 09:44:40 -0600 From: Martin Sebor User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.4.0 MIME-Version: 1.0 To: Segher Boessenkool CC: Jeff Law , Martin Sebor , Gcc Patch List Subject: Re: [PATCH] warn for unsafe calls to __builtin_return_address References: <555E2FC6.60804@redhat.com> <555E50A5.60309@redhat.com> <557A0617.6040605@redhat.com> <55B1C845.1030000@redhat.com> <20150725142035.GB7309@gate.crashing.org> <55B6F232.2080402@gmail.com> <20150728142406.GA14409@gate.crashing.org> In-Reply-To: <20150728142406.GA14409@gate.crashing.org> X-IsSubscribed: yes >> gcc/ChangeLog >> 2015-07-27 Martin Sebor >> >> * c-family/c.opt (-Wbuiltin-address): New warning option. >> * doc/invoke.texi (Wbuiltin-address): Document it. >> * doc/extend.texi (__builtin_frame_addrress, __builtin_return_addrress): > > Typoes (rr). Fixed. > >> - 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. */ >> + const unsigned HOST_WIDE_INT count = tree_to_uhwi (CALL_EXPR_ARG (exp, 0)); >> + >> + rtx tem = expand_builtin_return_addr (DECL_FUNCTION_CODE (fndecl), count); > > Do we need to say "const"? No, we don't. FWIW, I find code easier to think about when it's explicit about things like this, even if they have no semantic effect. But since it's not common practice I took the const out. > >> /* 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, "invalid argument to %qD", fndecl); > > "unsupported argument". Thanks, fixed. >> + if (0 < count) > > Yoda :-) You can just say "if (count)" fwiw. Sure. > This is not such a nice warning name, maybe -Wbuiltin-frame-address or > -Wframe-address? I renamed it to -Wframe-address. > I like the original "should only be used" better than that last line. Okay, reworded. > Elsewhere there was a "non-zero" btw, but we should use "nonzero" according > to the coding conventions. Huh. Changed. > Not all targets support weak. I replaced it with __attribute__((noclone, noinline)). Attached is an updated patch with the changes above. Thanks Martin 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. diff --git a/gcc/builtins.c b/gcc/builtins.c index e8fe3db..b7c5572 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -4564,34 +4564,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 285952e..ccbb399 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 9ad2b68..96b8b80 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -8562,8 +8562,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}) @@ -8601,8 +8604,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 5903c75..189d408 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 @@ -4436,6 +4436,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/g++.dg/Wframe-address-in-Wall.C b/gcc/testsuite/g++.dg/Wframe-address-in-Wall.C new file mode 100644 index 0000000..2d945e5 --- /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 0000000..229004e --- /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 0000000..b19cb43 --- /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 0000000..70da9c8 --- /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 0000000..7481baf --- /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 0000000..f48b91a --- /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"