public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Sebor <msebor@gmail.com>
To: Segher Boessenkool <segher@kernel.crashing.org>,
	 Jeff Law <law@redhat.com>
Cc: Martin Sebor <msebor@redhat.com>,
	 Gcc Patch List <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH] warn for unsafe calls to __builtin_return_address
Date: Tue, 28 Jul 2015 03:44:00 -0000	[thread overview]
Message-ID: <55B6F232.2080402@gmail.com> (raw)
In-Reply-To: <20150725142035.GB7309@gate.crashing.org>

[-- Attachment #1: Type: text/plain, Size: 400 bytes --]

>> So, my suggestion would be to warn for any call with a nonzero value.
>
> The current documentation says that you should only use nonzero values
> for debug purposes.  A warning would help yes, how many people read the
> manual after all :-)

Thank you both for the feedback. Attached is a simplified patch
to issue a warning for all builtin_xxx_address calls with any
non-zero argument.

Martin


[-- Attachment #2: gcc-Wbuiltin-address.patch --]
[-- Type: text/x-patch, Size: 13282 bytes --]

gcc/ChangeLog
2015-07-27  Martin Sebor  <msebor@redhat.com>

    * 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):
    Clarify possible effects of calling the functions with non-zero
    arguments and mention -Wbuiltin-address.
    * builtins.c (expand_builtin_frame_address): Handle -Wbuiltin-address.

gcc/testsuite/ChangeLog
2015-07-27  Martin Sebor  <msebor@redhat.com>

    * g++.dg/Wbuiltin-address-in-Wall.C: New test.
    * g++.dg/Wbuiltin-address.C: New test.
    * g++.dg/Wno-builtin-address.C: New test.
    * gcc.dg/Wbuiltin-address-in-Wall.c: New test.
    * gcc.dg/Wbuiltin-address.c: New test.
    * gcc.dg/Wno-builtin-address.c: New test.

diff --git a/gcc/builtins.c b/gcc/builtins.c
index e8fe3db..48379f8 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.  */
+      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);

       /* 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);
 	  return const0_rtx;
 	}

+      if (0 < count)
+	{
+	  /* Warn since no effort is made to ensure that any frame
+	     beyond the current one exists or can be safely reached.  */
+	  warning (OPT_Wbuiltin_address, "calling %qD with "
+		   "a non-zero 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..bdff624 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

+Wbuiltin-address
+C ObjC C++ ObjC++ Var(warn_builtin_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..1b4596c 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{-Wbuiltin-address}
+option is in effect.  Such calls are typically only useful 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{-Wbuiltin-address}
+option is in effect.  Such calls are typically only useful in debugging
+situations.
 @end deftypefn

 @node Vector Extensions
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 5903c75..4e64108 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 -Wbuiltin-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 -Wbuiltin-address
+@opindex Wno-builtin-address
+@opindex Wbuiltin-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/Wbuiltin-address-in-Wall.C b/gcc/testsuite/g++.dg/Wbuiltin-address-in-Wall.C
new file mode 100644
index 0000000..aa9e17f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/Wbuiltin-address-in-Wall.C
@@ -0,0 +1,14 @@
+// { dg-do compile }
+// { dg-options "-Wall" }
+
+// Verify that -Wbuiltin-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/Wbuiltin-address.C b/gcc/testsuite/g++.dg/Wbuiltin-address.C
new file mode 100644
index 0000000..5e6ff74
--- /dev/null
+++ b/gcc/testsuite/g++.dg/Wbuiltin-address.C
@@ -0,0 +1,70 @@
+// { dg-do compile }
+// { dg-options "-Wbuiltin-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__ ((weak))
+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__ ((weak))
+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-builtin-address.C b/gcc/testsuite/g++.dg/Wno-builtin-address.C
new file mode 100644
index 0000000..a460649
--- /dev/null
+++ b/gcc/testsuite/g++.dg/Wno-builtin-address.C
@@ -0,0 +1,6 @@
+// { dg-do compile }
+// { dg-options "-Werror" }
+
+// Verify that -Wbuiltin-address is not enabled by default by enabling
+// -Werror and verifying the test still compiles.
+#include "Wbuiltin-address.C"
diff --git a/gcc/testsuite/gcc.dg/Wbuiltin-address-in-Wall.c b/gcc/testsuite/gcc.dg/Wbuiltin-address-in-Wall.c
new file mode 100644
index 0000000..9f73810
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wbuiltin-address-in-Wall.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+/* Verify that -Wbuiltin-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/Wbuiltin-address.c b/gcc/testsuite/gcc.dg/Wbuiltin-address.c
new file mode 100644
index 0000000..5483f5d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wbuiltin-address.c
@@ -0,0 +1,54 @@
+/* { dg-do compile } */
+/* { dg-options "-Wbuiltin-address" } */
+
+void* __attribute__ ((weak))
+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__ ((weak))
+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-builtin-address.c b/gcc/testsuite/gcc.dg/Wno-builtin-address.c
new file mode 100644
index 0000000..c2724d1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wno-builtin-address.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-Werror" } */
+
+/* Verify that -Wbuiltin-address is not enabled by default by enabling
+   -Werror and verifying the test still compiles.  */
+#include "Wbuiltin-address.c"

  reply	other threads:[~2015-07-28  3:08 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-05-21 19:37 [PATCH] clarify doc for __builtin_return_address Martin Sebor
2015-05-21 20:50 ` Sandra Loosemore
2015-05-21 21:22   ` Martin Sebor
2015-05-21 22:00 ` Pedro Alves
2015-06-11 23:22   ` [PATCH] warn for unsafe calls to __builtin_return_address Martin Sebor
2015-06-18 17:32     ` [PING] " Martin Sebor
2015-06-27  0:48       ` [PING 2] " Martin Sebor
2015-07-07  3:41         ` [PING 3] " Martin Sebor
2015-07-07 10:14           ` Pedro Alves
2015-07-24  5:30     ` Jeff Law
2015-07-25 15:59       ` Segher Boessenkool
2015-07-28  3:44         ` Martin Sebor [this message]
2015-07-28 15:19           ` Segher Boessenkool
2015-07-28 16:03             ` Martin Sebor
2015-07-31 16:46               ` Jeff Law
2015-08-02 23:15                 ` Martin Sebor
2015-08-03 11:55                   ` [BUILDROBOT] Go runtime: calling ‘__builtin_frame_address’ with a nonzero argument is unsafe (was: warn for unsafe calls to __builtin_return_address) Jan-Benedict Glaw
2015-08-03 14:48                     ` [BUILDROBOT] Go runtime: calling ‘__builtin_frame_address’ with a nonzero argument is unsafe Martin Sebor
2015-08-03 15:29                       ` Jeff Law
2015-08-05  7:28               ` [PATCH] warn for unsafe calls to __builtin_return_address Andreas Schwab
2015-08-05 16:03               ` Jiong Wang
2015-08-05 17:56                 ` Martin Sebor

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55B6F232.2080402@gmail.com \
    --to=msebor@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=law@redhat.com \
    --cc=msebor@redhat.com \
    --cc=segher@kernel.crashing.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).