Bug 13182 - -fstack-check probes too distant when allocating on stack
Summary: -fstack-check probes too distant when allocating on stack
Status: RESOLVED WORKSFORME
Alias: None
Product: gcc
Classification: Unclassified
Component: middle-end (show other bugs)
Version: 3.3.1
: P3 enhancement
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2003-11-25 00:21 UTC by Robert R Schneck
Modified: 2019-06-15 01:04 UTC (History)
3 users (show)

See Also:
Host: i686-pc-cygwin
Target: i686-pc-cygwin
Build: i686-pc-cygwin
Known to work:
Known to fail:
Last reconfirmed: 2003-11-27 17:23:45


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Robert R Schneck 2003-11-25 00:21:36 UTC
The stack probes generated by -fstack-check appear to be too distant
when something gets allocated on the stack.

Running "gcc -fstack-check -S tmp.c" where tmp.c is
<code>
f () {
  int a;
  int foo[2100];
}
int g() {
  int a;
  int foo[2100];
  f ();
}
</code>
produces the following output in tmp.s:
<code>
        .file   "tmp.c"
        .text
.globl _f
        .def    _f;     .scl    2;      .type   32;     .endef
_f:
        pushl   %ebp
        movl    %esp, %ebp
        subl    $24, %esp
        movl    %esp, -12(%ebp)
        leal    -12792(%esp), %edx
        movl    $0, (%edx)
        movl    $8400, -8(%ebp)
        movl    -8(%ebp), %eax
        call    __alloca
        movl    -12(%ebp), %esp
        leave
        ret
.globl _g
        .def    _g;     .scl    2;      .type   32;     .endef
_g:
        pushl   %ebp
        movl    %esp, %ebp
        pushl   %ebx
        subl    $20, %esp
        leal    -4392(%esp), %eax
        movl    $0, (%eax)
        movl    %esp, %ebx
        leal    -12792(%esp), %eax
        movl    $0, (%eax)
        movl    $8400, -12(%ebp)
        movl    -12(%ebp), %eax
        call    __alloca
        call    _f
        movl    %ebx, %esp
        movl    -4(%ebp), %ebx
        leave
        ret
</code>

In f the first probe is at -12792, skipping over three whole pages!
In g, a non-leaf function, at least we first probe -4392, but there
are still two pages skipped between the two probes.

I think the culprit in the code (gcc-3.3.1-3 on cygwin)
is in the probe_stack_range function in explow.c:
<code>
      /* Start probing at FIRST + N * STACK_CHECK_PROBE_INTERVAL
         for values of N from 1 until it exceeds LAST.  If only one
         probe is needed, this will not generate any code.  Then probe
         at LAST.  */
      for (offset = first + STACK_CHECK_PROBE_INTERVAL;
           offset < INTVAL (size);
           offset = offset + STACK_CHECK_PROBE_INTERVAL)
        emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
                                          stack_pointer_rtx,
                                          GEN_INT (offset)));

      emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
                                        stack_pointer_rtx,
                                        plus_constant (size, first)));
</code>
It looks like there is a confusion about what 
probe_stack_range(first,size) means... is it probe from 
sp down to sp-size assuming that sp to sp-first is already probed?
Or is it to probe down to sp-(first+size)?

Additionally, it looks like it's being assumed that 4392 has already 
been probed, even in leaf functions where that has not been done.

Finally, can anyone tell me what the invariant guaranteed by 
-fstack-check is?  I think that it is "At entry to any function,
sp-4392 is guaranteed to be above the guard page."  (Then the probe in 
non-leaf functions is to preserve the guarantee in any functions that 
are called.)  Is that correct?

Robert
Comment 1 Andrew Pinski 2003-11-25 00:43:49 UTC
This is documented in the GCC internals manual how stack-checking works: <http://gcc.gnu.org/
onlinedocs/gccint/Stack-Checking.html>.  Also -fstack-check is only usefully for threaded 
applications.
Comment 2 Robert R Schneck 2003-11-25 13:02:44 UTC
(In reply to comment #1)

I fear you may have missed my point.

Stack probes are supposed to happen at STACK_CHECK_PROBE_INTERVAL,
i.e. 4096.

One function does one probe, at sp - 12792 (which is > 4096*3).
One function does two probes, one at sp - 4392,
the other at sp - 12792 (a difference of > 4096*2).

Even if the thread has TWO guard pages this could fail
to be safe!

Please forgive me if I misunderstand.  I had looked at the
internals manual, and I understand (I think) why it is
correct for the first check to be at sp - 4392.
But I am rather convinced that the interval had better
be 4096 (or less) thereafter.

Robert
Comment 3 Andrew Pinski 2003-11-27 17:23:45 UTC
Confirmed.
Comment 4 Andrew Pinski 2003-12-19 01:27:16 UTC
This is related to bug 10127.
Comment 5 Lothar Werzinger 2003-12-21 00:59:17 UTC
We also experience strange intermittent crashes (sometimes the program crashes, most times  
it doesn't) when using -fstack-check with GCC 3.3.2 on Linux. If the crash occurs it always  
shows a corrupt stack. It shows a function argument that is different from what the program  
had when it executed that function (we printed the argument). What puzzeled us, was that this  
kind of crash also occured with only one thread (the main thread).  
  
Comment 6 Eric Botcazou 2017-05-30 09:52:31 UTC
That's as expected: the probing mechanism maintains a protection area so the program can recover from a stack overflow condition by raising an exception.
That's why it always probes a few pages ahead but, once the first few pages are skipped at the entry point, every subsequent page is probed.
Comment 7 Florian Weimer 2017-05-30 09:59:53 UTC
(In reply to Eric Botcazou from comment #6)
> That's as expected: the probing mechanism maintains a protection area so the
> program can recover from a stack overflow condition by raising an exception.
> That's why it always probes a few pages ahead but, once the first few pages
> are skipped at the entry point, every subsequent page is probed.

I'm not sure if the the probing offset is large enough for this purpose because the kernel keeps pushing more and more data onto the stack during signal handling:

  https://sourceware.org/bugzilla/show_bug.cgi?id=20305
Comment 8 Eric Botcazou 2017-05-30 10:03:23 UTC
> I'm not sure if the the probing offset is large enough for this purpose
> because the kernel keeps pushing more and more data onto the stack during
> signal handling:
> 
>   https://sourceware.org/bugzilla/show_bug.cgi?id=20305

Right, the Ada runtime uses an alternate signal stack for specific platforms.
Comment 9 Eric Botcazou 2017-05-30 10:08:04 UTC
> Right, the Ada runtime uses an alternate signal stack for specific platforms.

To be clear: x86/Linux and x86-64/Linux (and for them there is no protection area during the probing).
Comment 10 Eric Botcazou 2017-05-30 10:18:09 UTC
> To be clear: x86/Linux and x86-64/Linux (and for them there is no protection
> area during the probing).

I misremembered: there is exactly one page of protection area for them because of the way the unwinding mechanism (run on the alternate stack) restores the regular execution of the program.