}
+/* Check whether ADDR looks like a bogus stack pointer. Non-bogosity is
+ defined as follows: ADDR is not bogus if
+ (1) it points into an already mapped stack segment, OR
+ (2) it points into a reservation segment into which an abutting SkAnonC
+ segment can be extended. */
+Bool VG_(am_is_bogus_client_stack_pointer)( Addr addr )
+{
+ const NSegment *seg = nsegments + find_nsegment_idx(addr);
+
+ switch (seg->kind) {
+ case SkFree:
+ case SkAnonV:
+ case SkFileV:
+ case SkFileC:
+ case SkShmC:
+ return True;
+
+ case SkResvn: {
+ if (seg->smode != SmUpper) return True;
+ /* If the the abutting segment towards higher addresses is an SkAnonC
+ segment, then ADDR is a future stack pointer. */
+ const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ True);
+ if (next == NULL || next->kind != SkAnonC) return True;
+
+ /* OK; looks like a stack segment */
+ return False;
+ }
+
+ case SkAnonC: {
+ /* If the abutting segment towards lower addresses is an SkResvn
+ segment, then ADDR is a stack pointer into mapped memory. */
+ const NSegment *next = VG_(am_next_nsegment)(seg, /*forward*/ False);
+ if (next == NULL || next->kind != SkResvn || seg->smode != SmUpper)
+ return True;
+
+ /* OK; looks like a stack segment */
+ return False;
+ }
+
+ default:
+ aspacem_assert(0); // should never happen
+ }
+}
+
/*-----------------------------------------------------------------*/
/*--- ---*/
/*--- Modifying the segment array, and constructing segments. ---*/
"while outside of scheduler");
}
-/* Extend the stack of thread #tid to cover addr.
+/* Extend the stack of thread #tid to cover addr. It is expected that
+ addr either points into an already mapped anonymous segment or into a
+ reservation segment abutting the stack segment. Everything else is a bug.
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 or in a free segment
+ - addr not below a growable segment
- new stack size would exceed the stack limit for the given thread
- mmap failed for some other reason
*/
/* Get the segment containing addr. */
const NSegment* seg = VG_(am_find_nsegment)(addr);
- if (seg == NULL) return False; // addr in a SkFree segment
+ vg_assert(seg != NULL);
/* TODO: the test "seg->kind == SkAnonC" is really inadequate,
because although it tests whether the segment is mapped
/* addr is already mapped. Nothing to do. */
return True;
- /* 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;
+ vg_assert(seg_next != NULL);
udelta = VG_PGROUNDUP(seg_next->start - addr);
if (tid == 1/*ROOT THREAD*/) {
Addr stackMin = VG_(get_SP)(tid) - VG_STACK_REDZONE_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
+ /* The precise thing to do here would be to extend the stack only
+ if the system call can be proven to access unmapped user stack
+ memory. That is an enormous amount of work even if a proper
+ spec of system calls was available.
+
+ In the case where the system call does not access user memory
+ the stack pointer here can have any value. 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.
+
+ So the approximation we're taking here is to extend the stack only
+ if the client stack pointer does not look bogus. */
+ if (! VG_(am_is_bogus_client_stack_pointer)(stackMin))
+ VG_(extend_stack)( tid, stackMin );
}
# endif
/* END ensure root thread's stack is suitably mapped */
extern Bool VG_(am_is_valid_for_client_or_free_or_resvn)
( Addr start, SizeT len, UInt prot );
+/* Check whether ADDR looks like a bogus stack pointer. */
+extern Bool VG_(am_is_bogus_client_stack_pointer)( Addr addr );
+
/* Trivial fn: return the total amount of space in anonymous mappings,
both for V and the client. Is used for printing stats in
out-of-memory messages. */
int res, i;
stack_t sigstk;
struct sigaction act;
- static const int size = SIGSTKSZ*4;
+ static const int size = SIGSTKSZ*2;
// We give EXEC permissions because this won't work on ppc32 unless you
// ask for an alt stack with EXEC permissions,
// since signal returning requires execution of code on the stack.