2008-01-09 Jakub Jelinek <jakub@redhat.com> * sysdeps/unix/sysv/linux/i386/makecontext.S (__makecontext): Avoid clobbering memory at or above uc_stack.ss_sp + uc_stack.ss_size. * stdlib/Makefile: Add rules to build and run tst-makecontext2. * stdlib/tst-makecontext2.c: New test. 2007-12-03 Ulrich Drepper <drepper@redhat.com> [BZ #5435] * sysdeps/unix/sysv/linux/i386/makecontext.S: Align stack. * stdlib/tst-setcontext.c: Catch the case where the links gets messed up and we do not reach main again. --- libc/sysdeps/unix/sysv/linux/i386/makecontext.S 26 May 2005 14:30:47 -0000 1.7 +++ libc/sysdeps/unix/sysv/linux/i386/makecontext.S 9 Jan 2008 19:35:15 -0000 1.9 @@ -35,24 +35,32 @@ movl %ecx, oEIP(%eax) addl oSS_SIZE(%eax), %edx - /* Put the next context on the new stack (from the uc_link - element). */ - movl oLINK(%eax), %ecx - movl %ecx, -4(%edx) - /* Remember the number of parameters for the exit handler since it has to remove them. We store the number in the EBX register which the function we will call must preserve. */ movl 12(%esp), %ecx movl %ecx, oEBX(%eax) - /* Make room on the new stack for the parameters. */ + /* Make room on the new stack for the parameters. + Room for the arguments, return address (== L(exitcode)) and + oLINK pointer is needed. One of the pointer sizes is subtracted + after aligning the stack. */ negl %ecx - leal -8(%edx,%ecx,4), %edx + leal -4(%edx,%ecx,4), %edx negl %ecx + + /* Align the stack. */ + andl $0xfffffff0, %edx + subl $4, %edx + /* Store the future stack pointer. */ movl %edx, oESP(%eax) + /* Put the next context on the new stack (from the uc_link + element). */ + movl oLINK(%eax), %eax + movl %eax, 4(%edx,%ecx,4) + /* Copy all the parameters. */ jecxz 2f 1: movl 12(%esp,%ecx,4), %eax --- libc/stdlib/tst-setcontext.c 3 Mar 2006 11:51:31 -0000 1.8 +++ libc/stdlib/tst-setcontext.c 3 Dec 2007 04:11:25 -0000 1.9 @@ -123,9 +123,26 @@ test_stack(volatile int a, volatile int volatile int global; + +static int back_in_main; + + +static void +check_called (void) +{ + if (back_in_main == 0) + { + puts ("program did no reach main again"); + _exit (1); + } +} + + int main (void) { + atexit (check_called); + char st1[32768]; puts ("making contexts"); @@ -185,6 +202,7 @@ main (void) exit (1); } puts ("back at main program"); + back_in_main = 1; if (was_in_f1 == 0) { --- libc/stdlib/Makefile 5 Oct 2007 06:50:27 -0000 1.119 +++ libc/stdlib/Makefile 9 Jan 2008 19:34:59 -0000 1.120 @@ -68,7 +68,7 @@ tests := tst-strtol tst-strtod testmb t tst-limits tst-rand48 bug-strtod tst-setcontext \ test-a64l tst-qsort tst-system testmb2 bug-strtod2 \ tst-atof1 tst-atof2 tst-strtod2 tst-strtod3 tst-rand48-2 \ - tst-makecontext tst-strtod4 tst-strtod5 + tst-makecontext tst-strtod4 tst-strtod5 tst-makecontext2 include ../Makeconfig @@ -110,6 +110,7 @@ endif CFLAGS-tst-bsearch.c = $(stack-align-test-flags) CFLAGS-tst-qsort.c = $(stack-align-test-flags) +CFLAGS-tst-makecontext2.c = $(stack-align-test-flags) include ../Rules --- libc/stdlib/tst-makecontext2.c 1 Jan 1970 00:00:00 -0000 +++ libc/stdlib/tst-makecontext2.c 9 Jan 2008 19:34:46 -0000 1.1 @@ -0,0 +1,80 @@ +/* Copyright (C) 2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ucontext.h> +#include <tst-stack-align.h> + +ucontext_t ucp, ucp2; +char st1[262144] __attribute__((aligned (16))); + +void +cf (int i, int j) +{ + if (i != 78 || j != 274) + { + printf ("i %d j %d\n", i, j); + exit (1); + } + else if (TEST_STACK_ALIGN ()) + { + puts ("insufficiently aligned stack"); + exit (2); + } +} + +int +do_test (void) +{ + for (size_t j = 32; j < 64; j += sizeof (long)) + { + if (getcontext (&ucp) != 0) + { + if (errno == ENOSYS) + { + puts ("context handling not supported"); + return 0; + } + + puts ("getcontext failed"); + return 1; + } + ucp.uc_link = &ucp2; + ucp.uc_stack.ss_sp = st1; + ucp.uc_stack.ss_size = sizeof (st1) - j; + memset (&st1[sizeof (st1) - j], 0x55, j); + makecontext (&ucp, (void (*) (void)) cf, 2, 78, 274); + if (swapcontext (&ucp2, &ucp) != 0) + { + puts ("setcontext failed"); + return 1; + } + + for (size_t i = j; i > 0; i--) + if (st1[sizeof (st1) - j + i - 1] != 0x55) + { printf ("fail %zd %zd\n", i, j); break; } + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c"