Fix an assertion in the address space manager. BZ #345887.
The VG_(extend_stack) call needs to be properly guarded because the
passed-in address is not necessarily part of an extensible stack
segment. And an extensible stack segment is the only thing that
function should have to deal with.
Previously, the function VG_(am_addr_is_in_extensible_client_stack)
was introduced to guard VG_(extend_stack) but it was not added in all
places it should have been.
Also, extending the client stack during signal delivery (in sigframe-common.c)
was simply calling VG_(extend_stack) hoping it would do the right thing.
But that was not always the case. The new testcase
none/tests/linux/pthread-stack.c exercises this (3.10.1 errors out on it).
Renamed ML_(sf_extend_stack) to ML_(sf_maybe_extend_stack) and add
proper guard logic for VG_(extend_stack).
Testcases none/tests/{amd64|x86}-linux/bug345887.c by Ivo Raisr.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@15138 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/NEWS b/NEWS
index 9fdc795..2a61168 100644
--- a/NEWS
+++ b/NEWS
@@ -151,6 +151,7 @@
345016 helgrind/tests/locked_vs_unlocked2 is failing sometimes
345394 Fix memcheck/tests/strchr on OS X
345637 Fix memcheck/tests/sendmsg on OS X
+345887 Fix an assertion in the address space manager
346307 fuse filesystem syscall deadlocks
n-i-bz Provide implementations of certain compiler builtins to support
compilers who may not provide those
diff --git a/configure.ac b/configure.ac
index a5aa964..d03aa5c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3033,6 +3033,7 @@
none/tests/tilegx/Makefile
none/tests/linux/Makefile
none/tests/darwin/Makefile
+ none/tests/amd64-linux/Makefile
none/tests/x86-linux/Makefile
exp-sgcheck/Makefile
exp-sgcheck/tests/Makefile
diff --git a/coregrind/m_sigframe/priv_sigframe.h b/coregrind/m_sigframe/priv_sigframe.h
index a81f4d0..7435185 100644
--- a/coregrind/m_sigframe/priv_sigframe.h
+++ b/coregrind/m_sigframe/priv_sigframe.h
@@ -37,7 +37,8 @@
/* --------------- Implemented in sigframe-common.c ---------------*/
-Bool ML_(sf_extend_stack)( const ThreadState *tst, Addr addr, SizeT size );
+Bool ML_(sf_maybe_extend_stack)( const ThreadState *tst, Addr addr,
+ SizeT size, UInt flags );
#endif // __PRIV_SIGFRAME_H
diff --git a/coregrind/m_sigframe/sigframe-amd64-darwin.c b/coregrind/m_sigframe/sigframe-amd64-darwin.c
index 77752be..38682f3 100644
--- a/coregrind/m_sigframe/sigframe-amd64-darwin.c
+++ b/coregrind/m_sigframe/sigframe-amd64-darwin.c
@@ -109,7 +109,7 @@
entry to a function. */
tst = VG_(get_ThreadState)(tid);
- if (! ML_(sf_extend_stack)(tst, rsp, sp_top_of_frame - rsp))
+ if (! ML_(sf_maybe_extend_stack)(tst, rsp, sp_top_of_frame - rsp, flags))
return;
vg_assert(VG_IS_16_ALIGNED(rsp+8));
diff --git a/coregrind/m_sigframe/sigframe-amd64-linux.c b/coregrind/m_sigframe/sigframe-amd64-linux.c
index a2b79e5..e015401 100644
--- a/coregrind/m_sigframe/sigframe-amd64-linux.c
+++ b/coregrind/m_sigframe/sigframe-amd64-linux.c
@@ -412,7 +412,7 @@
rsp = VG_ROUNDDN(rsp, 16) - 8;
frame = (struct rt_sigframe *)rsp;
- if (! ML_(sf_extend_stack)(tst, rsp, sizeof(*frame)))
+ if (! ML_(sf_maybe_extend_stack)(tst, rsp, sizeof(*frame), flags))
return rsp_top_of_frame;
/* retaddr, siginfo, uContext fields are to be written */
diff --git a/coregrind/m_sigframe/sigframe-arm-linux.c b/coregrind/m_sigframe/sigframe-arm-linux.c
index dbbebc3..7ae7f07 100644
--- a/coregrind/m_sigframe/sigframe-arm-linux.c
+++ b/coregrind/m_sigframe/sigframe-arm-linux.c
@@ -185,7 +185,7 @@
sp -= size;
sp = VG_ROUNDDN(sp, 16);
- if(! ML_(sf_extend_stack)(tst, sp, size))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, size, flags))
I_die_here; // XXX Incorrect behavior
diff --git a/coregrind/m_sigframe/sigframe-arm64-linux.c b/coregrind/m_sigframe/sigframe-arm64-linux.c
index 1b09696..1a7c984 100644
--- a/coregrind/m_sigframe/sigframe-arm64-linux.c
+++ b/coregrind/m_sigframe/sigframe-arm64-linux.c
@@ -173,7 +173,7 @@
sp -= size;
sp = VG_ROUNDDN(sp, 16);
- if (! ML_(sf_extend_stack)(tst, sp, size))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, size, flags))
return; // Give up. No idea if this is correct
struct rt_sigframe *rsf = (struct rt_sigframe *)sp;
diff --git a/coregrind/m_sigframe/sigframe-common.c b/coregrind/m_sigframe/sigframe-common.c
index 59b34ee..12ef1ed 100644
--- a/coregrind/m_sigframe/sigframe-common.c
+++ b/coregrind/m_sigframe/sigframe-common.c
@@ -54,16 +54,31 @@
/* Extend the stack segment downwards if needed so as to ensure the
new signal frames are mapped to something. Return a Bool
indicating whether or not the operation was successful. */
-Bool ML_(sf_extend_stack) ( const ThreadState *tst, Addr addr, SizeT size )
+Bool ML_(sf_maybe_extend_stack) ( const ThreadState *tst, Addr addr,
+ SizeT size, UInt flags )
{
ThreadId tid = tst->tid;
const NSegment *stackseg = NULL;
- if (VG_(extend_stack)(tid, addr)) {
+ if (flags & VKI_SA_ONSTACK) {
+ /* If the sigframe is allocated on an alternate stack, then we cannot
+ extend that stack. Nothing to do here. */
stackseg = VG_(am_find_nsegment)(addr);
- if (0 && stackseg)
- VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
- addr, stackseg->start, stackseg->end);
+ } else if (VG_(am_addr_is_in_extensible_client_stack)(addr)) {
+ if (VG_(extend_stack)(tid, addr)) {
+ stackseg = VG_(am_find_nsegment)(addr);
+ if (0 && stackseg)
+ VG_(printf)("frame=%#lx seg=%#lx-%#lx\n",
+ addr, stackseg->start, stackseg->end);
+ }
+ } else if ((stackseg = VG_(am_find_nsegment)(addr)) &&
+ VG_(am_is_valid_for_client)(addr, 1,
+ VKI_PROT_READ | VKI_PROT_WRITE)) {
+ /* We come here for explicitly defined pthread-stacks which can be
+ located in any client segment. */
+ } else {
+ /* Something unexpected */
+ stackseg = NULL;
}
if (stackseg == NULL || !stackseg->hasR || !stackseg->hasW) {
diff --git a/coregrind/m_sigframe/sigframe-mips32-linux.c b/coregrind/m_sigframe/sigframe-mips32-linux.c
index 6f09e4d..0e27e01 100644
--- a/coregrind/m_sigframe/sigframe-mips32-linux.c
+++ b/coregrind/m_sigframe/sigframe-mips32-linux.c
@@ -148,7 +148,7 @@
}
tst = VG_(get_ThreadState)(tid);
- if (! ML_(sf_extend_stack)(tst, sp, sp_top_of_frame - sp))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, sp_top_of_frame - sp, flags))
return;
vg_assert(VG_IS_8_ALIGNED(sp));
diff --git a/coregrind/m_sigframe/sigframe-mips64-linux.c b/coregrind/m_sigframe/sigframe-mips64-linux.c
index fa6615b..cacf9ce 100644
--- a/coregrind/m_sigframe/sigframe-mips64-linux.c
+++ b/coregrind/m_sigframe/sigframe-mips64-linux.c
@@ -135,7 +135,7 @@
sp = sp_top_of_frame - sizeof(struct rt_sigframe);
tst = VG_(get_ThreadState)(tid);
- if (! ML_(sf_extend_stack)(tst, sp, sp_top_of_frame - sp))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, sp_top_of_frame - sp, flags))
return;
sp = VG_ROUNDDN(sp, 16);
diff --git a/coregrind/m_sigframe/sigframe-ppc32-linux.c b/coregrind/m_sigframe/sigframe-ppc32-linux.c
index 346abb2..467814d 100644
--- a/coregrind/m_sigframe/sigframe-ppc32-linux.c
+++ b/coregrind/m_sigframe/sigframe-ppc32-linux.c
@@ -650,7 +650,7 @@
tst = VG_(get_ThreadState)(tid);
- if (! ML_(sf_extend_stack)(tst, sp, sp_top_of_frame - sp))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, sp_top_of_frame - sp, flags))
return;
vg_assert(VG_IS_16_ALIGNED(sp));
diff --git a/coregrind/m_sigframe/sigframe-ppc64-linux.c b/coregrind/m_sigframe/sigframe-ppc64-linux.c
index 8a6bcb3..5e90e54 100644
--- a/coregrind/m_sigframe/sigframe-ppc64-linux.c
+++ b/coregrind/m_sigframe/sigframe-ppc64-linux.c
@@ -158,7 +158,7 @@
sp = sp_top_of_frame - sizeof(struct rt_sigframe);
tst = VG_(get_ThreadState)(tid);
- if (! ML_(sf_extend_stack)(tst, sp, sp_top_of_frame - sp))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, sp_top_of_frame - sp, flags))
return;
vg_assert(VG_IS_16_ALIGNED(sp));
diff --git a/coregrind/m_sigframe/sigframe-s390x-linux.c b/coregrind/m_sigframe/sigframe-s390x-linux.c
index b3ca4ae..0568922 100644
--- a/coregrind/m_sigframe/sigframe-s390x-linux.c
+++ b/coregrind/m_sigframe/sigframe-s390x-linux.c
@@ -298,7 +298,7 @@
sp -= sizeof(*frame);
frame = (struct sigframe *)sp;
- if (! ML_(sf_extend_stack)(tst, sp, sizeof(*frame)))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, sizeof(*frame), flags))
return sp_top_of_frame;
/* retcode, sigNo, sc, sregs fields are to be written */
@@ -358,7 +358,7 @@
sp -= sizeof(*frame);
frame = (struct rt_sigframe *)sp;
- if (! ML_(sf_extend_stack)(tst, sp, sizeof(*frame)))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, sizeof(*frame), flags))
return sp_top_of_frame;
/* retcode, sigNo, sc, sregs fields are to be written */
diff --git a/coregrind/m_sigframe/sigframe-tilegx-linux.c b/coregrind/m_sigframe/sigframe-tilegx-linux.c
index 48d0859..b9de920 100644
--- a/coregrind/m_sigframe/sigframe-tilegx-linux.c
+++ b/coregrind/m_sigframe/sigframe-tilegx-linux.c
@@ -158,7 +158,7 @@
sp = sp_top_of_frame - sizeof(struct rt_sigframe);
tst = VG_(get_ThreadState)(tid);
- if (! ML_(sf_extend_stack)(tst, sp, sizeof(struct rt_sigframe)))
+ if (! ML_(sf_maybe_extend_stack)(tst, sp, sizeof(struct rt_sigframe), flags))
return;
vg_assert(VG_IS_8_ALIGNED(sp));
diff --git a/coregrind/m_sigframe/sigframe-x86-darwin.c b/coregrind/m_sigframe/sigframe-x86-darwin.c
index 6c2c1ef..e3da65d 100644
--- a/coregrind/m_sigframe/sigframe-x86-darwin.c
+++ b/coregrind/m_sigframe/sigframe-x86-darwin.c
@@ -112,7 +112,7 @@
entry to a function. */
tst = VG_(get_ThreadState)(tid);
- if (! ML_(sf_extend_stack)(tst, esp, sp_top_of_frame - esp))
+ if (! ML_(sf_maybe_extend_stack)(tst, esp, sp_top_of_frame - esp, flags))
return;
vg_assert(VG_IS_16_ALIGNED(esp+4));
diff --git a/coregrind/m_sigframe/sigframe-x86-linux.c b/coregrind/m_sigframe/sigframe-x86-linux.c
index d6597b6..a09aaf2 100644
--- a/coregrind/m_sigframe/sigframe-x86-linux.c
+++ b/coregrind/m_sigframe/sigframe-x86-linux.c
@@ -434,7 +434,7 @@
esp = VG_ROUNDDN(esp, 16);
frame = (struct sigframe *)esp;
- if (! ML_(sf_extend_stack)(tst, esp, sizeof(*frame)))
+ if (! ML_(sf_maybe_extend_stack)(tst, esp, sizeof(*frame), flags))
return esp_top_of_frame;
/* retaddr, sigNo, siguContext fields are to be written */
@@ -491,7 +491,7 @@
esp = VG_ROUNDDN(esp, 16);
frame = (struct rt_sigframe *)esp;
- if (! ML_(sf_extend_stack)(tst, esp, sizeof(*frame)))
+ if (! ML_(sf_maybe_extend_stack)(tst, esp, sizeof(*frame), flags))
return esp_top_of_frame;
/* retaddr, sigNo, pSiginfo, puContext fields are to be written */
diff --git a/coregrind/m_signals.c b/coregrind/m_signals.c
index 5dc5f2f..47a345f 100644
--- a/coregrind/m_signals.c
+++ b/coregrind/m_signals.c
@@ -1737,7 +1737,8 @@
if (tid == 1) { // main thread
Addr esp = VG_(get_SP)(tid);
Addr base = VG_PGROUNDDN(esp - VG_STACK_REDZONE_SZB);
- if (VG_(extend_stack)(tid, base)) {
+ if (VG_(am_addr_is_in_extensible_client_stack)(base) &&
+ VG_(extend_stack)(tid, base)) {
if (VG_(clo_trace_signals))
VG_(dmsg)(" -> extended stack base to %#lx\n",
VG_PGROUNDDN(esp));
@@ -2462,7 +2463,8 @@
then extend the stack segment.
*/
Addr base = VG_PGROUNDDN(esp - VG_STACK_REDZONE_SZB);
- if (VG_(extend_stack)(tid, base)) {
+ if (VG_(am_addr_is_in_extensible_client_stack)(base) &&
+ VG_(extend_stack)(tid, base)) {
if (VG_(clo_trace_signals))
VG_(dmsg)(" -> extended stack base to %#lx\n",
VG_PGROUNDDN(fault));
diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am
index 8997064..4edbeaa 100644
--- a/none/tests/Makefile.am
+++ b/none/tests/Makefile.am
@@ -45,12 +45,15 @@
endif
# Platform-specific tests
+if VGCONF_PLATFORMS_INCLUDE_AMD64_LINUX
+SUBDIRS += amd64-linux
+endif
if VGCONF_PLATFORMS_INCLUDE_X86_LINUX
SUBDIRS += x86-linux
endif
DIST_SUBDIRS = x86 amd64 ppc32 ppc64 arm arm64 s390x mips32 mips64 tilegx \
- linux darwin x86-linux scripts .
+ linux darwin amd64-linux x86-linux scripts .
dist_noinst_SCRIPTS = \
filter_cmdline0 \
diff --git a/none/tests/amd64-linux/Makefile.am b/none/tests/amd64-linux/Makefile.am
new file mode 100644
index 0000000..39d7bac
--- /dev/null
+++ b/none/tests/amd64-linux/Makefile.am
@@ -0,0 +1,15 @@
+
+include $(top_srcdir)/Makefile.tool-tests.am
+
+dist_noinst_SCRIPTS = \
+ filter_stderr filter_minimal
+
+EXTRA_DIST = \
+ bug345887.stderr.exp bug345887.vgtest
+
+check_PROGRAMS = \
+ bug345887
+
+AM_CFLAGS += @FLAG_M64@
+AM_CXXFLAGS += @FLAG_M64@
+AM_CCASFLAGS += @FLAG_M64@
diff --git a/none/tests/amd64-linux/bug345887.c b/none/tests/amd64-linux/bug345887.c
new file mode 100644
index 0000000..0f9237d
--- /dev/null
+++ b/none/tests/amd64-linux/bug345887.c
@@ -0,0 +1,42 @@
+/* This test used to cause an assertion in the address space manager */
+
+__attribute__((noinline))
+static void inner(void)
+{
+ /* Set registers to apriori known values. */
+ __asm__ __volatile__(
+ "movq $0x101, %%rax\n"
+ "movq $0x102, %%rbx\n"
+ "movq $0x103, %%rcx\n"
+ "movq $0x104, %%rdx\n"
+ "movq $0x105, %%rsi\n"
+ "movq $0x106, %%rdi\n"
+ "movq $0x107, %%r8\n"
+ "movq $0x108, %%r9\n"
+ "movq $0x109, %%r10\n"
+ "movq $0x10a, %%r11\n"
+ "movq $0x10b, %%r12\n"
+ "movq $0x10c, %%r13\n"
+ "movq $0x10d, %%r14\n"
+ "movq $0x10e, %%r15\n"
+ // not %rbp as mdb is then not able to reconstruct stack trace
+ "movq $0x10f, %%rsp\n"
+ "movq $0x1234, (%%rax)\n" // should cause SEGV here
+ "ud2" // should never get here
+ : // no output registers
+ : // no input registers
+ : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15", "%rsp");
+}
+
+__attribute__((noinline))
+static void outer(void)
+{
+ inner();
+}
+
+int main(int argc, const char *argv[])
+{
+ outer();
+ return 0;
+}
diff --git a/none/tests/amd64-linux/bug345887.stderr.exp b/none/tests/amd64-linux/bug345887.stderr.exp
new file mode 100644
index 0000000..129193c
--- /dev/null
+++ b/none/tests/amd64-linux/bug345887.stderr.exp
@@ -0,0 +1,9 @@
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+ at 0x........: inner (bug345887.c:7)
+ 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 ....
diff --git a/none/tests/amd64-linux/bug345887.vgtest b/none/tests/amd64-linux/bug345887.vgtest
new file mode 100644
index 0000000..c014423
--- /dev/null
+++ b/none/tests/amd64-linux/bug345887.vgtest
@@ -0,0 +1,4 @@
+prog: bug345887
+vgopts: -q
+stderr_filter: filter_minimal
+cleanup: rm -f vgcore.*
diff --git a/none/tests/amd64-linux/filter_minimal b/none/tests/amd64-linux/filter_minimal
new file mode 100755
index 0000000..e69398c
--- /dev/null
+++ b/none/tests/amd64-linux/filter_minimal
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+# Remove ==pid== and **pid** strings
+perl -p -e 's/(==|\*\*)[0-9]{1,7}\1 //' |
+
+perl -p -e 's/0x[0-9A-Fa-f]+/0x......../g' |
+
+# Older bash versions print abnormal termination messages on the stderr
+# of the bash process. Newer bash versions redirect such messages properly.
+# Suppress any redirected abnormal termination messages. You can find the
+# complete list of messages in the bash source file siglist.c.
+perl -n -e 'print if !/^(Segmentation fault|Alarm clock|Aborted|Bus error)( \(core dumped\))?$/' |
+
+# Remove the size in "The main thread stack size..." message.
+sed "s/The main thread stack size used in this run was [0-9]*/The main thread stack size used in this run was .../"
+
+# NOTE: it is essential for the bug345887 testcase that the stderr
+# filtering does *not* remove lines beginning with --
diff --git a/none/tests/amd64-linux/filter_stderr b/none/tests/amd64-linux/filter_stderr
new file mode 100755
index 0000000..587754a
--- /dev/null
+++ b/none/tests/amd64-linux/filter_stderr
@@ -0,0 +1,11 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+# Remove ==pid== and --pid-- and **pid** strings
+perl -p -e 's/(==|--|\*\*)[0-9]{1,7}\1 //' |
+
+perl -p -e 's/0x[0-9A-Fa-f]+/0x......../g'
+
+# NOTE: it is essential for the bug345887 testcase that the stderr
+# filtering does *not* remove lines beginning with --
diff --git a/none/tests/linux/Makefile.am b/none/tests/linux/Makefile.am
index 87f780c..0ac75da 100644
--- a/none/tests/linux/Makefile.am
+++ b/none/tests/linux/Makefile.am
@@ -9,6 +9,7 @@
mremap.vgtest \
mremap2.stderr.exp mremap2.stdout.exp mremap2.vgtest \
mremap3.stderr.exp mremap3.stdout.exp mremap3.vgtest \
+ pthread-stack.stderr.exp pthread-stack.vgtest \
stack-overflow.stderr.exp stack-overflow.vgtest
check_PROGRAMS = \
@@ -16,8 +17,12 @@
mremap \
mremap2 \
mremap3 \
+ pthread-stack \
stack-overflow
AM_CFLAGS += $(AM_FLAG_M3264_PRI)
AM_CXXFLAGS += $(AM_FLAG_M3264_PRI)
+
+# Special needs
+pthread_stack_LDADD = -lpthread
diff --git a/none/tests/linux/pthread-stack.c b/none/tests/linux/pthread-stack.c
new file mode 100644
index 0000000..4b7a953
--- /dev/null
+++ b/none/tests/linux/pthread-stack.c
@@ -0,0 +1,109 @@
+/* This test causes an error in 3.10.1 and earlier versions like so:
+
+==8336== Can't extend stack to 0x4033f98 during signal delivery for thread 2:
+==8336== no stack segment
+
+ The reason was that only AnonC segments were considered as stack
+ segments. */
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+static volatile char *lowest_j;
+static jmp_buf goback;
+
+static void sigsegv_handler(int signr)
+{
+ longjmp(goback, 1);
+}
+
+static void bad_things_till_guard_page(void)
+{
+ fprintf(stderr, "... doing bad things till guard page\n");
+ char j = 0;
+ char *p = &j;
+
+ for (;;) {
+ j = j + *p;
+ p = p - 400;
+ lowest_j = p;
+ }
+}
+
+static void say_something(void)
+{
+ fprintf(stderr, "plugh\n");
+}
+
+static void* child_func ( void* arg )
+{
+ if (setjmp(goback)) {
+ say_something();
+ } else
+ bad_things_till_guard_page();
+
+ return NULL;
+}
+
+int main(int argc, const char** argv)
+{
+ int r, fd;
+
+ /* We will discover the thread guard page using SEGV.
+ So, prepare an handler. */
+ struct sigaction sa;
+ sa.sa_handler = sigsegv_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ if (sigaction (SIGSEGV, &sa, NULL) != 0)
+ perror("sigaction");
+
+ pthread_t child;
+
+ /* Create a file that will be used as stack for a pthread. */
+ const size_t file_size = 1024 * 1024;
+ const char file_name[] = "FILE";
+ fd = open(file_name, O_CREAT|O_WRONLY,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ assert(fd > 0);
+ void *p = malloc(file_size);
+ assert(p != 0);
+ memset(p, 0, file_size);
+ int written = write(fd, p, file_size);
+ assert(written == file_size);
+ close(fd);
+
+ /* Create a file-based stack for the child */
+ fd = open(file_name, O_CREAT|O_RDWR,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
+ assert(fd > 0);
+ const size_t stack_size = 256 * 1024;
+ assert(stack_size < file_size);
+ void *stack = mmap(NULL, stack_size, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE, fd, 0);
+ assert(stack != (void *)-1);
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ r = pthread_attr_setstack(&attr, stack, stack_size);
+ assert(r == 0);
+
+ /* Create child run */
+ r = pthread_create(&child, &attr, child_func, NULL);
+ assert(r == 0);
+ r = pthread_join(child, NULL);
+ assert(r == 0);
+
+ /* Remove file */
+ unlink(file_name);
+ return 0;
+}
+
diff --git a/none/tests/linux/pthread-stack.stderr.exp b/none/tests/linux/pthread-stack.stderr.exp
new file mode 100644
index 0000000..391e60c
--- /dev/null
+++ b/none/tests/linux/pthread-stack.stderr.exp
@@ -0,0 +1,2 @@
+... doing bad things till guard page
+plugh
diff --git a/none/tests/linux/pthread-stack.vgtest b/none/tests/linux/pthread-stack.vgtest
new file mode 100644
index 0000000..50cafcb
--- /dev/null
+++ b/none/tests/linux/pthread-stack.vgtest
@@ -0,0 +1,2 @@
+prog: pthread-stack
+vgopts: -q
diff --git a/none/tests/x86-linux/Makefile.am b/none/tests/x86-linux/Makefile.am
index 8592f1d..4fa0fac 100644
--- a/none/tests/x86-linux/Makefile.am
+++ b/none/tests/x86-linux/Makefile.am
@@ -2,14 +2,16 @@
include $(top_srcdir)/Makefile.tool-tests.am
dist_noinst_SCRIPTS = \
- filter_stderr
+ filter_stderr filter_minimal
EXTRA_DIST = \
+ bug345887.stderr.exp bug345887.vgtest \
hang.stderr.exp hang.vgtest \
seg_override.stderr.exp seg_override.stdout.exp seg_override.vgtest \
sigcontext.stdout.exp sigcontext.stderr.exp sigcontext.vgtest
check_PROGRAMS = \
+ bug345887 \
hang \
seg_override \
sigcontext
@@ -17,5 +19,3 @@
AM_CFLAGS += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
AM_CXXFLAGS += @FLAG_M32@ $(FLAG_MMMX) $(FLAG_MSSE)
AM_CCASFLAGS += @FLAG_M32@
-
-
diff --git a/none/tests/x86-linux/bug345887.c b/none/tests/x86-linux/bug345887.c
new file mode 100644
index 0000000..f2e8a8d
--- /dev/null
+++ b/none/tests/x86-linux/bug345887.c
@@ -0,0 +1,33 @@
+/* This test used to cause an assertion in the address space manager */
+
+__attribute__((noinline))
+static void inner(void)
+{
+ /* Set other registers to apriori known values. */
+ __asm__ __volatile__(
+ "movl $0x101, %%eax\n"
+ "movl $0x102, %%ebx\n"
+ "movl $0x103, %%ecx\n"
+ "movl $0x104, %%edx\n"
+ "movl $0x105, %%esi\n"
+ "movl $0x106, %%edi\n"
+ // not %ebp as mdb is then not able to reconstruct stack trace
+ "movl $0x108, %%esp\n"
+ "movl $0x1234, (%%eax)\n" // should cause SEGV here
+ "ud2" // should never get here
+ : // no output registers
+ : // no input registers
+ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "%esp");
+}
+
+__attribute__((noinline))
+static void outer(void)
+{
+ inner();
+}
+
+int main(int argc, const char *argv[])
+{
+ outer();
+ return 0;
+}
diff --git a/none/tests/x86-linux/bug345887.stderr.exp b/none/tests/x86-linux/bug345887.stderr.exp
new file mode 100644
index 0000000..129193c
--- /dev/null
+++ b/none/tests/x86-linux/bug345887.stderr.exp
@@ -0,0 +1,9 @@
+
+Process terminating with default action of signal 11 (SIGSEGV)
+ Access not within mapped region at address 0x........
+ at 0x........: inner (bug345887.c:7)
+ 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 ....
diff --git a/none/tests/x86-linux/bug345887.vgtest b/none/tests/x86-linux/bug345887.vgtest
new file mode 100644
index 0000000..c014423
--- /dev/null
+++ b/none/tests/x86-linux/bug345887.vgtest
@@ -0,0 +1,4 @@
+prog: bug345887
+vgopts: -q
+stderr_filter: filter_minimal
+cleanup: rm -f vgcore.*
diff --git a/none/tests/x86-linux/filter_minimal b/none/tests/x86-linux/filter_minimal
new file mode 100755
index 0000000..e69398c
--- /dev/null
+++ b/none/tests/x86-linux/filter_minimal
@@ -0,0 +1,20 @@
+#! /bin/sh
+
+dir=`dirname $0`
+
+# Remove ==pid== and **pid** strings
+perl -p -e 's/(==|\*\*)[0-9]{1,7}\1 //' |
+
+perl -p -e 's/0x[0-9A-Fa-f]+/0x......../g' |
+
+# Older bash versions print abnormal termination messages on the stderr
+# of the bash process. Newer bash versions redirect such messages properly.
+# Suppress any redirected abnormal termination messages. You can find the
+# complete list of messages in the bash source file siglist.c.
+perl -n -e 'print if !/^(Segmentation fault|Alarm clock|Aborted|Bus error)( \(core dumped\))?$/' |
+
+# Remove the size in "The main thread stack size..." message.
+sed "s/The main thread stack size used in this run was [0-9]*/The main thread stack size used in this run was .../"
+
+# NOTE: it is essential for the bug345887 testcase that the stderr
+# filtering does *not* remove lines beginning with --