* ext/pty/pty.c (chfunc): pass through exceptions.

* io.c (rb_io_bufwrite, rb_io_bufread): added.

* process.c (rb_fork_err): protect from exceptions.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@29171 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2010-09-02 21:40:55 +00:00
parent 163b4dee96
commit aa5c05b8ba
4 changed files with 124 additions and 58 deletions

View File

@ -1,3 +1,11 @@
Fri Sep 3 06:40:44 2010 Nobuyoshi Nakada <nobu@ruby-lang.org>
* ext/pty/pty.c (chfunc): pass through exceptions.
* io.c (rb_io_bufwrite, rb_io_bufread): added.
* process.c (rb_fork_err): protect from exceptions.
Fri Sep 3 06:16:07 2010 Tanaka Akira <akr@fsij.org> Fri Sep 3 06:16:07 2010 Tanaka Akira <akr@fsij.org>
* ext/pathname/pathname.c (path_pipe_p): Pathname#pipe? * ext/pathname/pathname.c (path_pipe_p): Pathname#pipe?

View File

@ -135,18 +135,6 @@ struct pty_info {
static void getDevice(int*, int*, char [DEVICELEN], int); static void getDevice(int*, int*, char [DEVICELEN], int);
struct exec_info {
int argc;
VALUE *argv;
};
static VALUE
pty_exec(VALUE v)
{
struct exec_info *arg = (struct exec_info *)v;
return rb_f_exec(arg->argc, arg->argv);
}
struct child_info { struct child_info {
int master, slave; int master, slave;
char *slavename; char *slavename;
@ -162,10 +150,7 @@ chfunc(void *data, char *errbuf, size_t errbuf_len)
int slave = carg->slave; int slave = carg->slave;
int argc = carg->argc; int argc = carg->argc;
VALUE *argv = carg->argv; VALUE *argv = carg->argv;
VALUE exc;
struct exec_info arg;
int status;
#define ERROR_EXIT(str) do { \ #define ERROR_EXIT(str) do { \
strlcpy(errbuf, str, errbuf_len); \ strlcpy(errbuf, str, errbuf_len); \
return -1; \ return -1; \
@ -218,16 +203,7 @@ chfunc(void *data, char *errbuf, size_t errbuf_len)
seteuid(getuid()); seteuid(getuid());
#endif #endif
arg.argc = argc; return rb_f_exec(argc, argv);
arg.argv = argv;
rb_protect(pty_exec, (VALUE)&arg, &status);
sleep(1);
errno = ENOENT; /* last resort */
exc = rb_errinfo();
if (!NIL_P(exc)) {
errno = NUM2INT(rb_attr_get(exc, rb_intern("errno")));
}
ERROR_EXIT(StringValueCStr(argv[0]));
#undef ERROR_EXIT #undef ERROR_EXIT
} }

88
io.c
View File

@ -556,30 +556,36 @@ wsplit_p(rb_io_t *fptr)
return fptr->mode & FMODE_WSPLIT; return fptr->mode & FMODE_WSPLIT;
} }
struct io_internal_struct { struct io_internal_read_struct {
int fd; int fd;
void *buf; void *buf;
size_t capa; size_t capa;
}; };
struct io_internal_write_struct {
int fd;
const void *buf;
size_t capa;
};
static VALUE static VALUE
internal_read_func(void *ptr) internal_read_func(void *ptr)
{ {
struct io_internal_struct *iis = (struct io_internal_struct*)ptr; struct io_internal_read_struct *iis = ptr;
return read(iis->fd, iis->buf, iis->capa); return read(iis->fd, iis->buf, iis->capa);
} }
static VALUE static VALUE
internal_write_func(void *ptr) internal_write_func(void *ptr)
{ {
struct io_internal_struct *iis = (struct io_internal_struct*)ptr; struct io_internal_write_struct *iis = ptr;
return write(iis->fd, iis->buf, iis->capa); return write(iis->fd, iis->buf, iis->capa);
} }
static ssize_t static ssize_t
rb_read_internal(int fd, void *buf, size_t count) rb_read_internal(int fd, void *buf, size_t count)
{ {
struct io_internal_struct iis; struct io_internal_read_struct iis;
iis.fd = fd; iis.fd = fd;
iis.buf = buf; iis.buf = buf;
iis.capa = count; iis.capa = count;
@ -588,9 +594,9 @@ rb_read_internal(int fd, void *buf, size_t count)
} }
static ssize_t static ssize_t
rb_write_internal(int fd, void *buf, size_t count) rb_write_internal(int fd, const void *buf, size_t count)
{ {
struct io_internal_struct iis; struct io_internal_write_struct iis;
iis.fd = fd; iis.fd = fd;
iis.buf = buf; iis.buf = buf;
iis.capa = count; iis.capa = count;
@ -816,7 +822,7 @@ make_writeconv(rb_io_t *fptr)
struct binwrite_arg { struct binwrite_arg {
rb_io_t *fptr; rb_io_t *fptr;
VALUE str; VALUE str;
long offset; const char *ptr;
long length; long length;
}; };
@ -825,15 +831,14 @@ io_binwrite_string(VALUE arg)
{ {
struct binwrite_arg *p = (struct binwrite_arg *)arg; struct binwrite_arg *p = (struct binwrite_arg *)arg;
long l = io_writable_length(p->fptr, p->length); long l = io_writable_length(p->fptr, p->length);
return rb_write_internal(p->fptr->fd, RSTRING_PTR(p->str)+p->offset, l); return rb_write_internal(p->fptr->fd, p->ptr, l);
} }
static long static long
io_binwrite(VALUE str, rb_io_t *fptr, int nosync) io_binwrite(VALUE str, const char *ptr, long len, rb_io_t *fptr, int nosync)
{ {
long len, n, r, offset = 0; long n, r, offset = 0;
len = RSTRING_LEN(str);
if ((n = len) <= 0) return n; if ((n = len) <= 0) return n;
if (fptr->wbuf == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) { if (fptr->wbuf == NULL && !(!nosync && (fptr->mode & FMODE_SYNC))) {
fptr->wbuf_off = 0; fptr->wbuf_off = 0;
@ -852,7 +857,7 @@ io_binwrite(VALUE str, rb_io_t *fptr, int nosync)
MEMMOVE(fptr->wbuf, fptr->wbuf+fptr->wbuf_off, char, fptr->wbuf_len); MEMMOVE(fptr->wbuf, fptr->wbuf+fptr->wbuf_off, char, fptr->wbuf_len);
fptr->wbuf_off = 0; fptr->wbuf_off = 0;
} }
MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, RSTRING_PTR(str)+offset, char, len); MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, ptr+offset, char, len);
fptr->wbuf_len += (int)len; fptr->wbuf_len += (int)len;
n = 0; n = 0;
} }
@ -868,14 +873,14 @@ io_binwrite(VALUE str, rb_io_t *fptr, int nosync)
arg.fptr = fptr; arg.fptr = fptr;
arg.str = str; arg.str = str;
retry: retry:
arg.offset = offset; arg.ptr = ptr + offset;
arg.length = n; arg.length = n;
if (fptr->write_lock) { if (fptr->write_lock) {
r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg); r = rb_mutex_synchronize(fptr->write_lock, io_binwrite_string, (VALUE)&arg);
} }
else { else {
long l = io_writable_length(fptr, n); long l = io_writable_length(fptr, n);
r = rb_write_internal(fptr->fd, RSTRING_PTR(str)+offset, l); r = rb_write_internal(fptr->fd, ptr+offset, l);
} }
/* xxx: other threads may modify given string. */ /* xxx: other threads may modify given string. */
if (r == n) return len; if (r == n) return len;
@ -886,7 +891,7 @@ io_binwrite(VALUE str, rb_io_t *fptr, int nosync)
} }
if (rb_io_wait_writable(fptr->fd)) { if (rb_io_wait_writable(fptr->fd)) {
rb_io_check_closed(fptr); rb_io_check_closed(fptr);
if (offset < RSTRING_LEN(str)) if (offset < len)
goto retry; goto retry;
} }
return -1L; return -1L;
@ -897,7 +902,7 @@ io_binwrite(VALUE str, rb_io_t *fptr, int nosync)
MEMMOVE(fptr->wbuf, fptr->wbuf+fptr->wbuf_off, char, fptr->wbuf_len); MEMMOVE(fptr->wbuf, fptr->wbuf+fptr->wbuf_off, char, fptr->wbuf_len);
fptr->wbuf_off = 0; fptr->wbuf_off = 0;
} }
MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, RSTRING_PTR(str)+offset, char, len); MEMMOVE(fptr->wbuf+fptr->wbuf_off+fptr->wbuf_len, ptr+offset, char, len);
fptr->wbuf_len += (int)len; fptr->wbuf_len += (int)len;
return len; return len;
} }
@ -941,7 +946,18 @@ static long
io_fwrite(VALUE str, rb_io_t *fptr, int nosync) io_fwrite(VALUE str, rb_io_t *fptr, int nosync)
{ {
str = do_writeconv(str, fptr); str = do_writeconv(str, fptr);
return io_binwrite(str, fptr, nosync); return io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str),
fptr, nosync);
}
ssize_t
rb_io_bufwrite(VALUE io, const void *buf, size_t size)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_writable(fptr);
return (ssize_t)io_binwrite(0, buf, (long)size, fptr, 0);
} }
static VALUE static VALUE
@ -1520,33 +1536,31 @@ read_buffered_data(char *ptr, long len, rb_io_t *fptr)
} }
static long static long
io_fread(VALUE str, long offset, rb_io_t *fptr) io_bufread(char *ptr, long len, rb_io_t *fptr)
{ {
long len = RSTRING_LEN(str) - offset; long offset = 0;
long n = len; long n = len;
long c; long c;
rb_str_locktmp(str);
if (READ_DATA_PENDING(fptr) == 0) { if (READ_DATA_PENDING(fptr) == 0) {
while (n > 0) { while (n > 0) {
again: again:
c = rb_read_internal(fptr->fd, RSTRING_PTR(str)+offset, n); c = rb_read_internal(fptr->fd, ptr+offset, n);
if (c == 0) break; if (c == 0) break;
if (c < 0) { if (c < 0) {
if (rb_io_wait_readable(fptr->fd)) if (rb_io_wait_readable(fptr->fd))
goto again; goto again;
rb_sys_fail_path(fptr->pathv); return -1;
} }
offset += c; offset += c;
if ((n -= c) <= 0) break; if ((n -= c) <= 0) break;
rb_thread_wait_fd(fptr->fd); rb_thread_wait_fd(fptr->fd);
} }
rb_str_unlocktmp(str);
return len - n; return len - n;
} }
while (n > 0) { while (n > 0) {
c = read_buffered_data(RSTRING_PTR(str)+offset, n, fptr); c = read_buffered_data(ptr+offset, n, fptr);
if (c > 0) { if (c > 0) {
offset += c; offset += c;
if ((n -= c) <= 0) break; if ((n -= c) <= 0) break;
@ -1557,10 +1571,32 @@ io_fread(VALUE str, long offset, rb_io_t *fptr)
break; break;
} }
} }
rb_str_unlocktmp(str);
return len - n; return len - n;
} }
static long
io_fread(VALUE str, long offset, rb_io_t *fptr)
{
long len;
rb_str_locktmp(str);
len = io_bufread(RSTRING_PTR(str) + offset, RSTRING_LEN(str) - offset,
fptr);
rb_str_unlocktmp(str);
if (len < 0) rb_sys_fail_path(fptr->pathv);
return len;
}
ssize_t
rb_io_bufread(VALUE io, void *buf, size_t size)
{
rb_io_t *fptr;
GetOpenFile(io, fptr);
rb_io_check_readable(fptr);
return (ssize_t)io_bufread(buf, (long)size, fptr);
}
#define SMALLBUF 100 #define SMALLBUF 100
static long static long
@ -8475,7 +8511,7 @@ copy_stream_body(VALUE arg)
rb_str_resize(str,len); rb_str_resize(str,len);
read_buffered_data(RSTRING_PTR(str), len, src_fptr); read_buffered_data(RSTRING_PTR(str), len, src_fptr);
if (dst_fptr) { /* IO or filename */ if (dst_fptr) { /* IO or filename */
if (io_binwrite(str, dst_fptr, 0) < 0) if (io_binwrite(str, RSTRING_PTR(str), RSTRING_LEN(str), dst_fptr, 0) < 0)
rb_sys_fail(0); rb_sys_fail(0);
} }
else /* others such as StringIO */ else /* others such as StringIO */

View File

@ -137,6 +137,9 @@ static VALUE rb_cProcessTms;
do {int saved_errno = errno; stmts; errno = saved_errno;} while (0) do {int saved_errno = errno; stmts; errno = saved_errno;} while (0)
ssize_t rb_io_bufwrite(VALUE io, const void *buf, size_t size);
ssize_t rb_io_bufread(VALUE io, void *buf, size_t size);
/* /*
* call-seq: * call-seq:
* Process.pid -> fixnum * Process.pid -> fixnum
@ -2430,6 +2433,25 @@ pipe_nocrash(int filedes[2], VALUE fds)
return ret; return ret;
} }
struct chfunc_protect_t {
int (*chfunc)(void*, char *, size_t);
void *arg;
char *errmsg;
size_t buflen;
};
static VALUE
chfunc_protect(VALUE arg)
{
struct chfunc_protect_t *p = (struct chfunc_protect_t *)arg;
return (VALUE)(*p->chfunc)(p->arg, p->errmsg, p->buflen);
}
#ifndef O_BINARY
#define O_BINARY 0
#endif
/* /*
* Forks child process, and returns the process ID in the parent * Forks child process, and returns the process ID in the parent
* process. * process.
@ -2461,6 +2483,7 @@ rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALU
int err, state = 0; int err, state = 0;
#ifdef FD_CLOEXEC #ifdef FD_CLOEXEC
int ep[2]; int ep[2];
VALUE io = Qnil;
#endif #endif
#define prefork() ( \ #define prefork() ( \
@ -2507,11 +2530,21 @@ rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALU
if (!pid) { if (!pid) {
forked_child = 1; forked_child = 1;
if (chfunc) { if (chfunc) {
struct chfunc_protect_t arg;
arg.chfunc = chfunc;
arg.arg = charg;
arg.errmsg = errmsg;
arg.buflen = errmsg_buflen;
#ifdef FD_CLOEXEC #ifdef FD_CLOEXEC
close(ep[0]); close(ep[0]);
#endif #endif
if (!(*chfunc)(charg, errmsg, errmsg_buflen)) _exit(EXIT_SUCCESS); if (!(int)rb_protect(chfunc_protect, (VALUE)&arg, &state)) _exit(EXIT_SUCCESS);
#ifdef FD_CLOEXEC #ifdef FD_CLOEXEC
if (write(ep[1], &state, sizeof(state)) == sizeof(state) && state) {
io = rb_io_fdopen(ep[1], O_WRONLY|O_BINARY, NULL);
rb_marshal_dump(rb_errinfo(), io);
rb_io_flush(io);
}
err = errno; err = errno;
if (write(ep[1], &err, sizeof(err)) < 0) err = errno; if (write(ep[1], &err, sizeof(err)) < 0) err = errno;
if (errmsg && 0 < errmsg_buflen) { if (errmsg && 0 < errmsg_buflen) {
@ -2520,6 +2553,7 @@ rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALU
if (errmsg_buflen > 0 &&write(ep[1], errmsg, errmsg_buflen) < 0) if (errmsg_buflen > 0 &&write(ep[1], errmsg, errmsg_buflen) < 0)
err = errno; err = errno;
} }
if (!NIL_P(io)) rb_io_close(io);
#endif #endif
#if EXIT_SUCCESS == 127 #if EXIT_SUCCESS == 127
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
@ -2532,25 +2566,37 @@ rb_fork_err(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALU
#ifdef FD_CLOEXEC #ifdef FD_CLOEXEC
if (pid && chfunc) { if (pid && chfunc) {
ssize_t size; ssize_t size;
VALUE exc = Qnil;
close(ep[1]); close(ep[1]);
if ((size = read(ep[0], &err, sizeof(err))) < 0) { if ((read(ep[0], &state, sizeof(state))) == sizeof(state) && state) {
io = rb_io_fdopen(ep[0], O_RDONLY|O_BINARY, NULL);
exc = rb_marshal_load(io);
rb_set_errinfo(exc);
}
#define READ_FROM_CHILD(ptr, len) \
(NIL_P(io) ? read(ep[0], ptr, len) : rb_io_bufread(io, ptr, len))
if ((size = READ_FROM_CHILD(&err, sizeof(err))) < 0) {
err = errno; err = errno;
} }
if (size == sizeof(err) && if (size == sizeof(err) &&
errmsg && 0 < errmsg_buflen) { errmsg && 0 < errmsg_buflen) {
ssize_t ret; ssize_t ret = READ_FROM_CHILD(errmsg, errmsg_buflen-1);
ret = read(ep[0], errmsg, errmsg_buflen-1);
if (0 <= ret) { if (0 <= ret) {
errmsg[ret] = '\0'; errmsg[ret] = '\0';
} }
} }
if (NIL_P(io))
close(ep[0]); close(ep[0]);
if (size) { else
rb_io_close(io);
if (state || size) {
if (status) { if (status) {
*status = state;
rb_protect(proc_syswait, (VALUE)pid, status); rb_protect(proc_syswait, (VALUE)pid, status);
} }
else { else {
rb_syswait(pid); rb_syswait(pid);
if (state) rb_exc_raise(exc);
} }
errno = err; errno = err;
return -1; return -1;