Fix safe_fd exhaustion in fork chain caused by non closing of shared_mem_fd

Patch that fixes the problem reported by Christian Borntraeger.
The problem was created by keeping the shared memory mapped file opened
without reason till the process does an exec.
In case of a chain of forked processes (without exec), the range of safe_fd
reserved for Valgrind own usage becomes exhausted.

* coregrind/m_gdbserver/remote-utils.c :
   do not VG_(safe_fd) shared_mem_fd (as it is now closed directly)
   close shared_mem_fd once file is mmap-ed and written.
* gdbserver_tests/nlfork_chain.stderr.exp,nlfork_chain.vgtest,
               fork_chain.c,nlfork_chain.stdout.exp:
     new files
* gdbserver_tests/Makefile.am:
  modified for new nlfork_chain test

(patch from #214909 c 103,
Philippe Waroquiers, philippe.waroquiers@skynet.be)



git-svn-id: svn://svn.valgrind.org/valgrind/trunk@11818
This commit is contained in:
Julian Seward 2011-06-15 21:30:55 +00:00
parent 15107e7bdb
commit 196c5d876c
6 changed files with 92 additions and 5 deletions

View File

@ -279,10 +279,6 @@ void remote_open (char *name)
fatal("error writing %d bytes to shared mem %s\n",
(int) sizeof(VgdbShared), shared_mem);
}
shared_mem_fd = VG_(safe_fd)(shared_mem_fd);
if (shared_mem_fd == -1) {
fatal("safe_fd for vgdb shared_mem %s failed\n", shared_mem);
}
{
SysRes res = VG_(am_shared_mmap_file_float_valgrind)
(sizeof(VgdbShared), VKI_PROT_READ|VKI_PROT_WRITE,
@ -295,6 +291,7 @@ void remote_open (char *name)
addr_shared = sr_Res (res);
}
shared = (VgdbShared*) addr_shared;
VG_(close) (shared_mem_fd);
}
/* we open the read side FIFO in non blocking mode

View File

@ -72,10 +72,14 @@ EXTRA_DIST = \
nlcontrolc.stderr.exp \
nlcontrolc.stdinB.gdb \
nlcontrolc.stdoutB.exp \
nlcontrolc.vgtest
nlcontrolc.vgtest \
nlfork_chain.stderr.exp \
nlfork_chain.stdout.exp \
nlfork_chain.vgtest
check_PROGRAMS = \
clean_after_fork \
fork_chain \
sleepers \
t \
watchpoints

View File

@ -0,0 +1,37 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/wait.h>
void fork_chain(int level)
{
int pid;
printf ("forking level %d\n", level);
fflush (stdout);
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
}
if (pid == 0) {
if (level > 0) {
fork_chain (level - 1);
}
} else {
int ret;
int status;
while((ret = waitpid(pid, &status, 0)) != pid) {
if (errno != EINTR) {
perror("waitpid");
exit(1);
}
}
}
}
int main()
{
fork_chain (20);
return 0;
}

View File

@ -0,0 +1,24 @@
Nulgrind, the minimal Valgrind tool

View File

@ -0,0 +1,21 @@
forking level 20
forking level 19
forking level 18
forking level 17
forking level 16
forking level 15
forking level 14
forking level 13
forking level 12
forking level 11
forking level 10
forking level 9
forking level 8
forking level 7
forking level 6
forking level 5
forking level 4
forking level 3
forking level 2
forking level 1
forking level 0

View File

@ -0,0 +1,4 @@
# test that gdbserver properly cleans up its resources in a chain
# of forked processes.
prog: fork_chain
vgopts: --tool=none --vgdb=yes --trace-children=yes --vgdb-prefix=./vgdb-prefix-nlfork_chain