Mail Archives: cygwin/2015/07/06/06:02:25
--QHp3Wr1K3N9pKO2V
Content-Type: multipart/mixed; boundary="Wt10+cXOThorkX0z"
Content-Disposition: inline
--Wt10+cXOThorkX0z
Content-Type: text/plain; charset=utf-8
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable
Hi Ken,
thanks for further testing this.
On Jul 5 22:15, Ken Brown wrote:
> On 7/5/2015 5:34 PM, Corinna Vinschen wrote:
> >This test release needs some good testing!
>=20
> I repeated the emacs experiment discussed in the "[ANNOUNCEMENT] TEST
> RELEASE: Cygwin 2.1.0-0.1" thread. In the 32-bit case, the results were
> more-or-less the same as before: I forced a stack overflow, emacs recover=
ed,
> I tried to continue working, there was a second SIGSEGV, and handle_sigse=
gv
> bailed out because garbage collection was in progress. This time I was
> unable to prevent the second SIGSEGV by resetting max-specpdl-size and
> max-lisp-eval-depth. I'm not sure what caused the second SIGSEGV, but it
> might have nothing to do with Cygwin.
>=20
> In the 64-bit case, however, the recovery from stack overflow never happe=
ned
> (i.e., the program never reached the siglongjmp). Here's a gdb session:
> [...]
> 1647 if (!getrlimit (RLIMIT_STACK, &rlim))
> (gdb)
> 1656 beg =3D stack_bottom;
> (gdb)
> 1657 end =3D stack_bottom + stack_direction * rlim.rlim_cur;
> (gdb)
> 1658 if (beg > end)
> (gdb)
> 1660 addr =3D (char *) siginfo->si_addr;
> (gdb)
> 1663 if (beg < addr && addr < end
> (gdb) p beg
> $1 =3D 0x82ca27 ""
> (gdb) p addr
> $2 =3D 0x33ff8 ""
I can't reproduce this. It works fine for me. For reference I attached
my simplified testcase again. It's basically the emacs SIGSEGV setup,
main triggers the stack overflow, the handler tries to write a file for
testing if that works from the handler, then it siglongjmps. The main
function tests if it can still fork, and then it repeats the action to
test if we're back to normal in terms of signal handling.
If it works (and it does for me) the output looks like this:
$ ./sigalt
command loop 1 before crash
command loop 1 after crash
In child
In parent
command loop 2 before crash
command loop 2 after crash
In child
In parent
On W8.1 for a standard GCC build of this testcase I get:
(gdb) p beg
$1 =3D 0x40ac3 <error: Cannot access memory at address 0x40ac3>
(gdb) p addr
$2 =3D 0x43848 <error: Cannot access memory at address 0x43848>
(gdb) p end
$3 =3D 0x23cac3 ""
(gdb) p/x rlim.rlim_cur
$5 =3D 0x1fc000
Check default stacksize:
)$ peflags -x ./sigalt
./sigalt: stack reserve size : 2097152 (0x200000) bytes
0x200000 - dead zone 4K - default W8.1 64 bit guardpagesize 3 * 4K =3D=3D
0x1fc000, the value rlim.rlim_cur returns. Looks good to me.
On W8.1 32 bit under WOW:
(gdb) p beg
$1 =3D 0x8fc33 ""
(gdb) p addr
$2 =3D 0x92d5c <error: Cannot access memory at address 0x92d5c>
(gdb) p end
$3 =3D 0x28cc33 ""
(gdb) p/x rlim.rlim_cur
$4 =3D 0x1fd000
$ peflags -x ./sigalt
./sigalt: stack reserve size : 2097152 (0x200000) bytes
0x200000 - dead zone 4K - default W8.1 32 bit guardpagesize 2 * 4K =3D=3D
0x1fd000.
On W7 32 bit native:
(gdb) p beg
$1 =3D 0x2ec43 "\376\356..."
(gdb) p addr
$2 =3D 0x32d6c ""
(gdb) p end
$3 =3D 0x22cc43 ""
(gdb) p rlim.rlim_cur
$4 =3D 2088960
(gdb) p/x rlim.rlim_cur
$5 =3D 0x1fe000
$ peflags -x ./sigalt
./sigalt: stack reserve size : 2097152 (0x200000) bytes
0x200000 - dead zone 4K - default W7 32 bit guardpagesize 1 * 4K =3D=3D
0x1fe000.
> Note that addr < beg, so we never reach the siglongjmp.
I have no explanation for this. What OS? What does rlim_cur contain?
What does peflags -x print for this executable?
And last but not least, what is emacs doing there? The stack should be
pretty much in a good shape when it's back to the main loop. The stack
is fully commited and has the default number of guardpages at the bottom,
as it is just short of the stack overflow.
For debugging purposes I also added a global variable called "tib" and a
memory info struct called "m" to the testcase which are initialized
right at the start of main. tib points to the start of the TEB (Thread
Environment Block, a Windows per-thread bookkeeping structure) of the
main thread. If you expand it right after it's fetched, you get
something along these lines:
(gdb) p *tib
$2 =3D {ExceptionList =3D 0x22cd78, StackBase =3D 0x230000, StackLimit =
=3D 0x20c000,
SubSystemTib =3D 0x0, {FiberData =3D 0x1e00, Version =3D 7680},
ArbitraryUserPointer =3D 0x0, Self =3D 0x7ffdf000}
Note the values of StackBase and StackLimit and compare with your beg and
end values. StackBase is the upper limit of the stack. It grows downward
from there. StackLimit is the lowest address as yet commited. It's not mu=
ch
yet as you can see, 0x230000-0x20c000 =3D=3D 0x24000 =3D=3D 144K. Since Cy=
gwin
executables have a default stack of 2 Megs, the allocation base of the stack
is probably at 0x30000. This can be checked by looking at m:
(gdb) p m
$1 =3D {BaseAddress =3D 0x22c000, AllocationBase =3D 0x30000, AllocationP=
rotect =3D 4,
RegionSize =3D 16384, State =3D 4096, Protect =3D 4, Type =3D 131072}
See the value of AllocationBase.
When you hit the breakpoint in handle_sigsegv, the output of tib should
look like this:
(gdb) p *tib
$2 =3D {ExceptionList =3D 0x22cd78, StackBase =3D 0x230000, StackLimit =
=3D 0x32000,
SubSystemTib =3D 0x0, {FiberData =3D 0x1e00, Version =3D 7680},
ArbitraryUserPointer =3D 0x0, Self =3D 0x7ffdf000}
Observe the value of StackLimit. For this output I ran the testcase on
W7 32 bit. It has a default guardpage of 4K. The new wrapper I wrote
in Cygwin restored the stack to its state rifght before the stack overflow
occured:
- At 0x30000 we have the 4K dead zone, which is always only reserved,
never commited.
- At 0x31000 the 4K guard page starts.
- Thus the StackLimit (the start of the commited region of the stack)
starts at 0x32000.
You can utilize tib and m for testing in emacs as well. Just do this:
#include <windows.h>
NT_TIB *tib;
MEMORY_BASIC_INFORMATION m;
[...]
in main:
/* Record (approximately) where the stack begins. */
stack_bottom =3D &stack_bottom_variable;
tib =3D (NT_TIB *) __readfsdword(PcTeb);
VirtualQuery (stack_bottom, &m, sizeof m);
It would be nice to find out why this happens to your emacs...
Thanks,
Corinna
--=20
Corinna Vinschen Please, send mails regarding Cygwin to
Cygwin Maintainer cygwin AT cygwin DOT com
Red Hat
--Wt10+cXOThorkX0z
Content-Type: text/plain; charset=utf-8
Content-Disposition: attachment; filename="sigalt.c"
#include <alloca.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <sys/fcntl.h>
#include <windows.h>
int stack_direction;
char *stack_bottom;
sigjmp_buf return_to_command_loop;
NT_TIB *tib;
MEMORY_BASIC_INFORMATION m;
/* Attempt to recover from SIGSEGV caused by C stack overflow. */
static void
handle_sigsegv (int sig, siginfo_t *siginfo, void *arg)
{
struct rlimit rlim;
int fp = open ("sigalt.out", O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (fp < 0)
perror ("open");
else
{
write (fp, "ping\n", 5);
close (fp);
}
if (!getrlimit (RLIMIT_STACK, &rlim))
{
enum { STACK_DANGER_ZONE = 32 * 1024 };
char *beg, *end, *addr;
beg = stack_bottom;
end = stack_bottom + stack_direction * rlim.rlim_cur;
if (beg > end)
addr = beg, beg = end, end = addr;
addr = (char *) siginfo->si_addr;
/* If we're somewhere on stack and too close to
one of its boundaries, most likely this is it. */
if (beg < addr && addr < end
&& (addr - beg < STACK_DANGER_ZONE
|| end - addr < STACK_DANGER_ZONE))
siglongjmp (return_to_command_loop, 1);
}
/* Otherwise we can't do anything with this. */
//abort ();
}
static int
init_sigsegv (void)
{
struct sigaction sa;
stack_t ss;
stack_direction = ((char *) &ss < stack_bottom) ? -1 : 1;
ss.ss_sp = malloc (SIGSTKSZ);
ss.ss_size = SIGSTKSZ;
ss.ss_flags = 0;
if (sigaltstack (&ss, NULL) < 0)
return 0;
sigfillset (&sa.sa_mask);
sa.sa_sigaction = handle_sigsegv;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1;
}
void foo ()
{
int buf[512];
foo ();
}
int
main ()
{
int status;
char stack_bottom_variable;
/* Record (approximately) where the stack begins. */
stack_bottom = &stack_bottom_variable;
tib = (NT_TIB *) __readfsdword(PcTeb);
VirtualQuery (stack_bottom, &m, sizeof m);
init_sigsegv ();
if (!sigsetjmp (return_to_command_loop, 1))
{
printf ("command loop 1 before crash\n");
foo ();
}
else
{
printf ("command loop 1 after crash\n");
switch (fork ())
{
case -1:
perror ("fork");
break;
case 0:
printf ("In child\n");
exit (0);
default:
wait (&status);
printf ("In parent\n");
break;
}
}
if (!sigsetjmp (return_to_command_loop, 1))
{
printf ("command loop 2 before crash\n");
foo ();
}
else
{
printf ("command loop 2 after crash\n");
switch (fork ())
{
case -1:
perror ("fork");
break;
case 0:
printf ("In child\n");
exit (0);
default:
wait (&status);
printf ("In parent\n");
break;
}
}
return 0;
}
--Wt10+cXOThorkX0z--
--QHp3Wr1K3N9pKO2V
Content-Type: application/pgp-signature
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAEBCAAGBQJVmlIWAAoJEPU2Bp2uRE+gRu0P/i3fiMI3bwgfJUu8xK2e133h
9tjLdIUsQl51oWPW8KcN8e6ZXS2ShTQOud9lAd8U7NPkVOoVa2DzrnRz+dGYu1R+
g4z7tY6S0oyUYdYhgK/UJIa+DzpS43GoIglbQXpfpmTNhSosxJZVj5BWZoLXOoEP
ZzrECJ/vK0/1ZuDxJ5/y2xpvIqkpVEMRDlfRgOYTf2M+5T5EoDl+tp98gyqa6zsj
Mnynt/qZuE/corh1gkFZuDnCTFGaInJKKRa5R54DITiWB7Kt9vTnSkkhRWxy2Bus
7vQyexwOccmBMpaNBNC3/lURoRpaDglJ+vy0YE6dIBoxTXMOqjQa9wQmauxeG94O
Hp7EU5zIplkBCkiKSrnbbnLNh/uOk1dAUp/pdam7zTpZ/H+vf3unsY/PCwujXFoy
hYHxy0TUOZVrY2CiR1jOkIyB7rdYiLaXLp6eCnZ4+X1Y9ByirfaAAToq7LMunyJb
oQADZrbwGtyWcspY/eX6gw8K40/Op2OlDYhKzJqxqLJ3OxY7tBC1xQD9OJ3wTajI
95Zx/DtvZ88AePVbItp7gQhaaoT9Ya10VOsMcbELXVz5GzVtA/Yd1FtesXBG2BK3
580e/eVh/uoFtouIr/J6U1tXP+urpjWnJr2c2FKQWcBQAamc30xvrFoO1hDJPChv
1L7sGt/H3+wfsN5Kyotn
=1cty
-----END PGP SIGNATURE-----
--QHp3Wr1K3N9pKO2V--
- Raw text -