mirror of
https://github.com/Zenithsiz/ftmemsim-valgrind.git
synced 2026-02-03 18:13:01 +00:00
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:
parent
d38eac1bf6
commit
f9ea43d896
@ -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
|
||||
|
||||
182
corecheck/tests/fdleak_cmsg.c
Normal file
182
corecheck/tests/fdleak_cmsg.c
Normal 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;
|
||||
}
|
||||
61
corecheck/tests/fdleak_cmsg.stderr.exp
Normal file
61
corecheck/tests/fdleak_cmsg.stderr.exp
Normal 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)
|
||||
3
corecheck/tests/fdleak_cmsg.vgtest
Normal file
3
corecheck/tests/fdleak_cmsg.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_cmsg
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
21
corecheck/tests/fdleak_creat.c
Normal file
21
corecheck/tests/fdleak_creat.c
Normal 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;
|
||||
}
|
||||
23
corecheck/tests/fdleak_creat.stderr.exp
Normal file
23
corecheck/tests/fdleak_creat.stderr.exp
Normal 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)
|
||||
3
corecheck/tests/fdleak_creat.vgtest
Normal file
3
corecheck/tests/fdleak_creat.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_creat
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
19
corecheck/tests/fdleak_dup.c
Normal file
19
corecheck/tests/fdleak_dup.c
Normal 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;
|
||||
}
|
||||
27
corecheck/tests/fdleak_dup.stderr.exp
Normal file
27
corecheck/tests/fdleak_dup.stderr.exp
Normal 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)
|
||||
3
corecheck/tests/fdleak_dup.vgtest
Normal file
3
corecheck/tests/fdleak_dup.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_dup
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
23
corecheck/tests/fdleak_dup2.c
Normal file
23
corecheck/tests/fdleak_dup2.c
Normal 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;
|
||||
}
|
||||
32
corecheck/tests/fdleak_dup2.stderr.exp
Normal file
32
corecheck/tests/fdleak_dup2.stderr.exp
Normal 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)
|
||||
3
corecheck/tests/fdleak_dup2.vgtest
Normal file
3
corecheck/tests/fdleak_dup2.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_dup2
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
20
corecheck/tests/fdleak_fcntl.c
Normal file
20
corecheck/tests/fdleak_fcntl.c
Normal 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;
|
||||
}
|
||||
26
corecheck/tests/fdleak_fcntl.stderr.exp
Normal file
26
corecheck/tests/fdleak_fcntl.stderr.exp
Normal 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)
|
||||
3
corecheck/tests/fdleak_fcntl.vgtest
Normal file
3
corecheck/tests/fdleak_fcntl.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_fcntl
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
109
corecheck/tests/fdleak_ipv4.c
Normal file
109
corecheck/tests/fdleak_ipv4.c
Normal 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;
|
||||
}
|
||||
45
corecheck/tests/fdleak_ipv4.stderr.exp
Normal file
45
corecheck/tests/fdleak_ipv4.stderr.exp
Normal 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)
|
||||
1
corecheck/tests/fdleak_ipv4.stdout.exp
Normal file
1
corecheck/tests/fdleak_ipv4.stdout.exp
Normal file
@ -0,0 +1 @@
|
||||
hello
|
||||
3
corecheck/tests/fdleak_ipv4.vgtest
Normal file
3
corecheck/tests/fdleak_ipv4.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_ipv4
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
15
corecheck/tests/fdleak_open.c
Normal file
15
corecheck/tests/fdleak_open.c
Normal 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;
|
||||
}
|
||||
22
corecheck/tests/fdleak_open.stderr.exp
Normal file
22
corecheck/tests/fdleak_open.stderr.exp
Normal 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)
|
||||
3
corecheck/tests/fdleak_open.vgtest
Normal file
3
corecheck/tests/fdleak_open.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_open
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
17
corecheck/tests/fdleak_pipe.c
Normal file
17
corecheck/tests/fdleak_pipe.c
Normal 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;
|
||||
}
|
||||
27
corecheck/tests/fdleak_pipe.stderr.exp
Normal file
27
corecheck/tests/fdleak_pipe.stderr.exp
Normal 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)
|
||||
3
corecheck/tests/fdleak_pipe.vgtest
Normal file
3
corecheck/tests/fdleak_pipe.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_pipe
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
17
corecheck/tests/fdleak_socketpair.c
Normal file
17
corecheck/tests/fdleak_socketpair.c
Normal 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;
|
||||
}
|
||||
27
corecheck/tests/fdleak_socketpair.stderr.exp
Normal file
27
corecheck/tests/fdleak_socketpair.stderr.exp
Normal 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)
|
||||
3
corecheck/tests/fdleak_socketpair.vgtest
Normal file
3
corecheck/tests/fdleak_socketpair.vgtest
Normal file
@ -0,0 +1,3 @@
|
||||
prog: fdleak_socketpair
|
||||
vgopts: --track-fds=yes
|
||||
stderr_filter: filter_fdleak
|
||||
26
corecheck/tests/filter_fdleak
Executable file
26
corecheck/tests/filter_fdleak
Executable 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"
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
------------------------------------------------------------------ */
|
||||
|
||||
@ -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)();
|
||||
|
||||
|
||||
@ -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 ---*/
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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 */
|
||||
|
||||
/*--------------------------------------------------------------------*/
|
||||
|
||||
@ -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 );
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user