re PR target/10127 (-fstack-check let's program crash)

PR target/10127
	PR ada/20548
	* expr.h (STACK_CHECK_PROBE_INTERVAL): Delete.
	(STACK_CHECK_PROBE_INTERVAL_EXP): New macro.
	(STACK_CHECK_MOVING_SP): Likewise.
	* system.h (STACK_CHECK_PROBE_INTERVAL): Poison it.
	* doc/tm.texi (Stack Checking): Delete STACK_CHECK_PROBE_INTERVAL.
	Document STACK_CHECK_PROBE_INTERVAL_EXP and STACK_CHECK_MOVING_SP.
	* doc/md.texi (Standard Pattern Names): Tweak entry of CHECK_STACK.
	Document PROBE_STACK.
	* explow.c (anti_adjust_stack_and_probe): New function.
	(allocate_dynamic_stack_space): Do not directly allocate space if
	STACK_CHECK_MOVING_SP, instead invoke above function.
	(emit_stack_probe): Handle probe_stack insn.
	(PROBE_INTERVAL): New macro.
	(STACK_GROW_OPTAB): Likewise.
	(STACK_GROW_OFF): Likewise.
	(probe_stack_range): Use Pmode and memory_address consistently.  Fix
	loop condition in the small constant case.  Rewrite in the general
	case to be immune to wraparounds.  Make sure the address of probes
	is valid.  Try to use [base + disp] addressing mode if possible.
	* ira.c (setup_eliminable_regset): Set frame_pointer_needed if stack
	checking is enabled and STACK_CHECK_MOVING_SP.
	* rtlanal.c (may_trap_p_1) <MEM>: If stack checking is enabled,
	return 1 for volatile references to the stack pointer.
	* tree.c (build_common_builtin_nodes): Do not set ECF_NOTHROW on
	__builtin_alloca if stack checking is enabled.
	* unwind-dw2.c (uw_identify_context): Take into account whether the
	context is that of a signal frame or not.
	* config/i386/linux.h (STACK_CHECK_MOVING_SP): Define to 1.
	* config/i386/linux64.h (STACK_CHECK_MOVING_SP): Likewise.

From-SVN: r153877
This commit is contained in:
Eric Botcazou 2009-11-03 22:49:37 +00:00 committed by Eric Botcazou
parent 24d179b4c7
commit d809253a56
15 changed files with 440 additions and 101 deletions

View file

@ -1,3 +1,37 @@
2009-11-03 Eric Botcazou <ebotcazou@adacore.com>
PR target/10127
PR ada/20548
* expr.h (STACK_CHECK_PROBE_INTERVAL): Delete.
(STACK_CHECK_PROBE_INTERVAL_EXP): New macro.
(STACK_CHECK_MOVING_SP): Likewise.
* system.h (STACK_CHECK_PROBE_INTERVAL): Poison it.
* doc/tm.texi (Stack Checking): Delete STACK_CHECK_PROBE_INTERVAL.
Document STACK_CHECK_PROBE_INTERVAL_EXP and STACK_CHECK_MOVING_SP.
* doc/md.texi (Standard Pattern Names): Tweak entry of CHECK_STACK.
Document PROBE_STACK.
* explow.c (anti_adjust_stack_and_probe): New function.
(allocate_dynamic_stack_space): Do not directly allocate space if
STACK_CHECK_MOVING_SP, instead invoke above function.
(emit_stack_probe): Handle probe_stack insn.
(PROBE_INTERVAL): New macro.
(STACK_GROW_OPTAB): Likewise.
(STACK_GROW_OFF): Likewise.
(probe_stack_range): Use Pmode and memory_address consistently. Fix
loop condition in the small constant case. Rewrite in the general
case to be immune to wraparounds. Make sure the address of probes
is valid. Try to use [base + disp] addressing mode if possible.
* ira.c (setup_eliminable_regset): Set frame_pointer_needed if stack
checking is enabled and STACK_CHECK_MOVING_SP.
* rtlanal.c (may_trap_p_1) <MEM>: If stack checking is enabled,
return 1 for volatile references to the stack pointer.
* tree.c (build_common_builtin_nodes): Do not set ECF_NOTHROW on
__builtin_alloca if stack checking is enabled.
* unwind-dw2.c (uw_identify_context): Take into account whether the
context is that of a signal frame or not.
* config/i386/linux.h (STACK_CHECK_MOVING_SP): Define to 1.
* config/i386/linux64.h (STACK_CHECK_MOVING_SP): Likewise.
2009-11-03 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/41917

View file

@ -207,6 +207,9 @@ along with GCC; see the file COPYING3. If not see
#define MD_UNWIND_SUPPORT "config/i386/linux-unwind.h"
/* The stack pointer needs to be moved while checking the stack. */
#define STACK_CHECK_MOVING_SP 1
/* This macro may be overridden in i386/k*bsd-gnu.h. */
#define REG_NAME(reg) reg

View file

@ -110,6 +110,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define MD_UNWIND_SUPPORT "config/i386/linux-unwind.h"
/* The stack pointer needs to be moved while checking the stack. */
#define STACK_CHECK_MOVING_SP 1
/* This macro may be overridden in i386/k*bsd-gnu.h. */
#define REG_NAME(reg) reg

View file

@ -5037,11 +5037,19 @@ operations in addition to updating the stack pointer.
@item @samp{check_stack}
If stack checking cannot be done on your system by probing the stack with
a load or store instruction (@pxref{Stack Checking}), define this pattern
to perform the needed check and signaling an error if the stack
has overflowed. The single operand is the location in the stack furthest
from the current stack pointer that you need to validate. Normally,
on machines where this pattern is needed, you would obtain the stack
limit from a global or thread-specific variable or register.
to perform the needed check and signal an error if the stack has overflowed.
The single operand is the address in the stack furthest from the current
stack pointer that you need to validate. Normally, on machines where this
pattern is needed, you would obtain the stack limit from a global or
thread-specific variable or register.
@cindex @code{probe_stack} instruction pattern
@item @samp{probe_stack}
If stack checking can be done on your system by probing the stack but doing
it with a load or store instruction is not optimal (@pxref{Stack Checking}),
define this pattern to do the probing differently and signal an error if
the stack has overflowed. The single operand is the memory location in the
stack that needs to be probed.
@cindex @code{nonlocal_goto} instruction pattern
@item @samp{nonlocal_goto}

View file

@ -3556,11 +3556,12 @@ like to do static stack checking in some more efficient way than the generic
approach. The default value of this macro is zero.
@end defmac
@defmac STACK_CHECK_PROBE_INTERVAL
An integer representing the interval at which GCC must generate stack
probe instructions. You will normally define this macro to be no larger
than the size of the ``guard pages'' at the end of a stack area. The
default value of 4096 is suitable for most systems.
@defmac STACK_CHECK_PROBE_INTERVAL_EXP
An integer specifying the interval at which GCC must generate stack probe
instructions, defined as 2 raised to this integer. You will normally
define this macro so that the interval be no larger than the size of
the ``guard pages'' at the end of a stack area. The default value
of 12 (4096-byte interval) is suitable for most systems.
@end defmac
@defmac STACK_CHECK_PROBE_LOAD
@ -3569,6 +3570,15 @@ as a load instruction and zero if GCC should use a store instruction.
The default is zero, which is the most efficient choice on most systems.
@end defmac
@defmac STACK_CHECK_MOVING_SP
An integer which is nonzero if GCC should move the stack pointer page by page
when doing probes. This can be necessary on systems where the stack pointer
contains the bottom address of the memory area accessible to the executing
thread at any point in time. In this situation an alternate signal stack
is required in order to be able to recover from a stack overflow. The
default value of this macro is zero.
@end defmac
@defmac STACK_CHECK_PROTECT
The number of bytes of stack needed to recover from a stack overflow,
for languages where such a recovery is supported. The default value of

View file

@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
static rtx break_out_memory_refs (rtx);
static void emit_stack_probe (rtx);
static void anti_adjust_stack_and_probe (rtx);
/* Truncate and perhaps sign-extend C as appropriate for MODE. */
@ -1233,9 +1234,11 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align)
gcc_assert (!(stack_pointer_delta
% (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)));
/* If needed, check that we have the required amount of stack.
Take into account what has already been checked. */
if (flag_stack_check == GENERIC_STACK_CHECK)
/* If needed, check that we have the required amount of stack. Take into
account what has already been checked. */
if (STACK_CHECK_MOVING_SP)
;
else if (flag_stack_check == GENERIC_STACK_CHECK)
probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE,
size);
else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
@ -1304,7 +1307,10 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align)
emit_label (space_available);
}
anti_adjust_stack (size);
if (flag_stack_check && STACK_CHECK_MOVING_SP)
anti_adjust_stack_and_probe (size);
else
anti_adjust_stack (size);
#ifdef STACK_GROWS_DOWNWARD
emit_move_insn (target, virtual_stack_dynamic_rtx);
@ -1355,6 +1361,12 @@ emit_stack_probe (rtx address)
MEM_VOLATILE_P (memref) = 1;
/* See if we have an insn to probe the stack. */
#ifdef HAVE_probe_stack
if (HAVE_probe_stack)
emit_insn (gen_probe_stack (memref));
else
#endif
if (STACK_CHECK_PROBE_LOAD)
emit_move_insn (gen_reg_rtx (word_mode), memref);
else
@ -1362,15 +1374,20 @@ emit_stack_probe (rtx address)
}
/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.
FIRST is a constant and size is a Pmode RTX. These are offsets from the
current stack pointer. STACK_GROWS_DOWNWARD says whether to add or
subtract from the stack. If SIZE is constant, this is done
with a fixed number of probes. Otherwise, we must make a loop. */
FIRST is a constant and size is a Pmode RTX. These are offsets from
the current stack pointer. STACK_GROWS_DOWNWARD says whether to add
or subtract them from the stack pointer. */
#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
#ifdef STACK_GROWS_DOWNWARD
#define STACK_GROW_OP MINUS
#define STACK_GROW_OPTAB sub_optab
#define STACK_GROW_OFF(off) -(off)
#else
#define STACK_GROW_OP PLUS
#define STACK_GROW_OPTAB add_optab
#define STACK_GROW_OFF(off) (off)
#endif
void
@ -1380,113 +1397,272 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
size = convert_to_mode (Pmode, size, 1);
/* Next see if the front end has set up a function for us to call to
check the stack. */
if (stack_check_libfunc != 0)
/* Next see if we have a function to check the stack. */
if (stack_check_libfunc)
{
rtx addr = memory_address (QImode,
rtx addr = memory_address (Pmode,
gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
plus_constant (size, first)));
addr = convert_memory_address (ptr_mode, addr);
emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr,
ptr_mode);
emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr);
}
/* Next see if we have an insn to check the stack. Use it if so. */
/* Next see if we have an insn to check the stack. */
#ifdef HAVE_check_stack
else if (HAVE_check_stack)
{
insn_operand_predicate_fn pred;
rtx last_addr
= force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
plus_constant (size, first)),
NULL_RTX);
rtx addr = memory_address (Pmode,
gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
plus_constant (size, first)));
insn_operand_predicate_fn pred
= insn_data[(int) CODE_FOR_check_stack].operand[0].predicate;
if (pred && !((*pred) (addr, Pmode)))
addr = copy_to_mode_reg (Pmode, addr);
pred = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate;
if (pred && ! ((*pred) (last_addr, Pmode)))
last_addr = copy_to_mode_reg (Pmode, last_addr);
emit_insn (gen_check_stack (last_addr));
emit_insn (gen_check_stack (addr));
}
#endif
/* If we have to generate explicit probes, see if we have a constant
small number of them to generate. If so, that's the easy case. */
else if (CONST_INT_P (size)
&& INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL)
/* Otherwise we have to generate explicit probes. If we have a constant
small number of them to generate, that's the easy case. */
else if (CONST_INT_P (size) && INTVAL (size) < 7 * PROBE_INTERVAL)
{
HOST_WIDE_INT offset;
HOST_WIDE_INT isize = INTVAL (size), i;
rtx addr;
/* 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)));
/* Probe at FIRST + N * PROBE_INTERVAL for values of N from 1 until
it exceeds SIZE. If only one probe is needed, this will not
generate any code. Then probe at FIRST + SIZE. */
for (i = PROBE_INTERVAL; i < isize; i += PROBE_INTERVAL)
{
addr = memory_address (Pmode,
plus_constant (stack_pointer_rtx,
STACK_GROW_OFF (first + i)));
emit_stack_probe (addr);
}
emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
plus_constant (size, first)));
addr = memory_address (Pmode,
plus_constant (stack_pointer_rtx,
STACK_GROW_OFF (first + isize)));
emit_stack_probe (addr);
}
/* In the variable case, do the same as above, but in a loop. We emit loop
notes so that loop optimization can be done. */
/* In the variable case, do the same as above, but in a loop. Note that we
must be extra careful with variables wrapping around because we might be
at the very top (or the very bottom) of the address space and we have to
be able to handle this case properly; in particular, we use an equality
test for the loop condition. */
else
{
rtx test_addr
= force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
GEN_INT (first + STACK_CHECK_PROBE_INTERVAL)),
NULL_RTX);
rtx last_addr
= force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
plus_constant (size, first)),
NULL_RTX);
rtx incr = GEN_INT (STACK_CHECK_PROBE_INTERVAL);
rtx rounded_size, rounded_size_op, test_addr, last_addr, temp;
rtx loop_lab = gen_label_rtx ();
rtx test_lab = gen_label_rtx ();
rtx end_lab = gen_label_rtx ();
rtx temp;
if (!REG_P (test_addr)
|| REGNO (test_addr) < FIRST_PSEUDO_REGISTER)
test_addr = force_reg (Pmode, test_addr);
emit_jump (test_lab);
/* Step 1: round SIZE to the previous multiple of the interval. */
/* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */
rounded_size
= simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL));
rounded_size_op = force_operand (rounded_size, NULL_RTX);
/* Step 2: compute initial and final value of the loop counter. */
/* TEST_ADDR = SP + FIRST. */
test_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
GEN_INT (first)), NULL_RTX);
/* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */
last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
test_addr,
rounded_size_op), NULL_RTX);
/* Step 3: the loop
while (TEST_ADDR != LAST_ADDR)
{
TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
probe at TEST_ADDR
}
probes at FIRST + N * PROBE_INTERVAL for values of N from 1
until it is equal to ROUNDED_SIZE. */
emit_label (loop_lab);
emit_stack_probe (test_addr);
#ifdef STACK_GROWS_DOWNWARD
#define CMP_OPCODE GTU
temp = expand_binop (Pmode, sub_optab, test_addr, incr, test_addr,
/* Jump to END_LAB if TEST_ADDR == LAST_ADDR. */
emit_cmp_and_jump_insns (test_addr, last_addr, EQ, NULL_RTX, Pmode, 1,
end_lab);
/* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
temp = expand_binop (Pmode, STACK_GROW_OPTAB, test_addr,
GEN_INT (PROBE_INTERVAL), test_addr,
1, OPTAB_WIDEN);
#else
#define CMP_OPCODE LTU
temp = expand_binop (Pmode, add_optab, test_addr, incr, test_addr,
1, OPTAB_WIDEN);
#endif
gcc_assert (temp == test_addr);
emit_label (test_lab);
emit_cmp_and_jump_insns (test_addr, last_addr, CMP_OPCODE,
NULL_RTX, Pmode, 1, loop_lab);
emit_jump (end_lab);
/* Probe at TEST_ADDR. */
emit_stack_probe (test_addr);
emit_jump (loop_lab);
emit_label (end_lab);
emit_stack_probe (last_addr);
/* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
that SIZE is equal to ROUNDED_SIZE. */
/* TEMP = SIZE - ROUNDED_SIZE. */
temp = simplify_gen_binary (MINUS, Pmode, size, rounded_size);
if (temp != const0_rtx)
{
rtx addr;
if (GET_CODE (temp) == CONST_INT)
{
/* Use [base + disp} addressing mode if supported. */
HOST_WIDE_INT offset = INTVAL (temp);
addr = memory_address (Pmode,
plus_constant (last_addr,
STACK_GROW_OFF (offset)));
}
else
{
/* Manual CSE if the difference is not known at compile-time. */
temp = gen_rtx_MINUS (Pmode, size, rounded_size_op);
addr = memory_address (Pmode,
gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
last_addr, temp));
}
emit_stack_probe (addr);
}
}
}
/* Adjust the stack by SIZE bytes while probing it. Note that we skip the
probe for the first interval + a small dope of 4 words and instead probe
that many bytes past the specified size to maintain a protection area. */
static void
anti_adjust_stack_and_probe (rtx size)
{
const int dope = 4 * UNITS_PER_WORD;
/* First ensure SIZE is Pmode. */
if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
size = convert_to_mode (Pmode, size, 1);
/* If we have a constant small number of probes to generate, that's the
easy case. */
if (GET_CODE (size) == CONST_INT && INTVAL (size) < 7 * PROBE_INTERVAL)
{
HOST_WIDE_INT isize = INTVAL (size), i;
bool first_probe = true;
/* Adjust SP and probe to PROBE_INTERVAL + N * PROBE_INTERVAL for
values of N from 1 until it exceeds SIZE. If only one probe is
needed, this will not generate any code. Then adjust and probe
to PROBE_INTERVAL + SIZE. */
for (i = PROBE_INTERVAL; i < isize; i += PROBE_INTERVAL)
{
if (first_probe)
{
anti_adjust_stack (GEN_INT (2 * PROBE_INTERVAL + dope));
first_probe = false;
}
else
anti_adjust_stack (GEN_INT (PROBE_INTERVAL));
emit_stack_probe (stack_pointer_rtx);
}
if (first_probe)
anti_adjust_stack (plus_constant (size, PROBE_INTERVAL + dope));
else
anti_adjust_stack (plus_constant (size, PROBE_INTERVAL - i));
emit_stack_probe (stack_pointer_rtx);
}
/* In the variable case, do the same as above, but in a loop. Note that we
must be extra careful with variables wrapping around because we might be
at the very top (or the very bottom) of the address space and we have to
be able to handle this case properly; in particular, we use an equality
test for the loop condition. */
else
{
rtx rounded_size, rounded_size_op, last_addr, temp;
rtx loop_lab = gen_label_rtx ();
rtx end_lab = gen_label_rtx ();
/* Step 1: round SIZE to the previous multiple of the interval. */
/* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */
rounded_size
= simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL));
rounded_size_op = force_operand (rounded_size, NULL_RTX);
/* Step 2: compute initial and final value of the loop counter. */
/* SP = SP_0 + PROBE_INTERVAL. */
anti_adjust_stack (GEN_INT (PROBE_INTERVAL + dope));
/* LAST_ADDR = SP_0 + PROBE_INTERVAL + ROUNDED_SIZE. */
last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
stack_pointer_rtx,
rounded_size_op), NULL_RTX);
/* Step 3: the loop
while (SP != LAST_ADDR)
{
SP = SP + PROBE_INTERVAL
probe at SP
}
adjusts SP and probes to PROBE_INTERVAL + N * PROBE_INTERVAL for
values of N from 1 until it is equal to ROUNDED_SIZE. */
emit_label (loop_lab);
/* Jump to END_LAB if SP == LAST_ADDR. */
emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX,
Pmode, 1, end_lab);
/* SP = SP + PROBE_INTERVAL and probe at SP. */
anti_adjust_stack (GEN_INT (PROBE_INTERVAL));
emit_stack_probe (stack_pointer_rtx);
emit_jump (loop_lab);
emit_label (end_lab);
/* Step 4: adjust SP and probe to PROBE_INTERVAL + SIZE if we cannot
assert at compile-time that SIZE is equal to ROUNDED_SIZE. */
/* TEMP = SIZE - ROUNDED_SIZE. */
temp = simplify_gen_binary (MINUS, Pmode, size, rounded_size);
if (temp != const0_rtx)
{
/* Manual CSE if the difference is not known at compile-time. */
if (GET_CODE (temp) != CONST_INT)
temp = gen_rtx_MINUS (Pmode, size, rounded_size_op);
anti_adjust_stack (temp);
emit_stack_probe (stack_pointer_rtx);
}
}
/* Adjust back to account for the additional first interval. */
adjust_stack (GEN_INT (PROBE_INTERVAL + dope));
}
/* Return an rtx representing the register or memory location
in which a scalar value of data type VALTYPE
was returned by a function call to function FUNC.

View file

@ -218,9 +218,9 @@ do { \
#define STACK_CHECK_STATIC_BUILTIN 0
#endif
/* The default interval is one page. */
#ifndef STACK_CHECK_PROBE_INTERVAL
#define STACK_CHECK_PROBE_INTERVAL 4096
/* The default interval is one page (4096 bytes). */
#ifndef STACK_CHECK_PROBE_INTERVAL_EXP
#define STACK_CHECK_PROBE_INTERVAL_EXP 12
#endif
/* The default is to do a store into the stack. */
@ -228,6 +228,11 @@ do { \
#define STACK_CHECK_PROBE_LOAD 0
#endif
/* The default is not to move the stack pointer. */
#ifndef STACK_CHECK_MOVING_SP
#define STACK_CHECK_MOVING_SP 0
#endif
/* This is a kludge to try to capture the discrepancy between the old
mechanism (generic stack checking) and the new mechanism (static
builtin stack checking). STACK_CHECK_PROTECT needs to be bumped
@ -252,7 +257,7 @@ do { \
one probe per function. */
#ifndef STACK_CHECK_MAX_FRAME_SIZE
#define STACK_CHECK_MAX_FRAME_SIZE \
(STACK_CHECK_PROBE_INTERVAL - UNITS_PER_WORD)
((1 << STACK_CHECK_PROBE_INTERVAL_EXP) - UNITS_PER_WORD)
#endif
/* This is arbitrary, but should be large enough everywhere. */
@ -779,10 +784,9 @@ extern void update_nonlocal_goto_save_area (void);
extern rtx allocate_dynamic_stack_space (rtx, rtx, int);
/* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive.
FIRST is a constant and size is a Pmode RTX. These are offsets from the
current stack pointer. STACK_GROWS_DOWNWARD says whether to add or
subtract from the stack. If SIZE is constant, this is done
with a fixed number of probes. Otherwise, we must make a loop. */
FIRST is a constant and size is a Pmode RTX. These are offsets from
the current stack pointer. STACK_GROWS_DOWNWARD says whether to add
or subtract them from the stack pointer. */
extern void probe_stack_range (HOST_WIDE_INT, rtx);
/* Return an rtx that refers to the value returned by a library call

View file

@ -1442,6 +1442,9 @@ ira_setup_eliminable_regset (void)
int need_fp
= (! flag_omit_frame_pointer
|| (cfun->calls_alloca && EXIT_IGNORE_STACK)
/* We need the frame pointer to catch stack overflow exceptions
if the stack pointer is moving. */
|| (flag_stack_check && STACK_CHECK_MOVING_SP)
|| crtl->accesses_prior_frames
|| crtl->stack_realign_needed
|| targetm.frame_pointer_required ());

View file

@ -2252,6 +2252,11 @@ may_trap_p_1 (const_rtx x, unsigned flags)
/* Memory ref can trap unless it's a static var or a stack slot. */
case MEM:
/* Recognize specific pattern of stack checking probes. */
if (flag_stack_check
&& MEM_VOLATILE_P (x)
&& XEXP (x, 0) == stack_pointer_rtx)
return 1;
if (/* MEM_NOTRAP_P only relates to the actual position of the memory
reference; moving it out of context such as when moving code
when optimizing, might cause its address to become invalid. */

View file

@ -761,7 +761,7 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN;
TARGET_ASM_EXCEPTION_SECTION TARGET_ASM_EH_FRAME_SECTION \
SMALL_ARG_MAX ASM_OUTPUT_SHARED_BSS ASM_OUTPUT_SHARED_COMMON \
ASM_OUTPUT_SHARED_LOCAL UNALIGNED_WORD_ASM_OP \
ASM_MAKE_LABEL_LINKONCE
ASM_MAKE_LABEL_LINKONCE STACK_CHECK_PROBE_INTERVAL
/* Hooks that are no longer used. */
#pragma GCC poison LANG_HOOKS_FUNCTION_MARK LANG_HOOKS_FUNCTION_FREE \

View file

@ -1,3 +1,8 @@
2009-11-03 Eric Botcazou <ebotcazou@adacore.com>
* gnat.dg/stack_check.adb1: New test.
* gnat.dg/stack_check.adb2: Likewise.
2009-11-03 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/41917

View file

@ -0,0 +1,38 @@
-- { dg-do run }
-- { dg-options "-fstack-check" }
-- This test requires architecture- and OS-specific support code for unwinding
-- through signal frames (typically located in *-unwind.h) to pass. Feel free
-- to disable it if this code hasn't been implemented yet.
procedure Stack_Check1 is
type A is Array (1..2048) of Integer;
procedure Consume_Stack (N : Integer) is
My_A : A; -- 8 KB static
begin
My_A (1) := 0;
if N <= 0 then
return;
end if;
Consume_Stack (N-1);
end;
Task T;
Task body T is
begin
begin
Consume_Stack (Integer'Last);
raise Program_Error;
exception
when Storage_Error => null;
end;
Consume_Stack (128);
end;
begin
null;
end;

View file

@ -0,0 +1,43 @@
-- { dg-do run }
-- { dg-options "-fstack-check" }
-- This test requires architecture- and OS-specific support code for unwinding
-- through signal frames (typically located in *-unwind.h) to pass. Feel free
-- to disable it if this code hasn't been implemented yet.
procedure Stack_Check2 is
function UB return Integer is
begin
return 2048;
end;
type A is Array (Positive range <>) of Integer;
procedure Consume_Stack (N : Integer) is
My_A : A (1..UB); -- 8 KB dynamic
begin
My_A (1) := 0;
if N <= 0 then
return;
end if;
Consume_Stack (N-1);
end;
Task T;
Task body T is
begin
begin
Consume_Stack (Integer'Last);
raise Program_Error;
exception
when Storage_Error => null;
end;
Consume_Stack (128);
end;
begin
null;
end;

View file

@ -9009,7 +9009,8 @@ build_common_builtin_nodes (void)
tmp = tree_cons (NULL_TREE, size_type_node, void_list_node);
ftype = build_function_type (ptr_type_node, tmp);
local_define_builtin ("__builtin_alloca", ftype, BUILT_IN_ALLOCA,
"alloca", ECF_NOTHROW | ECF_MALLOC);
"alloca",
ECF_MALLOC | (flag_stack_check ? 0 : ECF_NOTHROW));
}
tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);

View file

@ -1559,7 +1559,13 @@ uw_install_context_1 (struct _Unwind_Context *current,
static inline _Unwind_Ptr
uw_identify_context (struct _Unwind_Context *context)
{
return _Unwind_GetCFA (context);
/* The CFA is not sufficient to disambiguate the context of a function
interrupted by a signal before establishing its frame and the context
of the signal itself. */
if (STACK_GROWS_DOWNWARD)
return _Unwind_GetCFA (context) - _Unwind_IsSignalFrame (context);
else
return _Unwind_GetCFA (context) + _Unwind_IsSignalFrame (context);
}