merge revision(s) 60055: [Backport #13856]

io.c: fix segfault with closing socket on Windows

	* io.c (fptr_finalize_flush): add an argument to keep GVL.
	* io.c (fptr_finalize): adjust for above change.
	* io.c (io_close_fptr): closing without GVL causes another
	  exception while raising exception in another thread. This causes
	  segfault on Windows. Keep GVL while closing when another thread
	  raises.
	  [Bug #13856] [ruby-core:82602]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_4@62690 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nagachika 2018-03-07 14:05:38 +00:00
parent 6d742295f3
commit 2921521e92
2 changed files with 14 additions and 7 deletions

15
io.c
View file

@ -4277,7 +4277,7 @@ static void free_io_buffer(rb_io_buffer_t *buf);
static void clear_codeconv(rb_io_t *fptr); static void clear_codeconv(rb_io_t *fptr);
static void static void
fptr_finalize_flush(rb_io_t *fptr, int noraise) fptr_finalize_flush(rb_io_t *fptr, int noraise, int keepgvl)
{ {
VALUE err = Qnil; VALUE err = Qnil;
int fd = fptr->fd; int fd = fptr->fd;
@ -4325,7 +4325,7 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise)
* We assumes it is closed. */ * We assumes it is closed. */
/**/ /**/
int keepgvl = !(mode & FMODE_WRITABLE); keepgvl |= !(mode & FMODE_WRITABLE);
keepgvl |= noraise; keepgvl |= noraise;
if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(err)) if ((maygvl_close(fd, keepgvl) < 0) && NIL_P(err))
err = noraise ? Qtrue : INT2NUM(errno); err = noraise ? Qtrue : INT2NUM(errno);
@ -4342,7 +4342,7 @@ fptr_finalize_flush(rb_io_t *fptr, int noraise)
static void static void
fptr_finalize(rb_io_t *fptr, int noraise) fptr_finalize(rb_io_t *fptr, int noraise)
{ {
fptr_finalize_flush(fptr, noraise); fptr_finalize_flush(fptr, noraise, FALSE);
free_io_buffer(&fptr->rbuf); free_io_buffer(&fptr->rbuf);
free_io_buffer(&fptr->wbuf); free_io_buffer(&fptr->wbuf);
clear_codeconv(fptr); clear_codeconv(fptr);
@ -4422,6 +4422,13 @@ rb_io_memsize(const rb_io_t *fptr)
return size; return size;
} }
#ifdef _WIN32
/* keep GVL while closing to prevent crash on Windows */
# define KEEPGVL TRUE
#else
# define KEEPGVL FALSE
#endif
int rb_notify_fd_close(int fd); int rb_notify_fd_close(int fd);
static rb_io_t * static rb_io_t *
io_close_fptr(VALUE io) io_close_fptr(VALUE io)
@ -4446,8 +4453,8 @@ io_close_fptr(VALUE io)
fd = fptr->fd; fd = fptr->fd;
busy = rb_notify_fd_close(fd); busy = rb_notify_fd_close(fd);
fptr_finalize_flush(fptr, FALSE);
if (busy) { if (busy) {
fptr_finalize_flush(fptr, FALSE, KEEPGVL);
do rb_thread_schedule(); while (rb_notify_fd_close(fd)); do rb_thread_schedule(); while (rb_notify_fd_close(fd));
} }
rb_io_fptr_cleanup(fptr, FALSE); rb_io_fptr_cleanup(fptr, FALSE);

View file

@ -1,10 +1,10 @@
#define RUBY_VERSION "2.4.4" #define RUBY_VERSION "2.4.4"
#define RUBY_RELEASE_DATE "2018-03-06" #define RUBY_RELEASE_DATE "2018-03-07"
#define RUBY_PATCHLEVEL 252 #define RUBY_PATCHLEVEL 253
#define RUBY_RELEASE_YEAR 2018 #define RUBY_RELEASE_YEAR 2018
#define RUBY_RELEASE_MONTH 3 #define RUBY_RELEASE_MONTH 3
#define RUBY_RELEASE_DAY 6 #define RUBY_RELEASE_DAY 7
#include "ruby/version.h" #include "ruby/version.h"