Add a facility for tracking open file descriptors. Information about

still open files is dumped out exit.  Enabled using the --track-fds
switch.


git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2031
This commit is contained in:
Robert Walsh 2003-11-17 17:45:00 +00:00
parent d38eac1bf6
commit f9ea43d896
37 changed files with 1319 additions and 14 deletions

View File

@ -8,6 +8,15 @@ noinst_SCRIPTS = filter_stderr
EXTRA_DIST = $(noinst_SCRIPTS) \
erringfds.stderr.exp erringfds.stdout.exp erringfds.vgtest \
fdleak_cmsg.stderr.exp fdleak_cmsg.vgtest \
fdleak_creat.stderr.exp fdleak_creat.vgtest \
fdleak_dup.stderr.exp fdleak_dup.vgtest \
fdleak_dup2.stderr.exp fdleak_dup2.vgtest \
fdleak_fcntl.stderr.exp fdleak_fcntl.vgtest \
fdleak_ipv4.stderr.exp fdleak_ipv4.stdout.exp fdleak_ipv4.vgtest \
fdleak_open.stderr.exp fdleak_open.vgtest \
fdleak_pipe.stderr.exp fdleak_pipe.vgtest \
fdleak_socketpair.stderr.exp fdleak_socketpair.vgtest \
pth_atfork1.stderr.exp pth_atfork1.stdout.exp pth_atfork1.vgtest \
pth_cancel2.stderr.exp pth_cancel2.vgtest \
pth_cvsimple.stderr.exp pth_cvsimple.stdout.exp pth_cvsimple.vgtest \
@ -21,7 +30,9 @@ EXTRA_DIST = $(noinst_SCRIPTS) \
vgprintf.stderr.exp vgprintf.stdout.exp vgprintf.vgtest
check_PROGRAMS = \
erringfds sigkill res_search \
erringfds fdleak_cmsg fdleak_creat fdleak_dup fdleak_dup2 \
fdleak_fcntl fdleak_ipv4 fdleak_open fdleak_pipe \
fdleak_socketpair sigkill res_search \
pth_atfork1 pth_cancel2 pth_cvsimple pth_empty \
pth_exit pth_mutexspeed pth_once \
vgprintf
@ -31,8 +42,17 @@ AM_CXXFLAGS = $(AM_CFLAGS)
# C ones
erringfds_SOURCES = erringfds.c
sigkill_SOURCES = sigkill.c
vgprintf_SOURCES = vgprintf.c
fdleak_cmsg_SOURCES = fdleak_cmsg.c
fdleak_creat_SOURCES = fdleak_creat.c
fdleak_dup_SOURCES = fdleak_dup.c
fdleak_dup2_SOURCES = fdleak_dup2.c
fdleak_fcntl_SOURCES = fdleak_fcntl.c
fdleak_ipv4_SOURCES = fdleak_ipv4.c
fdleak_open_SOURCES = fdleak_open.c
fdleak_pipe_SOURCES = fdleak_pipe.c
fdleak_socketpair_SOURCES = fdleak_socketpair.c
sigkill_SOURCES = sigkill.c
vgprintf_SOURCES = vgprintf.c
# Pthread ones
pth_atfork1_SOURCES = pth_atfork1.c

View File

@ -0,0 +1,182 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
char filea[24];
char fileb[24];
char sock[24];
void
server ()
{
int s, fd1, fd2;
struct sockaddr_un addr;
fd1 = open(filea, O_RDWR | O_CREAT | O_TRUNC, 0750);
if(fd1 == -1) {
perror("open");
exit(1);
}
fd2 = open(fileb, O_RDWR | O_CREAT | O_TRUNC, 0750);
if(fd2 == -1) {
perror("open");
exit(1);
}
s = socket(PF_UNIX, SOCK_STREAM, 0);
if(s == -1) {
perror("socket");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
sprintf(addr.sun_path, sock);
unlink(addr.sun_path);
if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind");
exit(1);
}
if(listen(s, 5) == -1) {
perror("listen");
exit(1);
}
{
int x;
int baddrsize = 0;
struct sockaddr_un baddr;
struct msghdr msg = {NULL, 0, NULL, 0, 0, 0, 0};
struct cmsghdr *cmsg;
char buf[CMSG_SPACE(sizeof(int) * 2)];
struct iovec iov[1];
memset(&baddr, 0, sizeof(baddr));
x = accept(s, (struct sockaddr *)&baddr, &baddrsize);
if(x == -1) {
perror("accept");
exit(1);
}
msg.msg_control = buf;
msg.msg_controllen = sizeof(buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int) * 2);
((int *)CMSG_DATA(cmsg))[0] = fd1;
((int *)CMSG_DATA(cmsg))[1] = fd2;
iov[0].iov_base = "hello";
iov[0].iov_len = 6;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if(sendmsg(x, &msg, 0) == -1) {
perror("sendmsg");
exit(1);
}
}
}
void
client ()
{
int s, fd1 = -1, fd2 = -1, size, count = 0, ret;
struct sockaddr_un addr;
struct iovec iov[1];
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int) * 2)];
} control_un;
struct msghdr msg = { NULL, 0, iov, 1, control_un.control,
sizeof(control_un), 0 };
struct cmsghdr *cmsg = &control_un.cm;
char buf[1024];
iov[0].iov_base = buf;
iov[0].iov_len = sizeof(buf);
s = socket(PF_UNIX, SOCK_STREAM, 0);
if(s == -1) {
perror("socket");
exit(1);
}
addr.sun_family = AF_UNIX;
sprintf(addr.sun_path, sock);
do {
count++;
ret = connect(s, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) sleep(1);
} while (count < 10 && ret == -1);
if(ret == -1) {
perror("connect");
exit(1);
}
if((size = recvmsg(s, &msg, 0)) == -1) {
perror("recvmsg");
exit(1);
}
cmsg = CMSG_FIRSTHDR(&msg);
while(cmsg) {
if(cmsg->cmsg_level == SOL_SOCKET &&
cmsg->cmsg_type == SCM_RIGHTS &&
cmsg->cmsg_len == CMSG_LEN(sizeof(int) * 2)) {
fd1 = ((int *)CMSG_DATA(cmsg))[0];
fd2 = ((int *)CMSG_DATA(cmsg))[1];
}
cmsg = CMSG_NXTHDR(&msg, cmsg);
}
if(fd1 != -1) write(fd1, "Yeah 1\n", 8);
if(fd2 != -1) write(fd2, "Yeah 2\n", 8);
}
int
main (int argc, char **argv)
{
int pid, status;
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
pid = getpid();
sprintf(filea, "/tmp/data1.%d", pid);
sprintf(fileb, "/tmp/data2.%d", pid);
sprintf(sock, "/tmp/sock.%d", pid);
if((pid = fork()) == 0) {
server();
return 0;
}
client();
wait(&status);
unlink(filea);
unlink(fileb);
unlink(sock);
return 0;
}

View File

@ -0,0 +1,61 @@
FILE DESCRIPTORS: 8 open at exit.
Open AF_UNIX socket .: /tmp/sock
at 0x........: __libc_accept (...libc...)
by 0x........: main (fdleak_cmsg.c:170)
Open AF_UNIX socket .: /tmp/sock
at 0x........: __socket (in /...libc...)
by 0x........: main (fdleak_cmsg.c:170)
Open file descriptor .: /tmp/data2
at 0x........: __libc_open (...libc...)
by 0x........: main (fdleak_cmsg.c:170)
Open file descriptor .: /tmp/data1
at 0x........: __libc_open (...libc...)
by 0x........: main (fdleak_cmsg.c:170)
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
FILE DESCRIPTORS: 7 open at exit.
Open file descriptor .: /tmp/data2
at 0x........: __libc_recvmsg (...libc...)
by 0x........: main (fdleak_cmsg.c:174)
Open file descriptor .: /tmp/data1
at 0x........: __libc_recvmsg (...libc...)
by 0x........: main (fdleak_cmsg.c:174)
Open AF_UNIX socket .: <unknown>
at 0x........: __socket (in /...libc...)
by 0x........: main (fdleak_cmsg.c:174)
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1,3 @@
prog: fdleak_cmsg
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

View File

@ -0,0 +1,21 @@
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int
main (int argc, char **argv)
{
char filename[24];
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
sprintf(filename, "/tmp/file.%d\n", getpid());
creat(filename, 0);
unlink(filename);
return 0;
}

View File

@ -0,0 +1,23 @@
FILE DESCRIPTORS: 5 open at exit.
Open file descriptor .: /tmp/file
at 0x........: __libc_creat (...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1,3 @@
prog: fdleak_creat
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

View File

@ -0,0 +1,19 @@
#include <unistd.h>
#include <fcntl.h>
int
main (int argc, char **argv)
{
int s;
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
s = open("/dev/null", O_RDONLY);
dup(s);
return 0;
}

View File

@ -0,0 +1,27 @@
FILE DESCRIPTORS: 6 open at exit.
Open file descriptor .: /dev/null
at 0x........: __dup (in /...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: /dev/null
at 0x........: __libc_open (...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1,3 @@
prog: fdleak_dup
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

View File

@ -0,0 +1,23 @@
#include <unistd.h>
#include <fcntl.h>
int
main (int argc, char **argv)
{
int s1;
int s2;
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
s1 = open("/dev/null", O_RDONLY);
s2 = open("/dev/null", O_RDONLY);
dup2(s1, 20);
dup2(s1, s2);
return 0;
}

View File

@ -0,0 +1,32 @@
FILE DESCRIPTORS: 7 open at exit.
Open file descriptor .: /dev/null
at 0x........: __dup2 (in /...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: /dev/null
at 0x........: __dup2 (in /...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: /dev/null
at 0x........: __libc_open (...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1,3 @@
prog: fdleak_dup2
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

View File

@ -0,0 +1,20 @@
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
int
main (int argc, char **argv)
{
int s1;
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
s1 = open("/dev/null", O_RDONLY);
if(fcntl(s1, F_DUPFD, s1) == -1) perror("fcntl");
return 0;
}

View File

@ -0,0 +1,26 @@
FILE DESCRIPTORS: 6 open at exit.
Open file descriptor .: /dev/null
at 0x........: __libc_fcntl (...libc...)
by 0x........: main (fdleak_fcntl.c:18)
Open file descriptor .: /dev/null
at 0x........: __libc_open (...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1,3 @@
prog: fdleak_fcntl
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

View File

@ -0,0 +1,109 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void
server ()
{
int s, x;
struct sockaddr_in baddr;
struct sockaddr_in addr;
int baddrsize = sizeof(baddr);
int one = 1;
s = socket(PF_INET, SOCK_STREAM, 0);
if(s == -1) {
perror("socket");
exit(1);
}
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = 12321;
if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind");
exit(1);
}
if(listen(s, 5) == -1) {
perror("listen");
exit(1);
}
memset(&baddr, 0, sizeof(baddr));
x = accept(s, (struct sockaddr *)&baddr, &baddrsize);
if(x == -1) {
perror("accept");
exit(1);
}
write(x, "hello", 6);
}
void
client ()
{
int s, count = 0, ret;
struct sockaddr_in addr;
char buf[1024];
s = socket(PF_INET, SOCK_STREAM, 0);
if(s == -1) {
perror("socket");
exit(1);
}
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = 12321;
do {
count++;
ret = connect(s, (struct sockaddr *)&addr, sizeof(addr));
if(ret == -1) sleep(1);
} while (count < 10 && ret == -1);
if(ret == -1) {
perror("connect");
exit(1);
}
read(s, buf, sizeof(buf));
printf("%s\n", buf);
}
int
main (int argc, char **argv)
{
int pid, status;
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
if((pid = fork()) == 0) {
server();
return 0;
}
client();
wait(&status);
return 0;
}

View File

@ -0,0 +1,45 @@
FILE DESCRIPTORS: 6 open at exit.
Open AF_INET socket 4: 127.0.0.1:... <-> 127.0.0.1:...
at 0x........: __libc_accept (...libc...)
by 0x........: main (fdleak_ipv4.c:100)
Open AF_INET socket 3: 127.0.0.1:... <-> unbound
at 0x........: __socket (in /...libc...)
by 0x........: main (fdleak_ipv4.c:100)
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
FILE DESCRIPTORS: 5 open at exit.
Open AF_INET socket 3: 127.0.0.1:... <-> 127.0.0.1:...
at 0x........: __socket (in /...libc...)
by 0x........: main (fdleak_ipv4.c:104)
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1 @@
hello

View File

@ -0,0 +1,3 @@
prog: fdleak_ipv4
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

View File

@ -0,0 +1,15 @@
#include <fcntl.h>
int
main (int argc, char **argv)
{
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
open("/dev/null", O_RDONLY);
return 0;
}

View File

@ -0,0 +1,22 @@
FILE DESCRIPTORS: 5 open at exit.
Open file descriptor .: /dev/null
at 0x........: __libc_open (...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1,3 @@
prog: fdleak_open
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

View File

@ -0,0 +1,17 @@
#include <unistd.h>
int
main (int argc, char **argv)
{
int fds[2];
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
pipe(fds);
return 0;
}

View File

@ -0,0 +1,27 @@
FILE DESCRIPTORS: 6 open at exit.
Open file descriptor .:
at 0x........: __pipe (in /...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .:
at 0x........: __pipe (in /...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1,3 @@
prog: fdleak_pipe
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

View File

@ -0,0 +1,17 @@
#include <sys/socket.h>
int
main (int argc, char **argv)
{
int fds[2];
/*
* Fedora Core 1's Perl opens /dev/pts/2 as fd 10. Let's close it
* now to get consistent results across different releases.
*/
close(10);
socketpair(AF_UNIX, SOCK_STREAM, PF_UNIX, fds);
return 0;
}

View File

@ -0,0 +1,27 @@
FILE DESCRIPTORS: 6 open at exit.
Open AF_UNIX socket .: <unknown>
at 0x........: __socketpair (in /...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open AF_UNIX socket .: <unknown>
at 0x........: __socketpair (in /...libc...)
by 0x........: __libc_start_main (...libc...)
by 0x........: ...
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
Open file descriptor .: .
<inherited from parent>
ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

View File

@ -0,0 +1,3 @@
prog: fdleak_socketpair
vgopts: --track-fds=yes
stderr_filter: filter_fdleak

26
corecheck/tests/filter_fdleak Executable file
View File

@ -0,0 +1,26 @@
#! /bin/sh
dir=`dirname $0`
$dir/../../tests/filter_stderr_basic |
# Anonymise addresses
$dir/../../tests/filter_addresses |
# Anonymise line numbers in mac_replace_strmem.c
sed "s/mac_replace_strmem.c:[0-9]\+/mac_replace_strmem.c:.../" |
$dir/../../tests/filter_test_paths |
# Anonymise paths like "(in /foo/bar/libc-baz.so)"
sed "s/(in \/.*libc.*)$/(in \/...libc...)/" |
# Anonymise paths like "__libc_start_main (../foo/bar/libc-quux.c:129)"
sed "s/__libc_\(.*\) (.*)$/__libc_\1 (...libc...)/" |
sed s/"^Open AF_UNIX socket [0-9]\+: <unknown>/Open AF_UNIX socket .: <unknown>/" |
sed s/"^Open \(AF_UNIX socket\|file descriptor\) [0-9]\+: \/dev\/null/Open \\1 .: \/dev\/null/" |
sed s/"^Open \(AF_UNIX socket\|file descriptor\) [0-9]\+: \/tmp\/\(sock\|data1\|data2\|file\)\.[0-9]\+/Open \\1 .: \/tmp\/\\2/" |
sed s/"^Open file descriptor [0-9]\+: .*/Open file descriptor .: ./" |
sed s/"^Open file descriptor [0-9]\+:$/Open file descriptor .:/" |
sed s/"127.0.0.1:[0-9]\+/127.0.0.1:.../g"

View File

@ -654,6 +654,15 @@ not Cachegrind.
<code>-v</code> option which prints out all used suppression records.
</li><br><p>
<li><code>--track-fds=no</code> [default]<br>
<code>--track-fds=yes</code>
<p>When enabled, Valgrind will print out a list of open file
descriptors on exit. Along with each file descriptor, Valgrind
prints out a stack backtrace of where the file was opened and any
details relating to the file descriptor such as the file name or
socket details.
<br><p>
<li><code>--gdb-attach=no</code> [default]<br>
<code>--gdb-attach=yes</code>
<p>When enabled, Valgrind will pause after every error shown,

View File

@ -257,6 +257,9 @@ extern Bool VG_(clo_assume_24);
extern Bool VG_(clo_lowlat_syscalls);
extern Bool VG_(clo_lowlat_signals);
/* Track open file descriptors? */
extern Bool VG_(clo_track_fds);
/* Should we run __libc_freeres at exit? Sometimes causes crashes.
Default: YES. Note this is subservient to VG_(needs).libc_freeres;
if the latter says False, then the setting of VG_(clo_weird_hacks)
@ -1574,6 +1577,10 @@ extern Bool VG_(is_kerror) ( Int res );
typedef void (*vg_atfork_t)(ThreadId);
extern void VG_(atfork)(vg_atfork_t pre, vg_atfork_t parent, vg_atfork_t child);
/* fd leakage calls. */
extern void VG_(init_preopened_fds) ( void );
extern void VG_(fd_stats) ( void );
/* ---------------------------------------------------------------------
Exports of vg_transtab.c
------------------------------------------------------------------ */

View File

@ -557,6 +557,7 @@ Int VG_(clo_dump_error) = 0;
Int VG_(clo_backtrace_size) = 4;
Char* VG_(clo_weird_hacks) = NULL;
Bool VG_(clo_run_libc_freeres) = True;
Bool VG_(clo_track_fds) = False;
Bool VG_(clo_chain_bb) = True;
Bool VG_(clo_show_below_main) = False;
@ -658,6 +659,8 @@ static void usage ( void )
" --suppressions=<filename> suppress errors described in <filename>\n"
" --gen-suppressions=no|yes print suppressions for errors detected [no]\n"
" --track-fds=no|yes Track open file descriptors? [no]\n"
" --gdb-attach=no|yes start GDB when errors detected? [no]\n"
" --gdb-path=/path/to/gdb path to the GDB to use [/usr/bin/gdb]\n"
" --input-fd=<number> file descriptor for (gdb) input [0=stdin]\n"
@ -999,6 +1002,11 @@ static void process_cmd_line_options ( void )
else if (VG_CLO_STREQ(argv[i], "--run-libc-freeres=no"))
VG_(clo_run_libc_freeres) = False;
else if (VG_CLO_STREQ(argv[i], "--track-fds=yes"))
VG_(clo_track_fds) = True;
else if (VG_CLO_STREQ(argv[i], "--track-fds=no"))
VG_(clo_track_fds) = False;
else if (VG_CLO_STREQN(15, argv[i], "--sanity-level="))
VG_(sanity_level) = (Int)VG_(atoll)(&argv[i][15]);
@ -1601,6 +1609,10 @@ void VG_(main) ( void )
/* Set up baseBlock offsets and copy the saved machine's state into it. */
vg_init_baseBlock();
/* Search for file descriptors that are inherited from our parent. */
if (VG_(clo_track_fds))
VG_(init_preopened_fds)();
/* Initialise the scheduler, and copy the client's state from
baseBlock into VG_(threads)[1]. Must be before:
- VG_(sigstartup_actions)()
@ -1675,6 +1687,10 @@ void VG_(main) ( void )
"Warning: pthread scheduler exited due to deadlock");
}
/* Print out file descriptor summary and stats. */
if(VG_(clo_track_fds))
VG_(fd_stats)();
if (VG_(needs).core_errors || VG_(needs).skin_errors)
VG_(show_all_errors)();

View File

@ -1204,6 +1204,15 @@ Int VG_(write) ( Int fd, const void* buf, Int count)
return res;
}
Int VG_(lseek) ( Int fd, Long offset, Int whence)
{
Int res;
/* res = lseek( fd, offset, whence ); */
res = VG_(do_syscall)(__NR_lseek, fd, (UInt)offset, whence);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
Int VG_(stat) ( Char* file_name, struct vki_stat* buf )
{
Int res;
@ -1289,6 +1298,37 @@ Char* VG_(getenv) ( Char* varname )
}
/* Support for getrlimit. */
Int VG_(getrlimit) (Int resource, struct vki_rlimit *rlim)
{
Int res;
/* res = getrlimit( resource, rlim ); */
res = VG_(do_syscall)(__NR_getrlimit, (UInt)resource, (UInt)rlim);
if(VG_(is_kerror)(res)) res = -1;
return res;
}
/* Support for getdents. */
Int VG_(getdents) (UInt fd, struct vki_dirent *dirp, UInt count)
{
Int res;
/* res = getdents( fd, dirp, count ); */
res = VG_(do_syscall)(__NR_getdents, fd, (UInt)dirp, count);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
/* Support for a readlink. */
Int VG_(readlink) (Char* path, Char* buf, UInt bufsiz)
{
Int res;
/* res = readlink( path, buf, bufsiz ); */
res = VG_(do_syscall)(__NR_readlink, (UInt)path, (UInt)buf, bufsiz);
if (VG_(is_kerror)(res)) res = -1;
return res;
}
/* You'd be amazed how many places need to know the current pid. */
Int VG_(getpid) ( void )
{
@ -1618,9 +1658,12 @@ void VG_(ssort)( void* base, UInt nmemb, UInt size,
/usr/src/linux-2.4.9-31 */
/* kernel, ./include/linux/net.h */
#define SYS_SOCKET 1 /* sys_socket(2) */
#define SYS_CONNECT 3 /* sys_connect(2) */
#define SYS_SEND 9 /* sys_send(2) */
#define SYS_SOCKET 1 /* sys_socket(2) */
#define SYS_CONNECT 3 /* sys_connect(2) */
#define SYS_GETSOCKNAME 6 /* sys_getsockname(2) */
#define SYS_GETPEERNAME 7 /* sys_getpeername(2) */
#define SYS_SEND 9 /* sys_send(2) */
#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */
typedef UInt __u32;
@ -1630,7 +1673,6 @@ struct vki_in_addr {
};
/* kernel, include/linux/socket.h */
typedef unsigned short vki_sa_family_t;
#define AF_INET 2 /* Internet IP Protocol */
#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */
@ -1822,6 +1864,48 @@ Int VG_(write_socket)( Int sd, void *msg, Int count )
return res;
}
Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
Int res;
UInt args[3];
args[0] = sd;
args[1] = (UInt)name;
args[2] = (UInt)namelen;
res = VG_(do_syscall)(__NR_socketcall, SYS_GETSOCKNAME, (UInt)&args);
if(VG_(is_kerror)(res))
res = -1;
return res;
}
Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen)
{
Int res;
UInt args[3];
args[0] = sd;
args[1] = (UInt)name;
args[2] = (UInt)namelen;
res = VG_(do_syscall)(__NR_socketcall, SYS_GETPEERNAME, (UInt)&args);
if(VG_(is_kerror)(res))
res = -1;
return res;
}
Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
Int *optlen)
{
Int res;
UInt args[5];
args[0] = sd;
args[1] = (UInt)level;
args[2] = (UInt)optname;
args[3] = (UInt)optval;
args[4] = (UInt)optlen;
res = VG_(do_syscall)(__NR_socketcall, SYS_GETSOCKOPT, (UInt)&args);
if(VG_(is_kerror)(res))
res = -1;
return res;
}
/*--------------------------------------------------------------------*/
/*--- end vg_mylibc.c ---*/

View File

@ -257,6 +257,291 @@ Bool VG_(is_kerror) ( Int res )
return False;
}
/* One of these is allocated for each open file descriptor. */
typedef struct OpenFd
{
Int fd; /* The file descriptor */
Char *pathname; /* NULL if not a regular file or unknown */
ExeContext *where; /* NULL if inherited from parent */
struct OpenFd *next, *prev;
} OpenFd;
/* List of allocated file descriptors. */
static OpenFd *allocated_fds;
/* Count of open file descriptors. */
static int fd_count = 0;
/* Given a file descriptor, attempt to deduce it's filename. To do this,
we use /proc/self/fd/<FD>. If this doesn't point to a file, or if it
doesn't exist, we just return NULL. Otherwise, we return a pointer
to the file name, which the caller is responsible for freeing. */
static
Char *resolve_fname(Int fd)
{
char tmp[28], buf[PATH_MAX];
VG_(sprintf)(tmp, "/proc/self/fd/%d", fd);
VG_(memset)(buf, 0, PATH_MAX);
if(VG_(readlink)(tmp, buf, PATH_MAX) == -1)
return NULL;
return ((buf[0] == '/') ? VG_(strdup)(buf) : NULL);
}
/* Note the fact that a file descriptor was just closed. */
static
void record_fd_close(Int tid, Int fd)
{
OpenFd *i = allocated_fds;
while(i) {
if(i->fd == fd) {
if(i->prev)
i->prev->next = i->next;
else
allocated_fds = i->next;
if(i->next)
i->next->prev = i->prev;
if(i->pathname)
VG_(free) (i->pathname);
VG_(free) (i);
fd_count--;
break;
}
i = i->next;
}
}
/* Note the fact that a file descriptor was just opened. If the
tid is -1, this indicates an inherited fd. If the pathname is NULL,
this either indicates a non-standard file (i.e. a pipe or socket or
some such thing) or that we don't know the filename. If the fd is
already open, then we're probably doing a dup2() to an existing fd,
so just overwrite the existing one. */
static
void record_fd_open(Int tid, Int fd, char *pathname)
{
OpenFd *i;
/* Check to see if this fd is already open. */
i = allocated_fds;
while (i) {
if (i->fd == fd) {
if (i->pathname) VG_(free)(i->pathname);
break;
}
i = i->next;
}
/* Not already one: allocate an OpenFd */
if (i == NULL) {
i = VG_(malloc)(sizeof(OpenFd));
i->prev = NULL;
i->next = allocated_fds;
if(allocated_fds) allocated_fds->prev = i;
allocated_fds = i;
fd_count++;
}
i->fd = fd;
i->pathname = pathname;
i->where = (tid == -1) ? NULL : VG_(get_ExeContext)(tid);
}
static
Char *unix2name(struct sockaddr_un *sa, UInt len, Char *name)
{
if(sa == NULL || len == 0 || sa->sun_path[0] == '\0') {
VG_(sprintf)(name, "<unknown>");
} else {
VG_(sprintf)(name, "%s", sa->sun_path);
}
return name;
}
static
Char *inet2name(struct sockaddr_in *sa, UInt len, Char *name)
{
if(sa == NULL || len == 0) {
VG_(sprintf)(name, "<unknown>");
} else {
UInt addr = sa->sin_addr.s_addr;
if (addr == 0) {
VG_(sprintf)(name, "<unbound>");
} else {
VG_(sprintf)(name, "%u.%u.%u.%u:%u",
addr & 0xFF, (addr>>8) & 0xFF,
(addr>>16) & 0xFF, (addr>>24) & 0xFF,
sa->sin_port);
}
}
return name;
}
/*
* Try get some details about a socket.
*/
static void
getsockdetails(int fd)
{
union u {
struct sockaddr a;
struct sockaddr_in in;
struct sockaddr_un un;
} laddr;
socklen_t llen;
llen = sizeof(laddr);
VG_(memset)(&laddr, 0, llen);
if(VG_(getsockname)(fd, (struct vki_sockaddr *)&(laddr.a), &llen) != -1) {
switch(laddr.a.sa_family) {
case AF_INET: {
static char lname[32];
static char pname[32];
struct sockaddr_in paddr;
socklen_t plen = sizeof(struct sockaddr_in);
if(VG_(getpeername)(fd, (struct vki_sockaddr *)&paddr, &plen) != -1) {
VG_(message)(Vg_UserMsg, "Open AF_INET socket %d: %s <-> %s", fd,
inet2name(&(laddr.in), llen, lname),
inet2name(&paddr, plen, pname));
} else {
VG_(message)(Vg_UserMsg, "Open AF_INET socket %d: %s <-> unbound",
fd, inet2name(&(laddr.in), llen, lname));
}
return;
}
case AF_UNIX: {
static char lname[256];
VG_(message)(Vg_UserMsg, "Open AF_UNIX socket %d: %s", fd,
unix2name(&(laddr.un), llen, lname));
return;
}
default:
VG_(message)(Vg_UserMsg, "Open pf-%d socket %d:",
laddr.a.sa_family, fd);
return;
}
}
VG_(message)(Vg_UserMsg, "Open socket %d:", fd);
}
/* Dump out a summary, and optionally a more detailed list, of open file
descriptors. */
void VG_(fd_stats) ()
{
OpenFd *i = allocated_fds;
VG_(message)(Vg_UserMsg,
"FILE DESCRIPTORS: %d open at exit.", fd_count);
while(i) {
if(i->pathname) {
VG_(message)(Vg_UserMsg, "Open file descriptor %d: %s", i->fd,
i->pathname);
} else {
int val;
socklen_t len = sizeof(val);
if(VG_(getsockopt)(i->fd, SOL_SOCKET, SO_TYPE, &val, &len) == -1) {
VG_(message)(Vg_UserMsg, "Open file descriptor %d:", i->fd);
} else {
getsockdetails(i->fd);
}
}
if(i->where) {
VG_(pp_ExeContext)(i->where);
VG_(message)(Vg_UserMsg, "");
} else {
VG_(message)(Vg_UserMsg, " <inherited from parent>");
VG_(message)(Vg_UserMsg, "");
}
i = i->next;
}
VG_(message)(Vg_UserMsg, "");
}
/* If /proc/self/fd doesn't exist for some weird reason (like you've
got a kernel that doesn't have /proc support compiled in), then we
need to find out what file descriptors we inherited from our parent
process the hard way - by checking each fd in turn. */
static
void do_hacky_preopened()
{
struct vki_rlimit lim;
unsigned int count;
int i;
if(VG_(getrlimit) (VKI_RLIMIT_NOFILE, &lim) == -1) {
/* Hmm. getrlimit() failed. Now we're screwed, so just choose
an arbitrarily high number. 1024 happens to be the limit in
the 2.4 kernels. */
count = 1024;
} else {
count = lim.rlim_cur;
}
for (i = 0; i < count; i++)
if(VG_(fcntl)(i, VKI_F_GETFL, 0) != -1)
record_fd_open(-1, i, NULL);
}
/* Initialize the list of open file descriptors with the file descriptors
we inherited from out parent process. */
void VG_(init_preopened_fds)()
{
int f, ret;
struct vki_dirent d;
f = VG_(open)("/proc/self/fd", VKI_O_RDONLY, 0);
if(f == -1) {
do_hacky_preopened();
return;
}
while((ret = VG_(getdents)(f, &d, sizeof(d))) != 0) {
if(ret == -1)
goto out;
if(VG_(strcmp)(d.d_name, ".") && VG_(strcmp)(d.d_name, "..")) {
int fno = VG_(atoll)(d.d_name);
if(fno != f)
if(VG_(clo_track_fds))
record_fd_open(-1, fno, resolve_fname(fno));
}
VG_(lseek)(f, d.d_off, VKI_SEEK_SET);
}
out:
VG_(close)(f);
}
static
UInt get_shm_size ( Int shmid )
{
@ -341,6 +626,27 @@ void msghdr_foreachfield (
(Addr)msg->msg_control, msg->msg_controllen );
}
void check_cmsg_for_fds(Int tid, struct msghdr *msg)
{
struct cmsghdr *cm = CMSG_FIRSTHDR(msg);
while (cm) {
if (cm->cmsg_level == SOL_SOCKET &&
cm->cmsg_type == SCM_RIGHTS ) {
int *fds = (int *) CMSG_DATA(cm);
int fdc = (cm->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)))
/ sizeof(int);
int i;
for (i = 0; i < fdc; i++)
if(VG_(clo_track_fds))
record_fd_open (tid, fds[i], resolve_fname(fds[i]));
}
cm = CMSG_NXTHDR(msg, cm);
}
}
static
void pre_mem_read_sockaddr ( ThreadId tid,
Char *description,
@ -1369,6 +1675,10 @@ PRE(close)
res = -VKI_EBADF;
}
POST(close)
{
if(VG_(clo_track_fds)) record_fd_close(tid, arg1);
}
PRE(dup)
{
@ -1382,6 +1692,9 @@ POST(dup)
if (!fd_allowed(res, "dup", tid)) {
VG_(close)(res);
res = -VKI_EMFILE;
} else {
if(VG_(clo_track_fds))
record_fd_open(tid, res, resolve_fname(res));
}
}
@ -1398,6 +1711,8 @@ POST(dup2)
MAYBE_PRINTF("SYSCALL[%d] dup2 ( %d, %d ) = %d\n",
VG_(getpid)(),
arg1, arg2, res);
if(VG_(clo_track_fds))
record_fd_open(tid, res, resolve_fname(res));
}
PRE(fcntl)
@ -1406,6 +1721,13 @@ PRE(fcntl)
MAYBE_PRINTF("fcntl ( %d, %d, %d )\n",arg1,arg2,arg3);
}
POST(fcntl)
{
if (arg2 == VKI_F_DUPFD)
if(VG_(clo_track_fds))
record_fd_open(tid, res, resolve_fname(res));
}
PRE(fchdir)
{
/* int fchdir(int fd); */
@ -1428,9 +1750,15 @@ PRE(fchmod)
PRE(fcntl64)
{
/* I don't know what the prototype for this is supposed to be. */
/* ??? int fcntl(int fd, int cmd); */
MAYBE_PRINTF("fcntl64 (?!) ( %d, %d )\n", arg1,arg2);
/* int fcntl64(int fd, int cmd, int arg); */
MAYBE_PRINTF("fcntl64 ( %d, %d, %d )\n", arg1,arg2,arg3);
}
POST(fcntl64)
{
if (arg2 == VKI_F_DUPFD)
if(VG_(clo_track_fds))
record_fd_open(tid, res, resolve_fname(res));
}
PRE(fstat)
@ -3003,6 +3331,9 @@ POST(open)
if (!fd_allowed(res, "open", tid)) {
VG_(close)(res);
res = -VKI_EMFILE;
} else {
if(VG_(clo_track_fds))
record_fd_open(tid, res, VG_(strdup)((Char*)arg1));
}
MAYBE_PRINTF("%d\n",res);
}
@ -3044,6 +3375,9 @@ POST(creat)
if (!fd_allowed(res, "creat", tid)) {
VG_(close)(res);
res = -VKI_EMFILE;
} else {
if(VG_(clo_track_fds))
record_fd_open(tid, res, VG_(strdup)((Char*)arg1));
}
MAYBE_PRINTF("%d\n",res);
}
@ -3065,8 +3399,13 @@ POST(pipe)
VG_(close)(p[0]);
VG_(close)(p[1]);
res = -VKI_EMFILE;
} else
} else {
VG_TRACK( post_mem_write, arg1, 2*sizeof(int) );
if(VG_(clo_track_fds)) {
record_fd_open(tid, p[0], NULL);
record_fd_open(tid, p[1], NULL);
}
}
MAYBE_PRINTF("SYSCALL[%d] pipe --> %d (rd %d, wr %d)\n",
VG_(getpid)(), res,
@ -3563,12 +3902,19 @@ POST(socketcall)
case SYS_SOCKETPAIR:
/* XXX TODO: check return fd against VG_MAX_FD */
VG_TRACK( post_mem_write, ((UInt*)arg2)[3], 2*sizeof(int) );
if(VG_(clo_track_fds)) {
record_fd_open(tid, ((UInt*)((UInt*)arg2)[3])[0], NULL);
record_fd_open(tid, ((UInt*)((UInt*)arg2)[3])[1], NULL);
}
break;
case SYS_SOCKET:
if (!fd_allowed(res, "socket", tid)) {
VG_(close)(res);
res = -VKI_EMFILE;
} else {
if(VG_(clo_track_fds))
record_fd_open(tid, res, NULL);
}
break;
@ -3593,6 +3939,8 @@ POST(socketcall)
if (addr_p != (Addr)NULL)
buf_and_len_post_check ( tid, res, addr_p, addrlen_p,
"socketcall.accept(addrlen_out)" );
if(VG_(clo_track_fds))
record_fd_open(tid, res, NULL);
}
break;
}
@ -3673,6 +4021,7 @@ POST(socketcall)
struct msghdr *msg = (struct msghdr *)((UInt *)arg2)[ 1 ];
msghdr_foreachfield( tid, msg, post_mem_write_recvmsg );
check_cmsg_for_fds( tid, msg );
break;
}
@ -4222,15 +4571,15 @@ static const struct sys_info sys_info[] = {
SYSB_(chown32, False),
SYSB_(lchown32, False),
SYSB_(chown, False),
SYSB_(close, False),
SYSBA(close, False),
SYSBA(dup, False),
SYSBA(dup2, False),
SYSB_(fcntl, True),
SYSBA(fcntl, True),
SYSB_(fchdir, False),
SYSB_(fchown32, False),
SYSB_(fchown, False),
SYSB_(fchmod, False),
SYSB_(fcntl64, True),
SYSBA(fcntl64, True),
SYSBA(fstat, False),
SYSBA(fork, False),
SYSB_(fsync, True),

View File

@ -330,6 +330,10 @@ struct vki_ucontext {
#define VKI_O_DIRECTORY 0200000 /* must be a directory */
#define VKI_O_NOFOLLOW 0400000 /* don't follow links */
#define VKI_SEEK_SET 0
#define VKI_SEEK_CUR 1
#define VKI_SEEK_END 2
/* Copied from linux-2.4.19/include/linux/stat.h */
#define VKI_S_IRWXU 00700
@ -633,6 +637,41 @@ typedef struct vki_modify_ldt_ldt_s {
#define VKI_CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force VKI_CLONE_PTRACE on this clone */
#define VKI_CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */
/* This is the structure passed to the getdents syscall. */
/*
* linux/dirent.h
*/
typedef struct vki_dirent {
long d_ino;
long d_off;
unsigned short d_reclen;
char d_name[256];
} vki_dirent;
/* This is the structure passed to the getrlimit syscall. */
/*
* bits/resource.h
*/
typedef struct vki_rlimit {
unsigned long rlim_cur;
unsigned long rlim_max;
} vki_rlimit;
#define VKI_RLIMIT_NOFILE 7
/* Socket stuff. */
/*
* sys/socket.h
*/
typedef unsigned short vki_sa_family_t;
struct vki_sockaddr {
vki_sa_family_t sa_family; /* Address family. */
char sa_data[14]; /* Address data. */
};
#endif /* ndef __VG_KERNELIFACE_H */
/*--------------------------------------------------------------------*/

View File

@ -362,6 +362,9 @@ extern void VG_(skin_panic) ( Char* str );
/* Looks up VG_(client_envp) */
extern Char* VG_(getenv) ( Char* name );
/* Get client resource limit*/
extern Int VG_(getrlimit) ( Int resource, struct vki_rlimit *rlim );
/* Crude stand-in for the glibc system() call. */
extern Int VG_(system) ( Char* cmd );
@ -420,6 +423,8 @@ extern Int VG_(log2) ( Int x );
/* ------------------------------------------------------------------ */
/* unistd.h, fcntl.h, sys/stat.h */
extern Int VG_(getdents)( UInt fd, struct vki_dirent *dirp, UInt count );
extern Int VG_(readlink)( Char* path, Char* buf, UInt bufsize );
extern Int VG_(getpid) ( void );
extern Int VG_(getppid) ( void );
extern Int VG_(getpgrp) ( void );
@ -429,6 +434,7 @@ extern Int VG_(setpgid) ( Int pid, Int pgrp );
extern Int VG_(open) ( const Char* pathname, Int flags, Int mode );
extern Int VG_(read) ( Int fd, void* buf, Int count);
extern Int VG_(write) ( Int fd, const void* buf, Int count);
extern Int VG_(lseek) ( Int fd, Long offset, Int whence);
extern void VG_(close) ( Int fd );
extern Int VG_(pipe) ( Int fd[2] );
@ -513,6 +519,14 @@ extern Int VG_(ksigpending) ( vki_ksigset_t* set );
extern Int VG_(waitpid) ( Int pid, Int *status, Int options );
/* ------------------------------------------------------------------ */
/* socket.h. */
extern Int VG_(getsockname) ( Int sd, struct vki_sockaddr *name, Int *namelen);
extern Int VG_(getpeername) ( Int sd, struct vki_sockaddr *name, Int *namelen);
extern Int VG_(getsockopt) ( Int sd, Int level, Int optname, void *optval,
Int *optlen);
/* ------------------------------------------------------------------ */
/* other, randomly useful functions */
extern UInt VG_(read_millisecond_timer) ( void );