Project

General

Profile

Backport #5075 » 5075-1.9.2.patch

akr (Akira Tanaka), 07/24/2011 11:22 PM

View differences:

include/ruby/intern.h (working copy)
void rb_write_error2(const char*, long);
void rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds);
int rb_pipe(int *pipes);
void rb_update_max_fd(int fd);
/* marshal.c */
VALUE rb_marshal_dump(VALUE, VALUE);
VALUE rb_marshal_load(VALUE);
ChangeLog (working copy)
Sun Jul 24 22:47:10 2011 Tanaka Akira <akr@fsij.org>
* backport r32579, r32581, r32587, r32588, r32598, r32638, r32655,
r32656, r32657 from trunk.
r32579:
* io.c (rb_update_max_fd): new function.
r32581:
* io.c (UPDATE_MAXFD): removed.
r32587:
* include/ruby/intern.h (rb_update_max_fd): declared.
* file.c: ditto.
* io.c: call rb_update_max_fd for each new fds.
* process.c: ditto.
* random.c: ditto.
* ruby.c: ditto.
* ext/openssl/ossl_bio.c: ditto.
* ext/pty/pty.c: ditto.
* ext/socket/init.c: ditto.
* ext/socket/socket.c: ditto.
* ext/socket/ancdata.c: ditto.
* ext/socket/unixsocket.c: ditto.
r32588:
* io.c (rb_update_max_fd): remove parentheses. they are not in
macro.
r32598:
* ext/socket/ancdata.c (discard_cmsg): workaround for MacOS X Lion.
r32638:
* io.c (rb_update_max_fd): validate fd.
* ext/socket/rubysocket.h (rsock_discard_cmsg_resource): add
msg_peek_p argument for the declaration.
* ext/socket/ancdata.c (discard_cmsg): add msg_peek_p argument.
assume FreeBSD, NetBSD and MacOS X doesn't generate passed fd
when MSG_PEEK.
(rsock_discard_cmsg_resource): add msg_peek_p argument.
(bsock_recvmsg_internal): call rsock_discard_cmsg_resource with
msg_peek_p argument.
* ext/socket/unixsocket.c (unix_recv_io): call
rsock_discard_cmsg_resource with msg_peek_p argument.
r32655:
* ext/socket/extconf.rb: test recvmsg allocates file descriptors for
fd passing even with MSG_PEEK.
* ext/socket/ancdata.c: use the above test result.
r32656:
* ext/socket/extconf.rb: fix the recvmsg test.
r32657:
* ext/socket/extconf.rb: refine the recvmsg test.
Sat Jul 9 19:25:02 2011 Yuki Sonoda (Yugui) <yugui@yugui.jp>
* ext/tk/extconf.rb: I gave up to fix the build issue of ext/tk with Windows
io.c (working copy)
};
static int max_file_descriptor = NOFILE;
#define UPDATE_MAXFD(fd) \
do { \
if (max_file_descriptor < (fd)) max_file_descriptor = (fd); \
} while (0)
void
rb_update_max_fd(int fd)
{
struct stat buf;
if (fstat(fd, &buf) != 0) {
rb_bug("rb_update_max_fd: invalid fd (%d) given.", fd);
}
if (max_file_descriptor < fd) max_file_descriptor = fd;
}
#define argf_of(obj) (*(struct argf *)DATA_PTR(obj))
#define ARGF argf_of(argf)
......
rb_sys_fail(0);
}
}
UPDATE_MAXFD(fd);
rb_update_max_fd(fd);
return fd;
}
......
static inline int
rb_sysopen_internal(struct sysopen_struct *data)
{
return (int)rb_thread_blocking_region(sysopen_func, data, RUBY_UBF_IO, 0);
int fd;
fd = (int)rb_thread_blocking_region(sysopen_func, data, RUBY_UBF_IO, 0);
if (0 <= fd)
rb_update_max_fd(fd);
return fd;
}
static int
......
rb_sys_fail(RSTRING_PTR(fname));
}
}
UPDATE_MAXFD(fd);
rb_update_max_fd(fd);
return fd;
}
......
}
}
if (ret == 0) {
UPDATE_MAXFD(pipes[0]);
UPDATE_MAXFD(pipes[1]);
rb_update_max_fd(pipes[0]);
rb_update_max_fd(pipes[1]);
}
return ret;
}
......
/* need to keep FILE objects of stdin, stdout and stderr */
if (dup2(fd2, fd) < 0)
rb_sys_fail_path(orig->pathv);
rb_update_max_fd(fd);
}
else {
fclose(fptr->stdio_file);
......
fptr->fd = -1;
if (dup2(fd2, fd) < 0)
rb_sys_fail_path(orig->pathv);
rb_update_max_fd(fd);
fptr->fd = fd;
}
rb_thread_fd_close(fd);
......
fp->mode = fmode;
io_check_tty(fp);
if (path) fp->pathv = rb_obj_freeze(rb_str_new_cstr(path));
rb_update_max_fd(fd);
return io;
}
......
#else
if (fstat(fd, &st) == -1) rb_sys_fail(0);
#endif
UPDATE_MAXFD(fd);
rb_update_max_fd(fd);
#if defined(HAVE_FCNTL) && defined(F_GETFL)
ofmode = rb_io_oflags_fmode(oflags);
if (NIL_P(vmode)) {
......
# endif
# if defined(F_DUPFD)
if (!io_p && retval != -1 && cmd == F_DUPFD) {
UPDATE_MAXFD(retval);
rb_update_max_fd(retval);
}
# endif
#else
process.c (working copy)
ERRMSG("dup");
return -1;
}
rb_update_max_fd(save_fd);
newary = rb_ary_entry(save, EXEC_OPTION_DUP2);
if (NIL_P(newary)) {
newary = hide_obj(rb_ary_new());
......
ERRMSG("dup2");
goto fail;
}
rb_update_max_fd(pairs[j].newfd);
pairs[j].oldfd = -1;
j = pairs[j].older_index;
if (j != -1)
......
ERRMSG("dup");
goto fail;
}
rb_update_max_fd(extra_fd);
}
else {
ret = redirect_dup2(pairs[i].oldfd, extra_fd);
......
ERRMSG("dup2");
goto fail;
}
rb_update_max_fd(extra_fd);
}
pairs[i].oldfd = extra_fd;
j = pairs[i].older_index;
......
ERRMSG("dup2");
goto fail;
}
rb_update_max_fd(ret);
pairs[j].oldfd = -1;
j = pairs[j].older_index;
}
......
ERRMSG("open");
return -1;
}
rb_update_max_fd(fd2);
while (i < RARRAY_LEN(ary) &&
(elt = RARRAY_PTR(ary)[i], RARRAY_PTR(elt)[1] == param)) {
fd = FIX2INT(RARRAY_PTR(elt)[0]);
......
ERRMSG("dup2");
return -1;
}
rb_update_max_fd(fd);
}
i++;
}
......
ERRMSG("dup2");
return -1;
}
rb_update_max_fd(newfd);
}
return 0;
}
......
ret = fcntl(fdp[i], F_DUPFD, min);
if (ret == -1)
return -1;
rb_update_max_fd(ret);
close(fdp[i]);
fdp[i] = ret;
}
......
if (ret == -1) return -1;
if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
rb_update_max_fd(fd);
ioctl(fd, TIOCNOTTY, NULL);
close(fd);
}
ext/pty/pty.c (working copy)
{
int i = open("/dev/tty", O_RDONLY);
if (i < 0) rb_sys_fail("/dev/tty");
rb_update_max_fd(i);
if (ioctl(i, TIOCNOTTY, (char *)0))
perror("ioctl(TIOCNOTTY)");
close(i);
......
perror("open: pty slave");
_exit(1);
}
rb_update_max_fd(slave);
close(master);
#endif
write(slave, "", 1);
......
sigemptyset(&dfl.sa_mask);
if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
rb_update_max_fd(masterfd);
if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
if (grantpt(masterfd) == -1) goto grantpt_error;
if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
......
if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
if (no_mesg(slavedevice, nomesg) == -1) goto error;
if ((slavefd = open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
rb_update_max_fd(slavefd);
#if defined I_PUSH && !defined linux
if (ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
......
if (!fail) return -1;
rb_raise(rb_eRuntimeError, "openpty() failed");
}
rb_update_max_fd(*master);
rb_update_max_fd(*slave);
if (no_mesg(SlaveName, nomesg) == -1) {
if (!fail) return -1;
rb_raise(rb_eRuntimeError, "can't chmod slave pty");
......
if (!fail) return -1;
rb_raise(rb_eRuntimeError, "_getpty() failed");
}
rb_update_max_fd(*master);
*slave = open(name, O_RDWR);
/* error check? */
rb_update_max_fd(*slave);
strlcpy(SlaveName, name, DEVICELEN);
return 0;
......
extern int grantpt(int);
if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
rb_update_max_fd(masterfd);
s = signal(SIGCHLD, SIG_DFL);
if(grantpt(masterfd) == -1) goto error;
signal(SIGCHLD, s);
......
if((slavedevice = ptsname(masterfd)) == NULL) goto error;
if (no_mesg(slavedevice, nomesg) == -1) goto error;
if((slavefd = open(slavedevice, O_RDWR, 0)) == -1) goto error;
rb_update_max_fd(slavefd);
#if defined I_PUSH && !defined linux
if(ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
if(ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
......
for (p = deviceNo; *p != NULL; p++) {
snprintf(MasterName, sizeof MasterName, MasterDevice, *p);
if ((masterfd = open(MasterName,O_RDWR,0)) >= 0) {
rb_update_max_fd(masterfd);
*master = masterfd;
snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
if ((slavefd = open(SlaveName,O_RDWR,0)) >= 0) {
rb_update_max_fd(slavefd);
*slave = slavefd;
if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
......
wfptr->fd = dup(info.fd);
if (wfptr->fd == -1)
rb_sys_fail("dup()");
rb_update_max_fd(wfptr->fd);
wfptr->pathv = rfptr->pathv;
res = rb_ary_new2(3);
ext/openssl/ossl_bio.c (working copy)
if ((fd = dup(FPTR_TO_FD(fptr))) < 0){
rb_sys_fail(0);
}
rb_update_max_fd(fd);
if (!(fp = fdopen(fd, "r"))){
close(fd);
rb_sys_fail(0);
ext/socket/rubysocket.h (working copy)
#endif
#ifdef HAVE_ST_MSG_CONTROL
void rsock_discard_cmsg_resource(struct msghdr *mh);
void rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p);
#endif
void rsock_init_basicsocket(void);
ext/socket/init.c (working copy)
#ifndef _WIN32
if (fstat(fd, &sbuf) < 0)
rb_sys_fail(0);
rb_update_max_fd(fd);
if (!S_ISSOCK(sbuf.st_mode))
rb_raise(rb_eArgError, "not a socket file descriptor");
#else
......
fd = socket(domain, type, proto);
}
}
if (0 <= fd)
rb_update_max_fd(fd);
return fd;
}
......
}
rb_sys_fail("accept(2)");
}
rb_update_max_fd(fd2);
make_fd_nonblock(fd2);
return rsock_init_sock(rb_obj_alloc(klass), fd2);
}
......
}
rb_sys_fail(0);
}
rb_update_max_fd(fd2);
if (!klass) return INT2NUM(fd2);
return rsock_init_sock(rb_obj_alloc(klass), fd2);
}
ext/socket/extconf.rb (working copy)
have_type("PADDRINFO", %w[ ws2tcpip.h wspiapi.h ])
if checking_for("recvmsg() with MSG_PEEK allocate file descriptors") {try_run(cpp_include(headers) + <<'EOF')}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ps[2], sv[2];
int ret;
ssize_t ss;
int s_fd, r_fd;
struct msghdr s_msg, r_msg;
union {
struct cmsghdr hdr;
char dummy[CMSG_SPACE(sizeof(int))];
} s_cmsg, r_cmsg;
struct iovec s_iov, r_iov;
char s_buf[1], r_buf[1];
struct stat s_statbuf, r_statbuf;
ret = pipe(ps);
if (ret == -1) { perror("pipe"); exit(EXIT_FAILURE); }
s_fd = ps[0];
ret = socketpair(AF_UNIX, SOCK_DGRAM, 0, sv);
if (ret == -1) { perror("socketpair"); exit(EXIT_FAILURE); }
s_msg.msg_name = NULL;
s_msg.msg_namelen = 0;
s_msg.msg_iov = &s_iov;
s_msg.msg_iovlen = 1;
s_msg.msg_control = &s_cmsg;
s_msg.msg_controllen = CMSG_SPACE(sizeof(int));;
s_msg.msg_flags = 0;
s_iov.iov_base = &s_buf;
s_iov.iov_len = sizeof(s_buf);
s_buf[0] = 'a';
s_cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(int));
s_cmsg.hdr.cmsg_level = SOL_SOCKET;
s_cmsg.hdr.cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(&s_cmsg.hdr), (char *)&s_fd, sizeof(int));
ss = sendmsg(sv[0], &s_msg, 0);
if (ss == -1) { perror("sendmsg"); exit(EXIT_FAILURE); }
r_msg.msg_name = NULL;
r_msg.msg_namelen = 0;
r_msg.msg_iov = &r_iov;
r_msg.msg_iovlen = 1;
r_msg.msg_control = &r_cmsg;
r_msg.msg_controllen = CMSG_SPACE(sizeof(int));
r_msg.msg_flags = 0;
r_iov.iov_base = &r_buf;
r_iov.iov_len = sizeof(r_buf);
r_buf[0] = '0';
memset(&r_cmsg, 0xff, CMSG_SPACE(sizeof(int)));
ss = recvmsg(sv[1], &r_msg, MSG_PEEK);
if (ss == -1) { perror("recvmsg"); exit(EXIT_FAILURE); }
if (ss != 1) {
fprintf(stderr, "unexpected return value from recvmsg: %ld\n", (long)ss);
exit(EXIT_FAILURE);
}
if (r_buf[0] != 'a') {
fprintf(stderr, "unexpected return data from recvmsg: 0x%02x\n", r_buf[0]);
exit(EXIT_FAILURE);
}
if (r_msg.msg_controllen < CMSG_LEN(sizeof(int))) {
fprintf(stderr, "unexpected: r_msg.msg_controllen < CMSG_LEN(sizeof(int)) not hold: %ld\n",
(long)r_msg.msg_controllen);
exit(EXIT_FAILURE);
}
if (r_cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(int))) {
fprintf(stderr, "unexpected: r_cmsg.hdr.cmsg_len < CMSG_LEN(sizeof(int)) not hold: %ld\n",
(long)r_cmsg.hdr.cmsg_len);
exit(EXIT_FAILURE);
}
memcpy((char *)&r_fd, CMSG_DATA(&r_cmsg.hdr), sizeof(int));
if (r_fd < 0) {
fprintf(stderr, "negative r_fd: %d\n", r_fd);
exit(EXIT_FAILURE);
}
if (r_fd == s_fd) {
fprintf(stderr, "r_fd and s_fd is same: %d\n", r_fd);
exit(EXIT_FAILURE);
}
ret = fstat(s_fd, &s_statbuf);
if (ret == -1) { perror("fstat(s_fd)"); exit(EXIT_FAILURE); }
ret = fstat(r_fd, &r_statbuf);
if (ret == -1) { perror("fstat(r_fd)"); exit(EXIT_FAILURE); }
if (s_statbuf.st_dev != r_statbuf.st_dev ||
s_statbuf.st_ino != r_statbuf.st_ino) {
fprintf(stderr, "dev/ino doesn't match: s_fd:%ld/%ld r_fd:%ld/%ld\n",
(long)s_statbuf.st_dev, (long)s_statbuf.st_ino,
(long)r_statbuf.st_dev, (long)r_statbuf.st_ino);
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
EOF
$defs << "-DFD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK"
end
getaddr_info_ok = (enable_config("wide-getaddrinfo") && :wide) ||
(checking_for("wide getaddrinfo") {try_run(<<EOF)} && :os)
#{cpp_include(headers)}
ext/socket/socket.c (working copy)
if (ret < 0) {
rb_sys_fail("socketpair(2)");
}
rb_update_max_fd(sp[0]);
rb_update_max_fd(sp[1]);
s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
ext/socket/ancdata.c (working copy)
#if defined(HAVE_ST_MSG_CONTROL)
static void
discard_cmsg(struct cmsghdr *cmh, char *msg_end)
discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
{
# if !defined(FD_PASSING_WORK_WITH_RECVMSG_MSG_PEEK)
/*
* FreeBSD 8.2.0, NetBSD 5 and MacOS X Snow Leopard doesn't
* allocate fds by recvmsg with MSG_PEEK.
* [ruby-dev:44189]
* http://redmine.ruby-lang.org/issues/5075
*
* Linux 2.6.38 allocate fds by recvmsg with MSG_PEEK.
*/
if (msg_peek_p)
return;
# endif
if (cmh->cmsg_level == SOL_SOCKET && cmh->cmsg_type == SCM_RIGHTS) {
int *fdp = (int *)CMSG_DATA(cmh);
int *end = (int *)((char *)cmh + cmh->cmsg_len);
while ((char *)fdp + sizeof(int) <= (char *)end &&
(char *)fdp + sizeof(int) <= msg_end) {
rb_update_max_fd(*fdp);
close(*fdp);
fdp++;
}
......
#endif
void
rsock_discard_cmsg_resource(struct msghdr *mh)
rsock_discard_cmsg_resource(struct msghdr *mh, int msg_peek_p)
{
#if defined(HAVE_ST_MSG_CONTROL)
struct cmsghdr *cmh;
......
msg_end = (char *)mh->msg_control + mh->msg_controllen;
for (cmh = CMSG_FIRSTHDR(mh); cmh != NULL; cmh = CMSG_NXTHDR(mh, cmh)) {
discard_cmsg(cmh, msg_end);
discard_cmsg(cmh, msg_end, msg_peek_p);
}
#endif
}
......
VALUE io;
if (fstat(fd, &stbuf) == -1)
rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
rb_update_max_fd(fd);
if (S_ISSOCK(stbuf.st_mode))
io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
else
......
/* there are big space bug truncated.
* file descriptors limit? */
if (!gc_done) {
rsock_discard_cmsg_resource(&mh);
rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
goto gc_and_retry;
}
}
......
}
#endif
if (grown) {
rsock_discard_cmsg_resource(&mh);
rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
goto retry;
}
else {
grow_buffer = 0;
if (flags != orig_flags) {
rsock_discard_cmsg_resource(&mh, (flags & MSG_PEEK) != 0);
flags = orig_flags;
rsock_discard_cmsg_resource(&mh);
goto retry;
}
}
......
if (request_scm_rights)
make_io_for_unix_rights(ctl, cmh, msg_end);
else
discard_cmsg(cmh, msg_end);
discard_cmsg(cmh, msg_end, (flags & MSG_PEEK) != 0);
rb_ary_push(ret, ctl);
}
}
ext/socket/unixsocket.c (working copy)
(int)arg.msg.msg_controllen, (int)CMSG_SPACE(sizeof(int)));
}
if (cmsg.hdr.cmsg_len != CMSG_LEN(sizeof(int))) {
rsock_discard_cmsg_resource(&arg.msg);
rsock_discard_cmsg_resource(&arg.msg, 0);
rb_raise(rb_eSocket,
"file descriptor was not passed (cmsg_len=%d, %d expected)",
(int)cmsg.hdr.cmsg_len, (int)CMSG_LEN(sizeof(int)));
......
#if FD_PASSING_BY_MSG_CONTROL
memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
#endif
rb_update_max_fd(fd);
if (klass == Qnil)
return INT2FIX(fd);
ruby.c (working copy)
if ((fd = open(fname, mode)) < 0) {
rb_load_fail(fname);
}
rb_update_max_fd(fd);
f = rb_io_fdopen(fd, mode, fname);
}
file.c (working copy)
if ((tmpfd = open(StringValueCStr(path), 0)) < 0) {
rb_sys_fail(RSTRING_PTR(path));
}
rb_update_max_fd(tmpfd);
if (chsize(tmpfd, pos) < 0) {
close(tmpfd);
rb_sys_fail(RSTRING_PTR(path));
......
int ret = 1;
int fd = open(path, O_RDONLY);
if (fd == -1) return 0;
rb_update_max_fd(fd);
#if !defined DOSISH
{
struct stat st;
random.c (working copy)
|O_NOCTTY
#endif
)) >= 0) {
rb_update_max_fd(fd);
if (fstat(fd, &statbuf) == 0 && S_ISCHR(statbuf.st_mode)) {
(void)read(fd, seed, DEFAULT_SEED_LEN);
}
(2-2/2)