page long. The function returns a pointer to the resized segment. */
const NSegment *VG_(am_extend_into_adjacent_reservation_client)( Addr addr,
- SSizeT delta )
+ SSizeT delta,
+ Bool *overflow)
{
Int segA, segR;
UInt prot;
SysRes sres;
+ *overflow = False;
+
segA = find_nsegment_idx(addr);
aspacem_assert(nsegments[segA].kind == SkAnonC);
segR = segA+1;
if (segR >= nsegments_used
|| nsegments[segR].kind != SkResvn
- || nsegments[segR].smode != SmLower
- || nsegments[segR].start != nsegments[segA].end + 1
- || delta + VKI_PAGE_SIZE
- > (nsegments[segR].end - nsegments[segR].start + 1))
- return NULL;
+ || nsegments[segR].smode != SmLower)
+ return NULL;
+
+ if (delta + VKI_PAGE_SIZE
+ > (nsegments[segR].end - nsegments[segR].start + 1)) {
+ *overflow = True;
+ return NULL;
+ }
/* Extend the kernel's mapping. */
// DDD: #warning GrP fixme MAP_FIXED can clobber memory!
segR = segA-1;
if (segR < 0
|| nsegments[segR].kind != SkResvn
- || nsegments[segR].smode != SmUpper
- || nsegments[segR].end + 1 != nsegments[segA].start
- || delta + VKI_PAGE_SIZE
- > (nsegments[segR].end - nsegments[segR].start + 1))
- return NULL;
+ || nsegments[segR].smode != SmUpper)
+ return NULL;
+
+ if (delta + VKI_PAGE_SIZE
+ > (nsegments[segR].end - nsegments[segR].start + 1)) {
+ *overflow = True;
+ return NULL;
+ }
/* Extend the kernel's mapping. */
// DDD: #warning GrP fixme MAP_FIXED can clobber memory!
nsegments[segR].end -= delta;
nsegments[segA].start -= delta;
aspacem_assert(nsegments[segR].start <= nsegments[segR].end);
-
}
AM_SANITY_CHECK;
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+ if (VG_(extend_stack)(tid, addr)) {
stackseg = VG_(am_find_nsegment)(addr);
if (0 && stackseg)
VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+ if (VG_(extend_stack)(tid, addr)) {
stackseg = VG_(am_find_nsegment)(addr);
if (0 && stackseg)
VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+ if (VG_(extend_stack)(tid, addr)) {
stackseg = VG_(am_find_nsegment)(addr);
if (0 && stackseg)
VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB))
- {
- stackseg = VG_(am_find_nsegment)(addr);
- }
+ if (VG_(extend_stack)(tid, addr)) {
+ stackseg = VG_(am_find_nsegment)(addr);
+ }
if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW)
{
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+ if (VG_(extend_stack)(tid, addr)) {
stackseg = VG_(am_find_nsegment)(addr);
}
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+ if (VG_(extend_stack)(tid, addr)) {
stackseg = VG_(am_find_nsegment)(addr);
if (0 && stackseg)
VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+ if (VG_(extend_stack)(tid, addr)) {
stackseg = VG_(am_find_nsegment)(addr);
if (0 && stackseg)
VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+ if (VG_(extend_stack)(tid, addr)) {
stackseg = VG_(am_find_nsegment)(addr);
if (0 && stackseg)
VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
ThreadId tid = tst->tid;
NSegment const* stackseg = NULL;
- if (VG_(extend_stack)(addr, tst->client_stack_szB)) {
+ if (VG_(extend_stack)(tid, addr)) {
stackseg = VG_(am_find_nsegment)(addr);
if (0 && stackseg)
VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
+/* -*- mode: C; c-basic-offset: 3; -*- */
/*--------------------------------------------------------------------*/
/*--- Implementation of POSIX signals. m_signals.c ---*/
if (tid == 1) { // main thread
Addr esp = VG_(get_SP)(tid);
Addr base = VG_PGROUNDDN(esp - VG_STACK_REDZONE_SZB);
- if (VG_(extend_stack)(base, VG_(threads)[tid].client_stack_szB)) {
+ if (VG_(extend_stack)(tid, base)) {
if (VG_(clo_trace_signals))
VG_(dmsg)(" -> extended stack base to %#lx\n",
VG_PGROUNDDN(esp));
"while outside of scheduler");
}
-/* Extend the stack to cover addr. maxsize is the limit the stack can grow to.
+/* Extend the stack of thread #tid to cover addr.
Returns True on success, False on failure.
Succeeds without doing anything if addr is already within a segment.
Failure could be caused by:
- - addr not below a growable segment
- - new stack size would exceed maxsize
+ - addr not below a growable segment or in a free segment
+ - new stack size would exceed the stack limit for the given thread
- mmap failed for some other reason
- */
-Bool VG_(extend_stack)(Addr addr, UInt maxsize)
+*/
+Bool VG_(extend_stack)(ThreadId tid, Addr addr)
{
SizeT udelta;
- /* Find the next Segment above addr */
- NSegment const* seg
- = VG_(am_find_nsegment)(addr);
- NSegment const* seg_next
- = seg ? VG_(am_next_nsegment)( seg, True/*fwds*/ )
- : NULL;
+ /* Get the segment containing addr. */
+ const NSegment* seg = VG_(am_find_nsegment)(addr);
+ if (seg == NULL) return False; // addr in a SkFree segment
/* TODO: the test "seg->kind == SkAnonC" is really inadequate,
because although it tests whether the segment is mapped
_somehow_, it doesn't check that it has the right permissions
(r,w, maybe x) ? */
- if (seg && seg->kind == SkAnonC)
+ if (seg->kind == SkAnonC)
/* addr is already mapped. Nothing to do. */
return True;
- /* Check that the requested new base is in a shrink-down
- reservation section which abuts an anonymous mapping that
- belongs to the client. */
- if ( ! (seg
- && seg->kind == SkResvn
- && seg->smode == SmUpper
- && seg_next
- && seg_next->kind == SkAnonC
- && seg->end+1 == seg_next->start))
- return False;
+ /* Find the next Segment above addr. This will return NULL if ADDR
+ is bogus -- which it may be. See comment at the call site in function
+ VG_(client_syscall) */
+ const NSegment* seg_next = VG_(am_next_nsegment)( seg, True/*fwds*/ );
+ if (seg_next == NULL || seg_next->kind != SkAnonC) return False;
udelta = VG_PGROUNDUP(seg_next->start - addr);
+
VG_(debugLog)(1, "signals",
"extending a stack base 0x%llx down by %lld\n",
(ULong)seg_next->start, (ULong)udelta);
+ Bool overflow;
if (! VG_(am_extend_into_adjacent_reservation_client)
- ( seg_next->start, -(SSizeT)udelta )) {
- VG_(debugLog)(1, "signals", "extending a stack base: FAILED\n");
+ ( seg_next->start, -(SSizeT)udelta, &overflow )) {
+ Addr new_stack_base = seg_next->start - udelta;
+ if (overflow)
+ VG_(umsg)("Stack overflow in thread #%d: can't grow stack to %#lx\n",
+ tid, new_stack_base);
+ else
+ VG_(umsg)("Cannot map memory to grow the stack for thread #%d "
+ "to %#lx\n", tid, new_stack_base);
return False;
}
Addr fault;
Addr esp;
NSegment const* seg;
- NSegment const* seg_next;
if (info->si_signo != VKI_SIGSEGV)
return False;
fault = (Addr)info->VKI_SIGINFO_si_addr;
esp = VG_(get_SP)(tid);
seg = VG_(am_find_nsegment)(fault);
- seg_next = seg ? VG_(am_next_nsegment)( seg, True/*fwds*/ )
- : NULL;
if (VG_(clo_trace_signals)) {
if (seg == NULL)
if (info->si_code == VKI_SEGV_MAPERR
&& seg
- && seg->kind == SkResvn
- && seg->smode == SmUpper
- && seg_next
- && seg_next->kind == SkAnonC
- && seg->end+1 == seg_next->start
&& fault >= fault_mask(esp - VG_STACK_REDZONE_SZB)) {
/* If the fault address is above esp but below the current known
stack segment base, and it was a fault because there was
then extend the stack segment.
*/
Addr base = VG_PGROUNDDN(esp - VG_STACK_REDZONE_SZB);
- if (VG_(extend_stack)(base, VG_(threads)[tid].client_stack_szB)) {
+ if (VG_(extend_stack)(tid, base)) {
if (VG_(clo_trace_signals))
VG_(dmsg)(" -> extended stack base to %#lx\n",
VG_PGROUNDDN(fault));
return True;
} else {
- VG_(umsg)("Stack overflow in thread %d: can't grow stack to %#lx\n",
- tid, fault);
return False;
}
} else {
vg_assert(delta > 0);
vg_assert(VG_IS_PAGE_ALIGNED(delta));
- if (! VG_(am_extend_into_adjacent_reservation_client)( aseg->start, delta ))
+ Bool overflow; // ignored here
+ if (! VG_(am_extend_into_adjacent_reservation_client)( aseg->start, delta,
+ &overflow))
goto bad;
VG_(brk_limit) = newbrk;
if (tid == 1/*ROOT THREAD*/) {
Addr stackMin = VG_(get_SP)(tid) - VG_STACK_REDZONE_SZB;
- VG_(extend_stack)( stackMin, tst->client_stack_szB );
+ /* Note, that the stack pointer can be bogus at this point. This is
+ extremely rare. A legitimate testcase that exercises this is
+ none/tests/s390x/stmg.c: The stack pointer happens to be in the
+ reservation segment near the end of the addressable memory and
+ there is no SkAnonC segment above.
+
+ We could do slightly better here by not extending the stack for
+ system calls that do not access user space memory. That's busy
+ work with very little gain... */
+ VG_(extend_stack)( tid, stackMin ); // may fail
}
# endif
/* END ensure root thread's stack is suitably mapped */
the reservation segment after the operation must be at least one
page long. The function returns a pointer to the resized segment. */
extern const NSegment *VG_(am_extend_into_adjacent_reservation_client)
- ( Addr addr, SSizeT delta );
+ ( Addr addr, SSizeT delta, /*OUT*/Bool *overflow );
/* --- --- --- resizing/move a mapping --- --- --- */
extern void VG_(synth_sigfpe) (ThreadId tid, UInt code);
/* Extend the stack to cover addr, if possible */
-extern Bool VG_(extend_stack)(Addr addr, UInt maxsize);
+extern Bool VG_(extend_stack)(ThreadId tid, Addr addr);
/* Forces the client's signal handler to SIG_DFL - generally just
before using that signal to kill the process. */
mremap.stderr.exp mremap.stderr.exp-glibc27 mremap.stdout.exp \
mremap.vgtest \
mremap2.stderr.exp mremap2.stdout.exp mremap2.vgtest \
- mremap3.stderr.exp mremap3.stdout.exp mremap3.vgtest
+ mremap3.stderr.exp mremap3.stdout.exp mremap3.vgtest \
+ stack-overflow.stderr.exp stack-overflow.vgtest
check_PROGRAMS = \
blockfault \
mremap \
mremap2 \
- mremap3
+ mremap3 \
+ stack-overflow
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
-
--- /dev/null
+/* There should be a user message about the overflow.
+ Wrtten in a single line so there is no confusion on what line
+ the overflow occurs. */
+
+int main(int argc, char *argv[]) \
+{ \
+ volatile int arr[1000]; \
+ return main(arr[argc%2], 0); \
+}
--- /dev/null
+
+Stack overflow in thread #1: can't grow stack to 0x........
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+Stack overflow in thread #1: can't grow stack to 0x........
+ at 0x........: main (stack-overflow.c:6)
+ If you believe this happened as a result of a stack
+ overflow in your program's main thread (unlikely but
+ possible), you can try to increase the size of the
+ main thread stack using the --main-stacksize= flag.
+ The main thread stack size used in this run was ....
+
--- /dev/null
+prog: stack-overflow