|
From: Jeremy F. <je...@go...> - 2004-02-24 23:44:05
|
CVS commit by fitzhardinge:
Fix the use of brk. This change removes the requirement for the "real" brk
segment to be moved up to stage2's brk segment. Instead, Valgrind's
use of brk is simulated with mmap. In order to prevent any unwanted use
of the process brk segment, it also sets the RLIMIT_DATA to 0, which will
make brk always fail. glibc's malloc will use mmap to allocate if brk
fails. We try to intercept glibc's brk, but malloc seems to always use the
library-internal version. (The client's use of brk has always been simulated,
and is unaffected by this change.)
A coregrind/vg_glibc.c 1.1 [no copyright]
M +1 -0 coregrind/Makefile.am 1.67
M +0 -1 coregrind/stage1.c 1.7
M +4 -30 coregrind/ume.c 1.9
M +1 -2 coregrind/ume.h 1.5
M +2 -0 coregrind/vg_include.h 1.182
M +11 -1 coregrind/vg_main.c 1.146
M +70 -28 coregrind/vg_mylibc.c 1.70
M +20 -6 coregrind/vg_syscalls.c 1.89
M +11 -1 include/vg_kerneliface.h 1.14
--- valgrind/coregrind/Makefile.am #1.66:1.67
@@ -51,4 +51,5 @@
vg_execontext.c \
vg_from_ucode.c \
+ vg_glibc.c \
vg_hashtable.c \
vg_helpers.S \
--- valgrind/coregrind/stage1.c #1.6:1.7
@@ -163,5 +163,4 @@ static void hoops(void)
*/
info.map_base = 0xb0000000;
- info.setbrk = 1; /* ask do_exec to move the brk-base */
info.argv = NULL;
--- valgrind/coregrind/ume.c #1.8:1.9
@@ -91,4 +91,5 @@
#include "ume.h"
+#include "vg_include.h"
static int padfile = -1;
@@ -310,5 +311,5 @@ struct elfinfo *readelf(int fd, const ch
/* Map an ELF file. Returns the brk address. */
-ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base, int setbrk)
+ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base)
{
int i;
@@ -331,31 +332,4 @@ ESZ(Addr) mapelf(struct elfinfo *e, ESZ(
}
- if (setbrk) {
- /* sneaking up on the brk limit works better than actually
- jumping directly there. Unfortunately, setting the brk is
- tested against the datasize rlimit, even though we're not
- actually using any memory. */
- char *b = sbrk(0);
- char *initb = (char *)PGROUNDUP(b);
-
- while(b < (char *)elfbrk) {
- unsigned delta = (char *)elfbrk - b;
- static const unsigned limit = 256*1024*1024;
- char *bb;
-
- if (delta > limit)
- delta = limit;
- //printf("elfbrk=%p b=%p delta=%u\n", elfbrk, b, delta);
- bb = sbrk(delta);
- if (bb != b) {
- fprintf(stderr, "sbrk failed while adjusting brk base: "
- "perhaps we hit the datasize ulimit?\n");
- return 0;
- }
- b += delta;
- }
- munmap(initb, (char *)PGROUNDDN(elfbrk)-initb);
- }
-
for(i = 0; i < e->e.e_phnum; i++) {
ESZ(Phdr) *ph = &e->p[i];
@@ -509,5 +483,5 @@ static int load_ELF(char *hdr, int len,
}
- info->brkbase = mapelf(e, 0, info->setbrk); /* map the executable */
+ info->brkbase = mapelf(e, 0); /* map the executable */
if (info->brkbase == 0)
@@ -529,5 +503,5 @@ static int load_ELF(char *hdr, int len,
baseoff = base - interp_addr;
- mapelf(interp, (ESZ(Addr))baseoff, 0);
+ mapelf(interp, (ESZ(Addr))baseoff);
close(interp->fd);
--- valgrind/coregrind/ume.h #1.4:1.5
@@ -44,5 +44,4 @@ typedef ESZ(Addr) addr_t;
struct exeinfo
{
- int setbrk; /* INPUT: if true, set the brk segment base */
addr_t map_base; /* INPUT: if non-zero, base address of mappings */
@@ -83,5 +82,5 @@ struct elfinfo
struct elfinfo *readelf(int fd, const char *filename);
-ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base, int setbrk);
+ESZ(Addr) mapelf(struct elfinfo *e, ESZ(Addr) base);
struct ume_auxv
--- valgrind/coregrind/vg_include.h #1.181:1.182
@@ -1360,4 +1360,6 @@ extern Addr VG_(valgrind_mmap_end);
extern Addr VG_(valgrind_end);
+extern vki_rlimit VG_(client_rlimit_data); /* client's original rlimit data */
+
/* stage1 executable file descriptor */
extern Int VG_(vgexecfd);
--- valgrind/coregrind/vg_main.c #1.145:1.146
@@ -106,4 +106,6 @@ Addr VG_(valgrind_mmap_end); /* valgrin
Addr VG_(valgrind_end);
+vki_rlimit VG_(client_rlimit_data);
+
/* This is set early to indicate whether this CPU has the
SSE/fxsave/fxrestor features. */
@@ -1365,5 +1367,4 @@ static void load_client(char* cl_argv[],
info->map_base = VG_(client_mapbase);
- info->setbrk = False;
info->exe_base = VG_(client_base);
@@ -2665,4 +2666,5 @@ int main(int argc, char **argv)
UInt * client_auxv;
VgSchedReturnCode src;
+ vki_rlimit zero = { 0, 0 };
//============================================================
@@ -2672,4 +2674,12 @@ int main(int argc, char **argv)
//============================================================
+ // Get the current process datasize rlimit, and set it to zero.
+ // This prevents any internal uses of brk() from having any effect.
+ // We remember the old value so we can restore it on exec, so that
+ // child processes will have a reasonable brk value.
+ VG_(getrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
+ zero.rlim_max = VG_(client_rlimit_data).rlim_max;
+ VG_(setrlimit)(VKI_RLIMIT_DATA, &zero);
+
//--------------------------------------------------------------
// Check we were launched by stage1
--- valgrind/coregrind/vg_mylibc.c #1.69:1.70
@@ -245,4 +245,23 @@ Int VG_(gettid)(void)
------------------------------------------------------------------ */
+static Int munmap_inner(void *start, UInt length)
+{
+ return VG_(do_syscall)(__NR_munmap, (UInt)start, (UInt)length );
+}
+
+static Addr mmap_inner(void *start, UInt length, UInt prot, UInt flags, UInt fd, UInt offset)
+{
+ UInt args[6];
+
+ args[0] = (UInt)start;
+ args[1] = length;
+ args[2] = prot;
+ args[3] = flags & ~(VKI_MAP_NOSYMS|VKI_MAP_CLIENT);
+ args[4] = fd;
+ args[5] = offset;
+
+ return VG_(do_syscall)(__NR_mmap, (UInt)(&(args[0])) );
+}
+
/* Returns -1 on failure. */
void* VG_(mmap)( void* start, UInt length,
@@ -250,5 +269,4 @@ void* VG_(mmap)( void* start, UInt lengt
{
Addr res;
- UInt args[6];
if (!(flags & VKI_MAP_FIXED)) {
@@ -260,11 +278,5 @@ void* VG_(mmap)( void* start, UInt lengt
}
- args[0] = (UInt)start;
- args[1] = length;
- args[2] = prot;
- args[3] = flags & ~(VKI_MAP_NOSYMS|VKI_MAP_CLIENT);
- args[4] = fd;
- args[5] = offset;
- res = VG_(do_syscall)(__NR_mmap, (UInt)(&(args[0])) );
+ res = mmap_inner(start, length, prot, flags, fd, offset);
if (!VG_(is_kerror)(res)) {
@@ -306,5 +318,5 @@ void* VG_(mmap)( void* start, UInt lengt
Int VG_(munmap)( void* start, Int length )
{
- Int res = VG_(do_syscall)(__NR_munmap, (UInt)start, (UInt)length );
+ Int res = munmap_inner(start, length);
if (!VG_(is_kerror)(res))
VG_(unmap_range)((Addr)start, length);
@@ -373,9 +385,47 @@ Int VG_(nanosleep)( const struct vki_tim
}
+extern Char _end;
+Char *VG_(curbrk) = NULL;
+extern void *__curbrk; /* in glibc */
+
void* VG_(brk) ( void* end_data_segment )
{
- Int res;
- res = VG_(do_syscall)(__NR_brk, (UInt)end_data_segment);
- return (void*)( VG_(is_kerror)(res) ? -1 : res );
+ Addr end;
+ Addr brkpage;
+ Addr endpage;
+
+ if (VG_(curbrk) == NULL) {
+ VG_(curbrk) = &_end;
+ __curbrk = (void *)VG_(curbrk);
+ }
+
+ end = (Addr)end_data_segment;
+ brkpage = PGROUNDUP(VG_(curbrk));
+ endpage = PGROUNDUP(end);
+
+ if (0 && VG_(curbrk) != __curbrk)
+ VG_(printf)("__curbrk changed unexpectedly: VG_(curbrk)=%p, __curbrk=%p\n",
+ VG_(curbrk), __curbrk);
+
+ if (0)
+ VG_(printf)("brk(end_data_segment=%p); brkpage=%p endpage=%p end=%p curbrk=%p &_end=%p\n",
+ end_data_segment, brkpage, endpage, end, VG_(curbrk), &_end);
+
+ if (endpage < (Addr)&_end) {
+ __curbrk = (void *)VG_(curbrk);
+ return (void *)VG_(curbrk);
+ }
+
+ if (brkpage != endpage) {
+ if (brkpage > endpage)
+ munmap_inner((void *)brkpage, brkpage-endpage);
+ else
+ mmap_inner((void *)brkpage, endpage-brkpage,
+ VKI_PROT_READ|VKI_PROT_WRITE|VKI_PROT_EXEC,
+ VKI_MAP_FIXED|VKI_MAP_PRIVATE|VKI_MAP_ANONYMOUS, -1, 0);
+ }
+ VG_(curbrk) = (Char *)__curbrk = end_data_segment;
+
+ return end_data_segment;
}
@@ -1533,4 +1583,7 @@ Int VG_(system) ( Char* cmd )
Char* argv[4];
+ /* restore the DATA rlimit for the child */
+ VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
+
if (envp == NULL) {
Int i;
@@ -1617,22 +1670,11 @@ void* VG_(get_memory_from_mmap) ( Int nB
static UInt tot_alloc = 0;
void* p;
-
-#if 0
- p = VG_(mmap)( (void *)VG_(valgrind_base), nBytes,
- VKI_PROT_READ | VKI_PROT_WRITE | VKI_PROT_EXEC,
- VKI_MAP_PRIVATE | VKI_MAP_ANONYMOUS, -1, 0 );
-#else
- /* use brk, because it will definitely be in the valgrind address space */
- {
Char *b = VG_(brk)(0);
p = (void *)PGROUNDUP(b);
-
b = VG_(brk)(p + PGROUNDUP(nBytes));
if (b != (p + PGROUNDUP(nBytes)))
p = (void *)-1;
- }
-#endif
if (p != ((void*)(-1))) {
--- valgrind/coregrind/vg_syscalls.c #1.88:1.89
@@ -1995,4 +1995,7 @@ PRE(execve)
}
+ /* restore the DATA rlimit for the child */
+ VG_(setrlimit)(VKI_RLIMIT_DATA, &VG_(client_rlimit_data));
+
res = VG_(do_syscall)(__NR_execve, arg1, arg2, arg3);
@@ -2483,14 +2486,20 @@ PRE(getrlimit)
MAYBE_PRINTF("getrlimit ( %d, %p )\n", arg1,arg2);
SYSCALL_TRACK( pre_mem_write, tid, "getrlimit(rlim)", arg2,
- sizeof(struct rlimit) );
+ sizeof(struct vki_rlimit) );
}
POST(getrlimit)
{
- if (res == 0)
- VG_TRACK( post_mem_write, arg2, sizeof(struct rlimit) );
+ VG_TRACK( post_mem_write, arg2, sizeof(struct vki_rlimit) );
- if (res == 0 && arg1 == VKI_RLIMIT_NOFILE)
- ((struct rlimit *)arg2)->rlim_cur = VG_(max_fd);
+ switch(arg1) {
+ case VKI_RLIMIT_NOFILE:
+ ((vki_rlimit *)arg2)->rlim_cur = VG_(max_fd);
+ break;
+
+ case VKI_RLIMIT_DATA:
+ *((vki_rlimit *)arg2) = VG_(client_rlimit_data);
+ break;
+ }
}
@@ -4246,5 +4255,10 @@ PRE(setrlimit)
MAYBE_PRINTF("setrlimit ( %d, %p )\n", arg1,arg2);
SYSCALL_TRACK( pre_mem_read, tid, "setrlimit(rlim)",
- arg2, sizeof(struct rlimit) );
+ arg2, sizeof(struct vki_rlimit) );
+
+ if (arg1 == VKI_RLIMIT_DATA) {
+ VG_(client_rlimit_data) = *(vki_rlimit *)arg2;
+ res = 0;
+ }
}
--- valgrind/include/vg_kerneliface.h #1.13:1.14
@@ -699,5 +699,15 @@ typedef struct vki_rlimit {
} vki_rlimit;
-#define VKI_RLIMIT_NOFILE 7
+#define VKI_RLIMIT_CPU 0 /* CPU time in ms */
+#define VKI_RLIMIT_FSIZE 1 /* Maximum filesize */
+#define VKI_RLIMIT_DATA 2 /* max data size */
+#define VKI_RLIMIT_STACK 3 /* max stack size */
+#define VKI_RLIMIT_CORE 4 /* max core file size */
+#define VKI_RLIMIT_RSS 5 /* max resident set size */
+#define VKI_RLIMIT_NPROC 6 /* max number of processes */
+#define VKI_RLIMIT_NOFILE 7 /* max number of open files */
+#define VKI_RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */
+#define VKI_RLIMIT_AS 9 /* address space limit */
+#define VKI_RLIMIT_LOCKS 10 /* maximum file locks held */
/* Socket stuff. */
|