Bug 6522 - abort should not be marked noreturn
Summary: abort should not be marked noreturn
Status: RESOLVED WONTFIX
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: unspecified
: P2 normal
Target Milestone: ---
Assignee: Ulrich Drepper
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-05-15 09:13 UTC by David Kastrup
Modified: 2014-07-03 11:32 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description David Kastrup 2008-05-15 09:13:07 UTC
the principal raison d'etre of abort is to die with a core dump
(typically on failed assertions).  I am not the only person who spent
days of useless post-mortem debugging (or debugging with a breakpoint on
abort) because of gcc's optimization of -fcross-jumping, which means
that gcc recycles a single abort call (with inconsistent stack state)
all across a function.

That means that the core dump has _both_ incoherent and unexpected stack
state, as well as pointing to a completely wrong position in the source
file.

The principal purpose of the noreturn attribute is to allow for
inconsistent stack state and call recycling.  So its effects, if any,
are directly in conflict with the purpose of abort, an unorderly exit
with the main purpose to facilitate debugging.

While technically abort _does_ not return, telling the compiler so is
giving it leave to eradicate its call history.  And that is not useful
at all when debugging.  Since the presence of -g should not alter the
code, abort should not be marked noreturn.
Comment 1 David Kastrup 2008-05-28 12:56:13 UTC
To add some more substance: I know of at least 5 different Emacs developers who
have independently wasted in the order of days making sense of failed assertions
because of the useless state of the stack frame for post mortem debugging.

The file DEBUG in the Emacs distribution contains the advice to compile with
-fno-crossjumping which helps somewhat (but most people only read this after
having wasted a lot of time).

So this problem is not academical.  It would be nice to at least get some sort
of minimal feedback.
Comment 2 Pierre Habouzit 2008-06-12 15:20:27 UTC
This is wrong and will break any function that has a non void return type and
that specify that code is unreachable using abort(), without "returning"
anything after abort().

This is perfectly valid code, there is quite a lot of it out there, and such a
change would gratuitously break it.
Comment 3 Ulrich Drepper 2008-06-13 06:20:19 UTC
Changing glibc to make debugging easier at the cost of speed or cost size won't
happen.  *Especially* since there are work arounds.  Just add the gcc flag.
Comment 4 David Kastrup 2008-06-13 08:45:07 UTC
(In reply to comment #2)
> This is wrong and will break any function that has a non void return type and
> that specify that code is unreachable using abort(), without "returning"
> anything after abort().

How will it "break" anything?  Unreachable code is not forbidden by any C
standard as far as I know.

> This is perfectly valid code, there is quite a lot of it out there, and such a
> change would gratuitously break it.

Perfectly valid according to which C standard?  Can you give an example for code
which would rely on the noreturn optimization and would fail without it?

(In reply to comment #3)
> Changing glibc to make debugging easier at the cost of speed or cost size won't
> happen.  *Especially* since there are work arounds.  Just add the gcc flag.

Let me put this more bluntly: the current behavior breaks abort's principal
functionality.

abort raises SIGABRT.  The default action for SIGABRT is

       Signal     Value     Action   Comment
       ----------------------------------------------------------------------
       SIGABRT       6       Core    Abort signal from abort(3)

So the default action is a core dump, and the core dump is junk when gcc
performs noreturn optimizations.  If people don't want a core dump, they will
use exit(255) instead of abort.

We are not talking about "making debugging easier".  We are talking about abort
being able to function as intended at all.

If you don't consider it appropriate to remove the noreturn attribute (which is
an expedience), you might consider implementing an attribute "uniquecall" or
"debug" or so which will basically enable "-fno-crossjumping" just for calls of
abort.  In that manner, the core dump at least points to a unique call point for
abort, and it becomes theoretically possible for the compiler/debugger combo to
untangle any noreturn optimizations that have been done at that particular call
point.

If the abort call can be jumped to from several different locations (possibly
even different functions), untangling the stack frame becomes no longer possible
and the core dump, the principal output of abort, is useless.
Comment 5 Ulrich Drepper 2008-06-13 14:27:40 UTC
Stop reopening.  You have your remedy, you're just too lazy to do any work
yourself and so would rather see everyone suffer.  And

>  Let me put this more bluntly: the current behaviour breaks abort's principal
>  functionality.

is of course total nonsense.  The main functionality is to abort the process and
that is done.
Comment 6 Mark S. Brown 2008-06-16 19:38:34 UTC
The ISO C std 9899:1999, Sec 7.20.4.1 makes it clear:
The specification of abort() is
    void abort(void);
and under "Returns" is the single sentence:
    The abort function does not return to its caller.

IEEE POSIX 1003.1-2001 reiterates the above. I hope this answers the questions
concerning the specification, and why we intend to remain in conformance.
Comment 7 David Kastrup 2008-06-17 09:19:34 UTC
(In reply to comment #6)
> The ISO C std 9899:1999, Sec 7.20.4.1 makes it clear:
> The specification of abort() is
>     void abort(void);
> and under "Returns" is the single sentence:
>     The abort function does not return to its caller.
> 
> IEEE POSIX 1003.1-2001 reiterates the above. I hope this answers the questions
> concerning the specification, and why we intend to remain in conformance.

Huh?  Nobody suggested letting abort return to its caller.  My proposal has
nothing whatsoever to do with complying or not complying to the above spec.  The
SPEC does _not_ state "The optimizer should ensure that abort is entered with a
stack state not containing useful information for the ensuing core dump".

Yes, certainly abort should not return.  But making use of this information in
the current manner means that abort is called without an identifiable call
context and associated identifiable register/stackframe/value state.  And for a
function with the distinguishing feature of creating a core dump, that's a
rather hefty drawback.  The resulting core dump is quite often useless, and not
useless in the usual "things may get executed and assigned in strange orders"
sense, but rather in the "utter garbage masquerading as something sensible and
wasting you hours of head-scratching" sense.
Comment 8 Andreas Schwab 2008-06-17 11:41:18 UTC
Removing noreturn from abort will not eliminate the problem, the compiler will 
still combine two calls if they appear in similar enough contexts.  In the 
following example the compiler will still generate only a single call to abort, 
no matter how it is declared.

#include <stdlib.h>

int bar (int);
#ifdef USE_ABORT1
void abort1 (void);
#define abort abort1
#endif

int
foo (int a)
{
  int b;

  if (a == 1)
    {
      b = bar (a);
      if (!b) abort ();
    }
  else if (a == 2)
    {
      b = bar (a + 1);
      if (!b) abort ();
    }
  else
    b = a;
  return b;
}
Comment 9 David Kastrup 2008-06-17 11:54:53 UTC
(In reply to comment #8)
> Removing noreturn from abort will not eliminate the problem, the compiler will 
> still combine two calls if they appear in similar enough contexts.

Quite correct.  However, this will occur at a junction of the code paths with
compatible and recognizable stack frame.  So the inconvenience is more or less
"par for optimization".  You will still be able to examine variable values (even
if they move through registers) and figure out what function you are in.

The optimal solution would, as I stated at the bottom of comment #4, introduce
some attribute that could effectively enable -fno-crossjumping for abort calls
only.  In that manner, the "noreturn" optimizations would have a chance to be
tracked by debugging information since the return address would uniquely
identify the context of the stack frame.

This would require work in the compiler and might be the most elegant solution
in the long run.  Leaving off "noreturn" in the meantime would provide an
expedience that gets rid of the most productivity-wasting artifacts.

If nothing is done at all, at least the GCC documentation would warrant a strong
warning about the particular effects of the (standard for -O) -fcrossjumping
option on post mortem debugging.
Comment 10 joseph@codesourcery.com 2008-06-17 13:37:26 UTC
Subject: Re:  abort should not be marked noreturn

On Tue, 17 Jun 2008, dak at gnu dot org wrote:

> The optimal solution would, as I stated at the bottom of comment #4, introduce
> some attribute that could effectively enable -fno-crossjumping for abort calls
> only.  In that manner, the "noreturn" optimizations would have a chance to be
> tracked by debugging information since the return address would uniquely
> identify the context of the stack frame.
> 
> This would require work in the compiler and might be the most elegant solution
> in the long run.  Leaving off "noreturn" in the meantime would provide an
> expedience that gets rid of the most productivity-wasting artifacts.

The compiler provides a noreturn attribute for abort automatically.  
Whether the header provides it doesn't matter unless you use 
-fno-builtin-abort.

Comment 11 David Kastrup 2008-06-17 13:44:15 UTC
(In reply to comment #10)

> The compiler provides a noreturn attribute for abort automatically.  
> Whether the header provides it doesn't matter unless you use 
> -fno-builtin-abort.

That would suggest that this report should better have been filed with GCC than
with glibc since it would seem that a header change will usually not make a
dfference.

Thanks for that information, appreciated.  Now I can move elsewhere in order to
let my head bashed in.