Bug 8743

Summary: receiving result from __builtin_return_address() beyond stack top causes segfault
Product: gcc Reporter: eddy
Component: middle-endAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED WONTFIX    
Severity: minor CC: bangerth, eddy, gcc-bugs, gcc, msebor
Priority: P3 Keywords: documentation
Version: 3.0.4   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2005-12-31 20:25:09

Description eddy 2002-11-28 05:16:01 UTC
The program shown below as `How-To-Repeat' segfaults when built with gcc-3.0.4 or 2.95.4; though (void)ing the function's return instead of storing (or attempting to print) it is OK.  This is despite the info page saying: <quote>

Getting the Return or Frame Address of a Function
=================================================
...
     On some machines it may be impossible to determine the return
     address of any function other than the current one; in such cases,
     or when the top of the stack has been reached, this function will
     return `0'.
...
</quote> which I read as meaning I should be getting the value 0 if I call with LEVEL greater than the actual depth of the stack.  The builtin works fine from deep in a stack all the way up to top-of-stack, but recieving its result from a call asking about frames above that causes a segfault.

Bug initially discovered in the course of trying to use ccmalloc; I wasn't even getting into main(), since libqt.so's loading called malloc, which asked for a backtrace, which segfaulted, before main() was invoked ! (This destroyed the work-around I initially thought of, namely having main() call a function which lets the backtracer record main()'s address as a sentinel at which to stop.)

Note that this bug makes it impossible to use this builtin for backtracing, since one has no way of detecting the depth from which one is calling it.  For use in generation of backtraces, at least the first invalid LEVEL needs to return a sentinel value, without segfaulting.

Release:
gcc-3.0.4

Environment:
Debian GNU/Linux 2.2.19pre17 #1 Tue Mar 13 22:37:59 EST 2001 i686 unknown

How-To-Repeat:
cat >backtrace.c <<EOF
int main(int count, char *args[])
{
	void *tmp = __builtin_return_address(2);
	return 0;
}
EOF
gcc -o backtrace backtrace.c
backtrace
Comment 1 eddy 2002-11-28 14:40:25 UTC
From: Edward Welbourne <eddy@opera.no>
To: gcc-gnats@gcc.gnu.org, nobody@gcc.gnu.org
Cc:  
Subject: Re: c/8743: receiving result from __builtin_return_address() beyond stack top causes segfault
Date: Thu, 28 Nov 2002 14:40:25 +0100

 I have now found a work-around:
 
 #define __builtin_return_address(N) \
 (__builtin_frame_address(N) ? __builtin_return_address_(N) : (void *)0)
 
 	Eddy.
Comment 2 Wolfgang Bangerth 2002-12-04 14:00:45 UTC
State-Changed-From-To: open->analyzed
State-Changed-Why: Despite the given workaround, the function is not doing what
    the documentation says. This is an error.
Comment 3 Wolfgang Bangerth 2002-12-05 08:00:27 UTC
From: Wolfgang Bangerth <bangerth@ticam.utexas.edu>
To: gcc-gnats@gcc.gnu.org
Cc:  
Subject: Re: c/8743: receiving result from __builtin_return_address() beyond
 stack top causes segfault (fwd)
Date: Thu, 5 Dec 2002 08:00:27 -0600 (CST)

 -------------------------------------------------------------------------
 Wolfgang Bangerth              email:           bangerth@ticam.utexas.edu
                                www: http://www.ticam.utexas.edu/~bangerth
 
 
 ---------- Forwarded message ----------
 Date: Thu, 05 Dec 2002 11:04:34 +0100
 From: Edward Welbourne <eddy@opera.no>
 To: bangerth@dealii.org, gcc-gnats@gcc.gnu.org
 Cc: biere@inf.ethz.ch, gcc-bugs@gcc.gnu.org, gcc-prs@gcc.gnu.org,
      nobody@gcc.gnu.org, steven.robbins@videotron.ca
 Subject: Re: c/8743: receiving result from __builtin_return_address()
     beyond stack top causes segfault
 
 Also: note that the work-around only fixes the problem for the *first*
 LEVEL at which it would otherwise seg-fault (which *is* just enough to
 enable backtracing in ccmalloc); it does nothing about the segfault at
 greater depth, which also happens in __builtin_frame_address(); if you
 use __builtin_frame_address(3) in place of __builtin_return_address(2)
 in the example code, you'll get a segfault just the same (on x86).
 
 [All of which rather hints that these functions do a zig-zag chain of
 pointer dereferences, which is missing an `are we zero yet' test.
 I naively imagine this will be easy to fix.]
 
 I've now had the opportunity to test the same on a ppc:
 __builtin_return_address(2) segfaults, as does
 __builtin_frame_address(4), but
 __builtin_frame_address(3) actually succeeds !
 This is with a 2.95.? version and with 3.2.1.
 
 	Eddy.
Comment 4 eddy 2002-12-05 11:04:34 UTC
From: Edward Welbourne <eddy@opera.no>
To: bangerth@dealii.org, gcc-gnats@gcc.gnu.org
Cc: biere@inf.ethz.ch, gcc-bugs@gcc.gnu.org, gcc-prs@gcc.gnu.org,
	nobody@gcc.gnu.org, steven.robbins@videotron.ca
Subject: Re: c/8743: receiving result from __builtin_return_address() beyond stack top causes segfault
Date: Thu, 05 Dec 2002 11:04:34 +0100

 Also: note that the work-around only fixes the problem for the *first*
 LEVEL at which it would otherwise seg-fault (which *is* just enough to
 enable backtracing in ccmalloc); it does nothing about the segfault at
 greater depth, which also happens in __builtin_frame_address(); if you
 use __builtin_frame_address(3) in place of __builtin_return_address(2)
 in the example code, you'll get a segfault just the same (on x86).
 
 [All of which rather hints that these functions do a zig-zag chain of
 pointer dereferences, which is missing an `are we zero yet' test.
 I naively imagine this will be easy to fix.]
 
 I've now had the opportunity to test the same on a ppc:
 __builtin_return_address(2) segfaults, as does
 __builtin_frame_address(4), but
 __builtin_frame_address(3) actually succeeds !
 This is with a 2.95.? version and with 3.2.1.
 
 	Eddy.

Comment 5 Dara Hazeghi 2003-07-18 23:16:07 UTC
Confirmed still present with gcc 3.3 branch and mainline (20030717).
Comment 6 Andrew Pinski 2005-08-20 00:57:01 UTC
This is just a doc problem really.  Also note __builtin_return_address for other than 0 is just for 
debuging puposes.
Comment 7 eddy@opera.com 2005-08-25 11:19:19 UTC
Subject: Re:  receiving result from __builtin_return_address() beyond stack top causes segfault

> This is just a doc problem really.

If it is "just a doc problem" then the doc needs to change to say:

   __builtin_return_address(0) returns the address to which the
   current function will return; __builtin_return_address(1+n) may
   crash but if you're lucky it'll give the address to which the
   function indicated by __builtin_return_address(n) will return.
   This function is only provided for debug purposes.

but I'm deeply skeptical.  The function should either *not* take a
parameter (how far up the stack to look) or *not* crash when that
parameter is supplied or have some predictable way of knowing what
values to not pass as parameter if you don't want to crash.  Since the
pattern of calls that doesn't crash (i.e. my work-around, see earlier
notes on this bug) depends on hardware architecture, this means the
code needs to change, even if the documentation is changed.

	Eddy.
Comment 8 norman graham 2005-09-08 01:43:47 UTC
Ed: 
I also have the same problem, but a little thought gives you a good work-
around.   First a little background.   There is a function that calls main.  
This is the last function on the stack you can query using 
__builtin_return_address.  If you query who calls that function you get a 
seg "fault" , quicker then grass through a goose.   They should have called 
their __builtin_return_address(0) logic from there and stored the address, 
stopping future calls to this function from going further.    This is exactly 
what you can do from main.  (This is your workaround) Call 
_builtin_return_address(0) from main, store the result to a global, and you 
can compare against this address in the future (provided your not in an 
at_exit, or on_exit function call stack).  Of course you've got to turn 
optimization off (-O0), I think or the results could be silly.   Then you can 
query back to the main function (or one up if you wish to the boot-up 
routine.).  Again: Dont be silly, turn off optmization (or function calls will 
colapse), store the result from main, and DONT call from "onexit" or "atexit" 
routines.

good luck.
n.
Comment 9 eddy@opera.com 2005-09-08 07:54:00 UTC
Subject: Re:  receiving result from __builtin_return_address() beyond stack top causes segfault

Yes, that's one of the work-arounds I considered: but has an
inconvenient problem - when shared libraries are loading, _start (the
function that calls main) hasn't yet been entered and main hasn't yet
recorded its address.  This means we have to not record the call-stack
when our global variable recording main's caller's address is as yet
unset.  Indeed, using ccmalloc got me a segfault before main was
entered in exactly this way, since it doesn't (or didn't, back when I
reported this bug - it's about time I had another look at ccmalloc) do
the work-around just described.

	Eddy.
Comment 10 Christian Häggström 2012-06-18 19:34:23 UTC
I guess this bug can be closed now, my gcc 4.7 documentation states:

 -- Built-in Function: void * __builtin_return_address (unsigned int LEVEL)
[...]
     On some machines it may be impossible to determine the return
     address of any function other than the current one; in such cases,
     or when the top of the stack has been reached, this function will
     return `0' or a random value.
[...]
     This function should only be used with a nonzero argument for
     debugging purposes.
Comment 11 Richard Biener 2012-06-19 09:18:12 UTC
Indeed.
Comment 12 Martin Sebor 2015-06-29 15:23:10 UTC
A GCC patch to issue a warning for potentially unsafe calls to __builtin_return_address() and __builtin_frame_address() posted here:

https://gcc.gnu.org/ml/gcc-patches/2015-06/msg00886.html