* io.c (fptr_copy_finalizer): remove fptr from pipe_list when pipe
  became ordinary file, to fix access after free.  to be finalized
  by pipe_finalize and being in pipe_list must match.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62123 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2018-01-31 08:17:16 +00:00
Родитель 302825ced8
Коммит 4057ee5e8e
2 изменённых файлов: 24 добавлений и 20 удалений

41
io.c
Просмотреть файл

@ -6194,22 +6194,31 @@ pipe_finalize(rb_io_t *fptr, int noraise)
#endif #endif
pipe_del_fptr(fptr); pipe_del_fptr(fptr);
} }
#endif
static void static void
pipe_register_fptr(rb_io_t *fptr) fptr_copy_finalizer(rb_io_t *fptr, const rb_io_t *orig)
{ {
struct pipe_list *list; #if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
void (*const old_finalize)(struct rb_io_t*,int) = fptr->finalize;
if (fptr->finalize != pipe_finalize) return;
for (list = pipe_list; list; list = list->next) {
if (list->fptr == fptr) return;
}
pipe_add_fptr(fptr);
}
#endif #endif
fptr->finalize = orig->finalize;
#if defined(__CYGWIN__) || !defined(HAVE_WORKING_FORK)
if (old_finalize == pipe_finalize) {
struct pipe_list *list;
for (list = pipe_list; list; list = list->next) {
if (list->fptr == fptr) break;
}
if (!list) pipe_add_fptr(fptr);
}
else {
pipe_del_fptr(fptr);
}
#endif
}
void void
rb_io_synchronized(rb_io_t *fptr) rb_io_synchronized(rb_io_t *fptr)
{ {
@ -7158,10 +7167,7 @@ io_reopen(VALUE io, VALUE nfile)
fptr->lineno = orig->lineno; fptr->lineno = orig->lineno;
if (RTEST(orig->pathv)) fptr->pathv = orig->pathv; if (RTEST(orig->pathv)) fptr->pathv = orig->pathv;
else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil; else if (!IS_PREP_STDIO(fptr)) fptr->pathv = Qnil;
fptr->finalize = orig->finalize; fptr_copy_finalizer(fptr, orig);
#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
pipe_register_fptr(fptr);
#endif
fd = fptr->fd; fd = fptr->fd;
fd2 = orig->fd; fd2 = orig->fd;
@ -7340,10 +7346,7 @@ rb_io_init_copy(VALUE dest, VALUE io)
fptr->pid = orig->pid; fptr->pid = orig->pid;
fptr->lineno = orig->lineno; fptr->lineno = orig->lineno;
if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv; if (!NIL_P(orig->pathv)) fptr->pathv = orig->pathv;
fptr->finalize = orig->finalize; fptr_copy_finalizer(fptr, orig);
#if defined (__CYGWIN__) || !defined(HAVE_WORKING_FORK)
pipe_register_fptr(fptr);
#endif
fd = ruby_dup(orig->fd); fd = ruby_dup(orig->fd);
fptr->fd = fd; fptr->fd = fd;

Просмотреть файл

@ -1814,8 +1814,9 @@ class TestProcess < Test::Unit::TestCase
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin; begin;
io = File.open(IO::NULL) io = File.open(IO::NULL)
io2 = io.dup
IO.popen("echo") {|f| io.reopen(f)} IO.popen("echo") {|f| io.reopen(f)}
io.reopen(io.dup) io.reopen(io2)
end; end;
end end