ftmemsim-valgrind/coregrind/m_clientstate.c
Philippe Waroquiers 3168fa1e2a fix 321960 pthread_create() then alloca() causing invalid stack write errors
Problem created by a discrepancy between the initial main stack
anon segment, and the main stack registered in m_stacks.c

Looking at some tracing; we see that there are two pages of stack:
--9078:2:main       tell tool about 0ffefff000-0fff000fff rw-
The stack between the base and the current sp is marked as not accessible:
--9078:2:main       mark stack inaccessible 0ffefff000-0fff0004bf

This is matching the aspacemgr view:
--9078:1:aspacem   22: RSVN 0ffe801000-0ffeffefff 8380416 ----- SmUpper
--9078:1:aspacem   23: anon 0ffefff000-0fff000fff    8192 rw---
(all the above is normal/as expected)


However, the main stack is registered in m_stacks.c as having only one page:
--9078:2:stacks     register 0xFFF000000-0xFFF000FFF as stack 0

When the main stack is grown, m_stacks.c is informed by m_signals.c
that the stack is grown. This is done by trapping the signal 11
when a not mapped page is accessed.
However, the 2nd page does not cause a signal (as it is mapped).
So, m_stacks.c still believes the main has one page stack.
This then gives problems in the tracking of the SP and current_stack
in m_stacks.c.

Only one page was registered for the main stack, as the registration
was done with values computed before possibly adding a page
needed for the ABI redzone.

The fix is to properly register the main stack with the size of
the stack segment, once all aspects have been taken into account.
With the fix, the stack is registered as:
--31501:2:stacks     register 0xFFEFFF000-0xFFF000FFF as stack 0

  Another possible fix would be to always register the main stack with the
  full size of the aspacemgr stack segment (i.e. the anon+RSVN above)
  (idea is that this is similar to non main threads, for which the
  full thread stack is registered from the beginning, even if not fully
  used yet).
  The first fix was preferred, assuming it is better to keep registering
  the main stack "physical" size (and not its maximal size).


Test memcheck/tests/thread_alloca added, based on reproducer
done by Daniel Stodden.
The bug might be triggered or not depending on the initial value
of the SP, which is influenced by the size of the "env".
So, the test execs itself, growing each time the environment.
This has given a reasonable chance/way to reproduce the bug on Ubuntu 12
and on a Debian 6.
(tested on amd64/Ubuntu 12 and Debian 6
           x86/fedora12
           ppc64/fedora18

Note that while investigating this bug, another strange thing was seen:
thread stacks are registered in m_stacks.c but are never unregistered.
It is not very clear that it is needed or not to unregister them:
thread stack segments are not freed when a thread terminates :
when a thread slot is re-used, its thread stack will also be re-used.
(Is that good for address space mgt ? A process that has created many
temporary threads will have the thread stacks lost forever ???).

 



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@13467
2013-07-21 16:04:05 +00:00

114 lines
4.3 KiB
C

/*--------------------------------------------------------------------*/
/*--- A home for miscellaneous bits of information which pertain ---*/
/*--- to the client's state. ---*/
/*--- m_clientstate.c ---*/
/*--------------------------------------------------------------------*/
/*
This file is part of Valgrind, a dynamic binary instrumentation
framework.
Copyright (C) 2000-2012 Julian Seward
jseward@acm.org
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program 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
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307, USA.
The GNU General Public License is contained in the file COPYING.
*/
#include "pub_core_basics.h"
#include "pub_core_vki.h"
#include "pub_core_xarray.h"
#include "pub_core_clientstate.h"
/*-----------------------------------------------------------------*/
/*--- ---*/
/*--- Basic globals about the address space. ---*/
/*--- ---*/
/*-----------------------------------------------------------------*/
/* Client address space, lowest to highest (see top of ume.c) */
// TODO: get rid of as many of these as possible.
/* ***Initial*** lowest address of the stack segment of the main thread.
The main stack will grow if needed but VG_(clstk_base) will
not be changed according to the growth. */
Addr VG_(clstk_base) = 0;
/* Initial highest address of the stack segment of the main thread. */
Addr VG_(clstk_end) = 0;
UWord VG_(clstk_id) = 0;
/* linux only: where is the client auxv ? */
/* This is set up as part of setup_client_stack in initimg-linux.c. */
UWord* VG_(client_auxv) = NULL;
Addr VG_(brk_base) = 0; /* start of brk */
Addr VG_(brk_limit) = 0; /* current brk */
/* A fd which refers to the client executable. */
Int VG_(cl_exec_fd) = -1;
/* A fd which refers to the fake /proc/<pid>/cmdline in /tmp. */
Int VG_(cl_cmdline_fd) = -1;
/* A fd which refers to the fake /proc/<pid>/auxv in /tmp. */
Int VG_(cl_auxv_fd) = -1;
// Command line pieces, after they have been extracted from argv in
// m_main.main(). The payload vectors are allocated in VG_AR_TOOL
// (the default arena). They are never freed.
/* Args for the client. */
XArray* /* of HChar* */ VG_(args_for_client) = NULL;
/* Args for V (augments, then those from the launcher). */
XArray* /* of HChar* */ VG_(args_for_valgrind) = NULL;
/* How many of the above not to pass on at execve time? */
Int VG_(args_for_valgrind_noexecpass) = 0;
/* The name of the client executable, as specified on the command
line. */
const HChar* VG_(args_the_exename) = NULL;
// Client's original rlimit data and rlimit stack
struct vki_rlimit VG_(client_rlimit_data);
struct vki_rlimit VG_(client_rlimit_stack);
// Name of the launcher, as extracted from VALGRIND_LAUNCHER at
// startup.
HChar* VG_(name_of_launcher) = NULL;
/* Application-visible file descriptor limits */
Int VG_(fd_soft_limit) = -1;
Int VG_(fd_hard_limit) = -1;
/* Useful addresses extracted from the client */
/* Where is the __libc_freeres_wrapper routine we made? */
Addr VG_(client___libc_freeres_wrapper) = 0;
/* x86-linux only: where is glibc's _dl_sysinfo_int80 function?
Finding it isn't essential, but knowing where it is does sometimes
help produce better back traces. See big comment in
VG_(get_StackTrace) in m_stacktrace.c for further info. */
Addr VG_(client__dl_sysinfo_int80) = 0;
/*--------------------------------------------------------------------*/
/*--- end ---*/
/*--------------------------------------------------------------------*/