summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorshirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-05-08 12:47:25 +0000
committershirosaki <shirosaki@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-05-08 12:47:25 +0000
commit5ccee663e9150df0de86f8eaaebed079c7561186 (patch)
tree8477f16e57e17599013640fdda744a378678013e
parent7e134cf71e2535b562cd2d81e3ff69cbe49d0ce0 (diff)
* include/ruby/win32.h (FD_SET): change function to macro.
To avoid buffer overflow when smaller FD_SETSISE is used in ext libraries. * win32/win32.c (rb_w32_fdset): this function is not used anymore. But we leave this for compatibility. * win32/win32.c (rb_w32_select_with_thread): fix SEGV when smaller FD_SETSISE is used in ext libraries. Dereference of fd_set pointer causes SEGV. * test/-ext-/win32/test_fd_setsize.rb(TestFdSetSize): add tests for above. * ext/-test-/win32/fd_setsize/depend: ditto. * ext/-test-/win32/fd_setsize/extconf.rb: ditto. * ext/-test-/win32/fd_setsize/fd_setsize.c: ditto. [ruby-core:44588] [Bug #6352] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35595 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog21
-rw-r--r--ext/-test-/win32/fd_setsize/depend2
-rw-r--r--ext/-test-/win32/fd_setsize/extconf.rb3
-rw-r--r--ext/-test-/win32/fd_setsize/fd_setsize.c55
-rw-r--r--include/ruby/win32.h17
-rw-r--r--test/-ext-/win32/test_fd_setsize.rb25
-rw-r--r--win32/win32.c34
7 files changed, 134 insertions, 23 deletions
diff --git a/ChangeLog b/ChangeLog
index e68a7c30bf9..423b7077ef5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,24 @@
+Tue May 8 21:09:00 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com>
+
+ * include/ruby/win32.h (FD_SET): change function to macro.
+ To avoid buffer overflow when smaller FD_SETSISE is used in ext
+ libraries.
+
+ * win32/win32.c (rb_w32_fdset): this function is not used anymore.
+ But we leave this for compatibility.
+
+ * win32/win32.c (rb_w32_select_with_thread): fix SEGV when smaller
+ FD_SETSISE is used in ext libraries. Dereference of fd_set pointer
+ causes SEGV.
+
+ * test/-ext-/win32/test_fd_setsize.rb(TestFdSetSize): add tests for
+ above.
+ * ext/-test-/win32/fd_setsize/depend: ditto.
+ * ext/-test-/win32/fd_setsize/extconf.rb: ditto.
+ * ext/-test-/win32/fd_setsize/fd_setsize.c: ditto.
+
+ [ruby-core:44588] [Bug #6352]
+
Tue May 8 20:44:46 2012 Hiroshi Shirosaki <h.shirosaki@gmail.com>
* io.c (io_unread): fix IO#pos with mode 'r' bug on Windows.
diff --git a/ext/-test-/win32/fd_setsize/depend b/ext/-test-/win32/fd_setsize/depend
new file mode 100644
index 00000000000..4936d6b28c9
--- /dev/null
+++ b/ext/-test-/win32/fd_setsize/depend
@@ -0,0 +1,2 @@
+fd_setsize.o: $(top_srcdir)/win32/win32.c \
+ $(hdrdir)/ruby/ruby.h
diff --git a/ext/-test-/win32/fd_setsize/extconf.rb b/ext/-test-/win32/fd_setsize/extconf.rb
new file mode 100644
index 00000000000..ed40f8b1d7a
--- /dev/null
+++ b/ext/-test-/win32/fd_setsize/extconf.rb
@@ -0,0 +1,3 @@
+if $mingw or $mswin
+ create_makefile("-test-/win32/fd_setsize")
+end
diff --git a/ext/-test-/win32/fd_setsize/fd_setsize.c b/ext/-test-/win32/fd_setsize/fd_setsize.c
new file mode 100644
index 00000000000..8da8b1eaa09
--- /dev/null
+++ b/ext/-test-/win32/fd_setsize/fd_setsize.c
@@ -0,0 +1,55 @@
+#undef FD_SETSIZE
+/* redefine smaller size then default 64 */
+#define FD_SETSIZE 32
+#include <ruby.h>
+
+static VALUE
+test_select(VALUE self)
+{
+ int sd = socket(AF_INET, SOCK_DGRAM, 0);
+ struct timeval zero;
+ fd_set read;
+ fd_set write;
+ fd_set error;
+
+ zero.tv_sec = 0;
+ zero.tv_usec = 0;
+
+ FD_ZERO(&read);
+ FD_ZERO(&write);
+ FD_ZERO(&error);
+
+ FD_SET(sd, &read);
+ FD_SET(sd, &write);
+ FD_SET(sd, &error);
+
+ select(sd+1, &read, &write, &error, &zero);
+
+ return Qtrue;
+}
+
+static VALUE
+test_fdset(VALUE self)
+{
+ int i;
+ fd_set set;
+
+ FD_ZERO(&set);
+
+ for (i = 0; i < FD_SETSIZE * 2; i++) {
+ int sd = socket(AF_INET, SOCK_DGRAM, 0);
+ FD_SET(sd, &set);
+ if (set.fd_count > FD_SETSIZE) {
+ return Qfalse;
+ }
+ }
+ return Qtrue;
+}
+
+void
+Init_fd_setsize(void)
+{
+ VALUE m = rb_define_module_under(rb_define_module("Bug"), "Win32");
+ rb_define_module_function(m, "test_select", test_select, 0);
+ rb_define_module_function(m, "test_fdset", test_fdset, 0);
+}
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index 1f966484b8d..757d2f19e14 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -581,7 +581,22 @@ extern char *rb_w32_strerror(int);
#define O_NONBLOCK 1
#undef FD_SET
-#define FD_SET(f, s) rb_w32_fdset(f, s)
+#define FD_SET(fd, set) do {\
+ unsigned int i;\
+ SOCKET s = _get_osfhandle(fd);\
+\
+ for (i = 0; i < (set)->fd_count; i++) {\
+ if ((set)->fd_array[i] == s) {\
+ break;\
+ }\
+ }\
+ if (i == (set)->fd_count) {\
+ if ((set)->fd_count < FD_SETSIZE) {\
+ (set)->fd_array[i] = s;\
+ (set)->fd_count++;\
+ }\
+ }\
+} while(0)
#undef FD_CLR
#define FD_CLR(f, s) rb_w32_fdclr(f, s)
diff --git a/test/-ext-/win32/test_fd_setsize.rb b/test/-ext-/win32/test_fd_setsize.rb
new file mode 100644
index 00000000000..08819719691
--- /dev/null
+++ b/test/-ext-/win32/test_fd_setsize.rb
@@ -0,0 +1,25 @@
+require 'test/unit'
+require_relative '../../ruby/envutil'
+
+module Bug
+ module Win32
+ class TestFdSetSize < Test::Unit::TestCase
+ def test_select_with_unmatched_fd_setsize
+ bug6532 = '[ruby-core:44588]'
+ assert_in_out_err([], <<-INPUT, %w(:ok), [], bug6532)
+ require '-test-/win32/fd_setsize'
+ Bug::Win32.test_select
+ p :ok
+ INPUT
+ end
+
+ def test_fdset_with_unmatched_fd_setsize
+ bug6532 = '[ruby-core:44588]'
+ assert_in_out_err([], <<-INPUT, %w(:ok), [], bug6532)
+ require '-test-/win32/fd_setsize'
+ p :ok if Bug::Win32.test_fdset
+ INPUT
+ end
+ end
+ end
+end if /mswin|mingw/ =~ RUBY_PLATFORM
diff --git a/win32/win32.c b/win32/win32.c
index 50387844ab7..16ec249b4c5 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -2452,25 +2452,10 @@ ioctl(int i, int u, ...)
return -1;
}
-#undef FD_SET
-
void
rb_w32_fdset(int fd, fd_set *set)
{
- unsigned int i;
- SOCKET s = TO_SOCKET(fd);
-
- for (i = 0; i < set->fd_count; i++) {
- if (set->fd_array[i] == s) {
- return;
- }
- }
- if (i == set->fd_count) {
- if (set->fd_count < FD_SETSIZE) {
- set->fd_array[i] = s;
- set->fd_count++;
- }
- }
+ FD_SET(fd, set);
}
#undef FD_CLR
@@ -2868,14 +2853,19 @@ rb_w32_select_with_thread(int nfds, fd_set *rd, fd_set *wr, fd_set *ex,
fd_set orig_rd;
fd_set orig_wr;
fd_set orig_ex;
- if (rd) orig_rd = *rd;
- if (wr) orig_wr = *wr;
- if (ex) orig_ex = *ex;
+
+ FD_ZERO(&orig_rd);
+ FD_ZERO(&orig_wr);
+ FD_ZERO(&orig_ex);
+
+ if (rd) copy_fd(&orig_rd, rd);
+ if (wr) copy_fd(&orig_wr, wr);
+ if (ex) copy_fd(&orig_ex, ex);
r = do_select(nfds, rd, wr, ex, &zero); // polling
if (r != 0) break; // signaled or error
- if (rd) *rd = orig_rd;
- if (wr) *wr = orig_wr;
- if (ex) *ex = orig_ex;
+ if (rd) copy_fd(rd, &orig_rd);
+ if (wr) copy_fd(wr, &orig_wr);
+ if (ex) copy_fd(ex, &orig_ex);
if (timeout) {
struct timeval now;