Hi All, On 06/28/2016 01:59 PM, Bálint Réczey wrote: > Hi Christian, > > 2016-06-28 7:27 GMT+02:00 Christian Hofstaedtler <[email protected]>: >> Hi, >> >> * Bálint Réczey <[email protected]> [160628 00:28]: >>> Dear Ruby and LTS Maintainers, >>> >>> I plan updating the ruby-eventmachine package in Wheezy LTS to >>> fix the following security issue: >>> https://security-tracker.debian.org/tracker/TEMP-0678512-2E167C >>> >>> Please see the diff to previous version attached. > > Thanks! I also tried the new test without fixing the issue in the code > and it crashes nicely. > >> >> Only gave this a quick glance, but LGTM. >> >>> I plan updating Jessie's version through jessie-proposed-updates, since >>> the issue is marked as no-DSA. >> >> This can probably still go through debian-security? > > I'll ask them, showing the proposed diff.
I asked, but here is no clear new decision regarding handling the issue in Jessie. > >> Also, given there's no ruby1.8 in jessie, the diff will be a lot >> smaller I guess. > > IMO the difference is very small and I'd rather add the few macros for 1.8 > than breaking the source package's compatibility with the update. > > I have pushed my changes to the packaging repository in two new branches here: > https://anonscm.debian.org/cgit/pkg-ruby-extras/ruby-eventmachine.git While reading all the bug reports related to the crash I noticed that the fix introduced a memory leak which is fixed in successive commits. I have added them to the update growing it significantly, but at least we don't introduce a regression with the fix. Please see the diff attached and also in the git repository as separate commits. Cheers, Balint
diff -Nru ruby-eventmachine-0.12.10/debian/changelog ruby-eventmachine-0.12.10/debian/changelog --- ruby-eventmachine-0.12.10/debian/changelog 2012-06-20 16:21:30.000000000 +0200 +++ ruby-eventmachine-0.12.10/debian/changelog 2016-06-29 22:53:09.000000000 +0200 @@ -1,3 +1,14 @@ +ruby-eventmachine (0.12.10-3+deb7u1) wheezy-security; urgency=medium + + * Fix remotely triggerable crash due to FD handling + (Closes: #678512, #696015) + * Add net-tools to build dependencies to let tests run + * Run all tests in tests/ directory + * Skip tests requiring network connection + * Fix memory leak caused when fixing crash + + -- Balint Reczey <[email protected]> Wed, 29 Jun 2016 21:21:12 +0200 + ruby-eventmachine (0.12.10-3) unstable; urgency=low * Add myself to uploaders. diff -Nru ruby-eventmachine-0.12.10/debian/control ruby-eventmachine-0.12.10/debian/control --- ruby-eventmachine-0.12.10/debian/control 2012-06-20 16:21:30.000000000 +0200 +++ ruby-eventmachine-0.12.10/debian/control 2016-06-29 22:53:09.000000000 +0200 @@ -3,7 +3,7 @@ Priority: optional Maintainer: Debian Ruby Extras Maintainers <[email protected]> Uploaders: Daigo Moriwaki <[email protected]>, Ryan Niebur <[email protected]>, Laurent Arnoud <[email protected]>, Paul van Tilburg <[email protected]>, Per Andersson <[email protected]> -Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.2.7~) +Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.2.7~), net-tools Standards-Version: 3.9.3 Homepage: http://rubyeventmachine.com/ Vcs-Git: git://git.debian.org/pkg-ruby-extras/ruby-eventmachine.git diff -Nru ruby-eventmachine-0.12.10/debian/patches/0002-use-ruby-select-api-with-expandable-fd-sets.patch ruby-eventmachine-0.12.10/debian/patches/0002-use-ruby-select-api-with-expandable-fd-sets.patch --- ruby-eventmachine-0.12.10/debian/patches/0002-use-ruby-select-api-with-expandable-fd-sets.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0002-use-ruby-select-api-with-expandable-fd-sets.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,158 @@ +From bd881bb291b30bf9de71d6ab45caa69f25707577 Mon Sep 17 00:00:00 2001 +From: Patrick Reynolds <[email protected]> +Date: Tue, 11 Mar 2014 16:01:25 -0500 +Subject: [PATCH 2/4] use ruby select api with expandable fd sets + +Conflicts: + ext/em.cpp + ext/em.h +--- + ext/em.cpp | 30 +++++++++++++++--------------- + ext/em.h | 10 +++++----- + tests/test_many_fds.rb | 22 ++++++++++++++++++++++ + 3 files changed, 42 insertions(+), 20 deletions(-) + create mode 100644 tests/test_many_fds.rb + +--- a/ext/em.cpp ++++ b/ext/em.cpp +@@ -774,9 +774,9 @@ + SelectData_t::SelectData_t() + { + maxsocket = 0; +- FD_ZERO (&fdreads); +- FD_ZERO (&fdwrites); +- FD_ZERO (&fderrors); ++ rb_fd_init (&fdreads); ++ rb_fd_init (&fdwrites); ++ rb_fd_init (&fderrors); + } + + +@@ -789,7 +789,7 @@ + static VALUE _SelectDataSelect (void *v) + { + SelectData_t *sd = (SelectData_t*)v; +- sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv)); ++ sd->nSockets = rb_fd_select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv)); + return Qnil; + } + #endif +@@ -850,9 +850,9 @@ + + SelectData_t SelectData; + /* +- fd_set fdreads, fdwrites; +- FD_ZERO (&fdreads); +- FD_ZERO (&fdwrites); ++ rb_fdset_t fdreads, fdwrites; ++ rb_fd_init (&fdreads); ++ rb_fd_init (&fdwrites); + + int maxsocket = 0; + */ +@@ -862,7 +862,7 @@ + // running on localhost with a randomly-chosen port. (*Puke*) + // Windows has a version of the Unix pipe() library function, but it doesn't + // give you back descriptors that are selectable. +- FD_SET (LoopBreakerReader, &(SelectData.fdreads)); ++ rb_fd_set (LoopBreakerReader, &(SelectData.fdreads)); + if (SelectData.maxsocket < LoopBreakerReader) + SelectData.maxsocket = LoopBreakerReader; + +@@ -877,15 +877,15 @@ + assert (sd != INVALID_SOCKET); + + if (ed->SelectForRead()) +- FD_SET (sd, &(SelectData.fdreads)); ++ rb_fd_set (sd, &(SelectData.fdreads)); + if (ed->SelectForWrite()) +- FD_SET (sd, &(SelectData.fdwrites)); ++ rb_fd_set (sd, &(SelectData.fdwrites)); + + #ifdef OS_WIN32 + /* 21Sep09: on windows, a non-blocking connect() that fails does not come up as writable. + Instead, it is added to the error set. See http://www.mail-archive.com/[email protected]/msg58500.html + */ +- FD_SET (sd, &(SelectData.fderrors)); ++ rb_fd_set (sd, &(SelectData.fderrors)); + #endif + + if (SelectData.maxsocket < sd) +@@ -920,15 +920,15 @@ + continue; + assert (sd != INVALID_SOCKET); + +- if (FD_ISSET (sd, &(SelectData.fdwrites))) ++ if (rb_fd_isset (sd, &(SelectData.fdwrites))) + ed->Write(); +- if (FD_ISSET (sd, &(SelectData.fdreads))) ++ if (rb_fd_isset (sd, &(SelectData.fdreads))) + ed->Read(); +- if (FD_ISSET (sd, &(SelectData.fderrors))) ++ if (rb_fd_isset (sd, &(SelectData.fderrors))) + ed->HandleError(); + } + +- if (FD_ISSET (LoopBreakerReader, &(SelectData.fdreads))) ++ if (rb_fd_isset (LoopBreakerReader, &(SelectData.fdreads))) + _ReadLoopBreaker(); + } + else if (s < 0) { +--- a/ext/em.h ++++ b/ext/em.h +@@ -32,7 +32,7 @@ + + #ifdef BUILD_FOR_RUBY + #include <ruby.h> +- #define EmSelect rb_thread_select ++ #define EmSelect rb_thread_fd_select + + #if defined(HAVE_RBTRAP) + #include <rubysig.h> +@@ -54,7 +54,7 @@ + #define RUBY_UBF_IO RB_UBF_DFL + #endif + #else +- #define EmSelect select ++ #define EmSelect rb_fd_select + #endif + + class EventableDescriptor; +@@ -227,9 +227,9 @@ + int _Select(); + + int maxsocket; +- fd_set fdreads; +- fd_set fdwrites; +- fd_set fderrors; ++ rb_fdset_t fdreads; ++ rb_fdset_t fdwrites; ++ rb_fdset_t fderrors; + timeval tv; + int nSockets; + }; +--- /dev/null ++++ b/tests/test_many_fds.rb +@@ -0,0 +1,22 @@ ++require 'em_test_helper' ++require 'socket' ++ ++class TestManyFDs < Test::Unit::TestCase ++ def setup ++ @port = next_port ++ end ++ ++ def test_connection_class_cache ++ mod = Module.new ++ a = nil ++ Process.setrlimit(Process::RLIMIT_NOFILE,4096); ++ EM.run { ++ EM.start_server '127.0.0.1', @port, mod ++ 1100.times do ++ a = EM.connect '127.0.0.1', @port, mod ++ assert_kind_of EM::Connection, a ++ end ++ EM.stop ++ } ++ end ++end diff -Nru ruby-eventmachine-0.12.10/debian/patches/0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch ruby-eventmachine-0.12.10/debian/patches/0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch --- ruby-eventmachine-0.12.10/debian/patches/0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,40 @@ +From 0313f9e909f8c307563826e0e363cfdbf5ff3372 Mon Sep 17 00:00:00 2001 +From: Patrick Reynolds <[email protected]> +Date: Wed, 12 Mar 2014 00:15:41 -0500 +Subject: [PATCH 3/4] add stubs with warnings for 1.8.7 and 1.9.0 + +Conflicts: + ext/em.h +--- + ext/em.h | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +--- a/ext/em.h ++++ b/ext/em.h +@@ -60,6 +60,26 @@ + class EventableDescriptor; + class InotifyDescriptor; + ++#ifndef rb_fd_max ++#define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n))) ++typedef fd_set rb_fdset_t; ++#define rb_fd_zero(f) FD_ZERO(f) ++#define rb_fd_set(n, f) do { if (fd_check(n)) FD_SET((n), (f)); } while(0) ++#define rb_fd_clr(n, f) do { if (fd_check(n)) FD_CLR((n), (f)); } while(0) ++#define rb_fd_isset(n, f) (fd_check(n) ? FD_ISSET((n), (f)) : 0) ++#define rb_fd_copy(d, s, n) (*(d) = *(s)) ++#define rb_fd_dup(d, s) (*(d) = *(s)) ++#define rb_fd_resize(n, f) ((void)(f)) ++#define rb_fd_ptr(f) (f) ++#define rb_fd_init(f) FD_ZERO(f) ++#define rb_fd_init_copy(d, s) (*(d) = *(s)) ++#define rb_fd_term(f) ((void)(f)) ++#define rb_fd_max(f) FD_SETSIZE ++#define rb_fd_select(n, rfds, wfds, efds, timeout) \ ++ select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout)) ++#define rb_thread_fd_select(n, rfds, wfds, efds, timeout) \ ++ rb_thread_select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout)) ++#endif + + /******************** + class EventMachine_t diff -Nru ruby-eventmachine-0.12.10/debian/patches/0004-add-comment-about-where-the-macros-came-from.patch ruby-eventmachine-0.12.10/debian/patches/0004-add-comment-about-where-the-macros-came-from.patch --- ruby-eventmachine-0.12.10/debian/patches/0004-add-comment-about-where-the-macros-came-from.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0004-add-comment-about-where-the-macros-came-from.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,21 @@ +From 05b66f11c27e2df9e9e2d7ff75f0f42d258856d7 Mon Sep 17 00:00:00 2001 +From: Patrick Reynolds <[email protected]> +Date: Wed, 21 Jan 2015 22:34:43 -0600 +Subject: [PATCH 4/4] add comment about where the macros came from + +--- + ext/em.h | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/ext/em.h ++++ b/ext/em.h +@@ -62,6 +62,9 @@ + + #ifndef rb_fd_max + #define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n))) ++// These definitions are cribbed from include/ruby/intern.h in Ruby 1.9.3, ++// with this change: any macros that read or write the nth element of an ++// fdset first call fd_check to make sure n is in bounds. + typedef fd_set rb_fdset_t; + #define rb_fd_zero(f) FD_ZERO(f) + #define rb_fd_set(n, f) do { if (fd_check(n)) FD_SET((n), (f)); } while(0) diff -Nru ruby-eventmachine-0.12.10/debian/patches/0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch ruby-eventmachine-0.12.10/debian/patches/0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch --- ruby-eventmachine-0.12.10/debian/patches/0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,173 @@ +From d5eec7b64c42edce688ef1d60e9900d66848b35f Mon Sep 17 00:00:00 2001 +From: Balint Reczey <[email protected]> +Date: Mon, 27 Jun 2016 22:48:38 +0200 +Subject: [PATCH 5/5] Back-port em_test_helper.rb for test_many_fds.rb + +--- + tests/em_test_helper.rb | 154 ++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 154 insertions(+) + create mode 100644 tests/em_test_helper.rb + +diff --git a/tests/em_test_helper.rb b/tests/em_test_helper.rb +new file mode 100644 +index 0000000..20a3e59 +--- /dev/null ++++ b/tests/em_test_helper.rb +@@ -0,0 +1,154 @@ ++require 'em/pure_ruby' if ENV['EM_PURE_RUBY'] ++require 'eventmachine' ++require 'test/unit' ++require 'rbconfig' ++require 'socket' ++ ++puts "EM Library Type: #{EM.library_type}" ++ ++class Test::Unit::TestCase ++ class EMTestTimeout < StandardError ; end ++ ++ def setup_timeout(timeout = TIMEOUT_INTERVAL) ++ EM.schedule { ++ EM.add_timer(timeout) { ++ raise EMTestTimeout, "Test was cancelled after #{timeout} seconds." ++ } ++ } ++ end ++ ++ def port_in_use?(port, host="127.0.0.1") ++ s = TCPSocket.new(host, port) ++ s.close ++ s ++ rescue Errno::ECONNREFUSED ++ false ++ end ++ ++ def next_port ++ @@port ||= 9000 ++ begin ++ @@port += 1 ++ end while port_in_use?(@@port) ++ ++ @@port ++ end ++ ++ # Returns true if the host have a localhost 127.0.0.1 IPv4. ++ def self.local_ipv4? ++ return @@has_local_ipv4 if defined?(@@has_local_ipv4) ++ begin ++ get_my_ipv4_address "127.0.0.1" ++ @@has_local_ipv4 = true ++ rescue ++ @@has_local_ipv4 = false ++ end ++ end ++ ++ # Returns true if the host have a public IPv4 and stores it in ++ # @@public_ipv4. ++ def self.public_ipv4? ++ return @@has_public_ipv4 if defined?(@@has_public_ipv4) ++ begin ++ @@public_ipv4 = get_my_ipv4_address "1.2.3.4" ++ @@has_public_ipv4 = true ++ rescue ++ @@has_public_ipv4 = false ++ end ++ end ++ ++ # Returns true if the host have a localhost ::1 IPv6. ++ def self.local_ipv6? ++ return @@has_local_ipv6 if defined?(@@has_local_ipv6) ++ begin ++ get_my_ipv6_address "::1" ++ @@has_local_ipv6 = true ++ rescue ++ @@has_local_ipv6 = false ++ end ++ end ++ ++ # Returns true if the host have a public IPv6 and stores it in ++ # @@public_ipv6. ++ def self.public_ipv6? ++ return @@has_public_ipv6 if defined?(@@has_public_ipv6) ++ begin ++ @@public_ipv6 = get_my_ipv6_address "2001::1" ++ @@has_public_ipv6 = true ++ rescue ++ @@has_public_ipv6 = false ++ end ++ end ++ ++ # Returns an array with the localhost addresses (IPv4 and/or IPv6). ++ def local_ips ++ return @@local_ips if defined?(@@local_ips) ++ @@local_ips = [] ++ @@local_ips << "127.0.0.1" if self.class.local_ipv4? ++ @@local_ips << "::1" if self.class.local_ipv6? ++ @@local_ips ++ end ++ ++ def exception_class ++ jruby? ? NativeException : RuntimeError ++ end ++ ++ module PlatformHelper ++ # http://blog.emptyway.com/2009/11/03/proper-way-to-detect-windows-platform-in-ruby/ ++ def windows? ++ RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ++ end ++ ++ def solaris? ++ RUBY_PLATFORM =~ /solaris/ ++ end ++ ++ # http://stackoverflow.com/questions/1342535/how-can-i-tell-if-im-running-from-jruby-vs-ruby/1685970#1685970 ++ def jruby? ++ defined? JRUBY_VERSION ++ end ++ ++ def rbx? ++ defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx' ++ end ++ end ++ ++ include PlatformHelper ++ extend PlatformHelper ++ ++ # Tests run significantly slower on windows. YMMV ++ TIMEOUT_INTERVAL = windows? ? 1 : 0.25 ++ ++ def silent ++ backup, $VERBOSE = $VERBOSE, nil ++ begin ++ yield ++ ensure ++ $VERBOSE = backup ++ end ++ end ++ ++ ++ private ++ ++ def self.get_my_ipv4_address ip ++ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily ++ UDPSocket.open(Socket::AF_INET) do |s| ++ s.connect ip, 1 ++ s.addr.last ++ end ++ ensure ++ Socket.do_not_reverse_lookup = orig ++ end ++ ++ def self.get_my_ipv6_address ip ++ orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true # turn off reverse DNS resolution temporarily ++ UDPSocket.open(Socket::AF_INET6) do |s| ++ s.connect ip, 1 ++ s.addr.last ++ end ++ ensure ++ Socket.do_not_reverse_lookup = orig ++ end ++ ++end +-- +2.1.4 + diff -Nru ruby-eventmachine-0.12.10/debian/patches/0006-must-call-raw-select-from-thread_blocking_region.patch ruby-eventmachine-0.12.10/debian/patches/0006-must-call-raw-select-from-thread_blocking_region.patch --- ruby-eventmachine-0.12.10/debian/patches/0006-must-call-raw-select-from-thread_blocking_region.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0006-must-call-raw-select-from-thread_blocking_region.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,20 @@ +From a648e7a8e10b3c3fe7331568af3044834614a781 Mon Sep 17 00:00:00 2001 +From: Aman Gupta <[email protected]> +Date: Mon, 9 Feb 2015 22:29:00 -0800 +Subject: [PATCH 06/12] must call raw select() from thread_blocking_region + +--- + ext/em.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/ext/em.cpp ++++ b/ext/em.cpp +@@ -789,7 +789,7 @@ + static VALUE _SelectDataSelect (void *v) + { + SelectData_t *sd = (SelectData_t*)v; +- sd->nSockets = rb_fd_select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv)); ++ sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv)); + return Qnil; + } + #endif diff -Nru ruby-eventmachine-0.12.10/debian/patches/0007-epoll-kqueue-on-older-rubies-without-rb_wait_for_sin.patch ruby-eventmachine-0.12.10/debian/patches/0007-epoll-kqueue-on-older-rubies-without-rb_wait_for_sin.patch --- ruby-eventmachine-0.12.10/debian/patches/0007-epoll-kqueue-on-older-rubies-without-rb_wait_for_sin.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0007-epoll-kqueue-on-older-rubies-without-rb_wait_for_sin.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,30 @@ +From 82d690c972281df959762b814db02d2a5b6f7f4b Mon Sep 17 00:00:00 2001 +From: Aman Gupta <[email protected]> +Date: Mon, 9 Feb 2015 22:31:25 -0800 +Subject: [PATCH 07/12] epoll/kqueue on older rubies (without + rb_wait_for_single_fd) should use rb_thread_select with regular fdset + +epoll/kqueue fds are created early during ruby boot, so it is highly +unlikely that they will ever overflow FD_SETSIZE + +Conflicts: + ext/em.cpp +--- + ext/em.cpp | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/ext/em.cpp ++++ b/ext/em.cpp +@@ -850,9 +850,9 @@ + + SelectData_t SelectData; + /* +- rb_fdset_t fdreads, fdwrites; +- rb_fd_init (&fdreads); +- rb_fd_init (&fdwrites); ++ fd_set fdreads, fdwrites; ++ FD_ZERO (&fdreads); ++ FD_ZERO (&fdwrites); + + int maxsocket = 0; + */ diff -Nru ruby-eventmachine-0.12.10/debian/patches/0008-make-sure-to-clean-up-rb_fd_init-memory-during-shutd.patch ruby-eventmachine-0.12.10/debian/patches/0008-make-sure-to-clean-up-rb_fd_init-memory-during-shutd.patch --- ruby-eventmachine-0.12.10/debian/patches/0008-make-sure-to-clean-up-rb_fd_init-memory-during-shutd.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0008-make-sure-to-clean-up-rb_fd_init-memory-during-shutd.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,35 @@ +From 8cc177a151f77f07ce7fb32aab746b972d0d74cc Mon Sep 17 00:00:00 2001 +From: Aman Gupta <[email protected]> +Date: Mon, 9 Feb 2015 22:32:19 -0800 +Subject: [PATCH 08/12] make sure to clean up rb_fd_init memory during shutdown + +--- + ext/em.cpp | 6 ++++++ + ext/em.h | 1 + + 2 files changed, 7 insertions(+) + +--- a/ext/em.cpp ++++ b/ext/em.cpp +@@ -779,6 +779,12 @@ + rb_fd_init (&fderrors); + } + ++SelectData_t::~SelectData_t() ++{ ++ rb_fd_term (&fdreads); ++ rb_fd_term (&fdwrites); ++ rb_fd_term (&fderrors); ++} + + #ifdef BUILD_FOR_RUBY + /***************** +--- a/ext/em.h ++++ b/ext/em.h +@@ -246,6 +246,7 @@ + struct SelectData_t + { + SelectData_t(); ++ ~SelectData_t(); + + int _Select(); + diff -Nru ruby-eventmachine-0.12.10/debian/patches/0009-keep-BUILD_FOR_RUBY-compat.patch ruby-eventmachine-0.12.10/debian/patches/0009-keep-BUILD_FOR_RUBY-compat.patch --- ruby-eventmachine-0.12.10/debian/patches/0009-keep-BUILD_FOR_RUBY-compat.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0009-keep-BUILD_FOR_RUBY-compat.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,27 @@ +From e95f0f5e21d5620b9b0429677fbd0b949222f2d1 Mon Sep 17 00:00:00 2001 +From: Aman Gupta <[email protected]> +Date: Mon, 9 Feb 2015 22:40:10 -0800 +Subject: [PATCH 09/12] keep BUILD_FOR_RUBY compat + +--- + ext/em.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/ext/em.h ++++ b/ext/em.h +@@ -54,13 +54,13 @@ + #define RUBY_UBF_IO RB_UBF_DFL + #endif + #else +- #define EmSelect rb_fd_select ++ #define EmSelect select + #endif + + class EventableDescriptor; + class InotifyDescriptor; + +-#ifndef rb_fd_max ++#if defined(BUILD_FOR_RUBY) && !defined(rb_fd_max) + #define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n))) + // These definitions are cribbed from include/ruby/intern.h in Ruby 1.9.3, + // with this change: any macros that read or write the nth element of an diff -Nru ruby-eventmachine-0.12.10/debian/patches/0010-use-rb_thread_fd_select-whenever-possible.patch ruby-eventmachine-0.12.10/debian/patches/0010-use-rb_thread_fd_select-whenever-possible.patch --- ruby-eventmachine-0.12.10/debian/patches/0010-use-rb_thread_fd_select-whenever-possible.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0010-use-rb_thread_fd_select-whenever-possible.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,35 @@ +From d0f66631518907e4b10437fc046543ae99ffa2bb Mon Sep 17 00:00:00 2001 +From: Aman Gupta <[email protected]> +Date: Mon, 9 Feb 2015 23:24:32 -0800 +Subject: [PATCH 10/12] use rb_thread_fd_select whenever possible + +Conflicts: + ext/em.cpp +--- + ext/em.cpp | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +--- a/ext/em.cpp ++++ b/ext/em.cpp +@@ -791,7 +791,7 @@ + _SelectDataSelect + *****************/ + +-#ifdef HAVE_TBR ++#if !defined(HAVE_RB_THREAD_FD_SELECT) && defined(HAVE_TBR) + static VALUE _SelectDataSelect (void *v) + { + SelectData_t *sd = (SelectData_t*)v; +@@ -806,7 +806,11 @@ + + int SelectData_t::_Select() + { +- #ifdef HAVE_TBR ++ #if defined(HAVE_RB_THREAD_FD_SELECT) ++ // added in ruby 1.9.2 ++ return rb_thread_fd_select (maxsocket+1, &fdreads, &fdwrites, &fderrors, &tv); ++ #elif defined(HAVE_TBR) ++ // added in ruby 1.9.1, deprecated in ruby 2.0.0 + rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0); + return nSockets; + #endif diff -Nru ruby-eventmachine-0.12.10/debian/patches/0011-fix-build-on-ruby-1.9.1.patch ruby-eventmachine-0.12.10/debian/patches/0011-fix-build-on-ruby-1.9.1.patch --- ruby-eventmachine-0.12.10/debian/patches/0011-fix-build-on-ruby-1.9.1.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0011-fix-build-on-ruby-1.9.1.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,68 @@ +From 8b656c4f9b77f0674f28d32d5fe4644c8e655b67 Mon Sep 17 00:00:00 2001 +From: Aman Gupta <[email protected]> +Date: Mon, 9 Feb 2015 23:45:00 -0800 +Subject: [PATCH 11/12] fix build on ruby 1.9.1 + +Conflicts: + ext/extconf.rb +--- + ext/em.cpp | 2 +- + ext/em.h | 9 +++++++-- + ext/extconf.rb | 5 ++++- + 3 files changed, 12 insertions(+), 4 deletions(-) + +--- a/ext/em.cpp ++++ b/ext/em.cpp +@@ -795,7 +795,7 @@ + static VALUE _SelectDataSelect (void *v) + { + SelectData_t *sd = (SelectData_t*)v; +- sd->nSockets = select (sd->maxsocket+1, &(sd->fdreads), &(sd->fdwrites), &(sd->fderrors), &(sd->tv)); ++ sd->nSockets = select (sd->maxsocket+1, rb_fd_ptr(&(sd->fdreads)), rb_fd_ptr(&(sd->fdwrites)), rb_fd_ptr(&(sd->fderrors)), &(sd->tv)); + return Qnil; + } + #endif +--- a/ext/em.h ++++ b/ext/em.h +@@ -32,7 +32,12 @@ + + #ifdef BUILD_FOR_RUBY + #include <ruby.h> +- #define EmSelect rb_thread_fd_select ++ #ifdef HAVE_RB_THREAD_FD_SELECT ++ #define EmSelect rb_thread_fd_select ++ #else ++ // ruby 1.9.1 and below ++ #define EmSelect rb_thread_select ++ #endif + + #if defined(HAVE_RBTRAP) + #include <rubysig.h> +@@ -60,7 +65,7 @@ + class EventableDescriptor; + class InotifyDescriptor; + +-#if defined(BUILD_FOR_RUBY) && !defined(rb_fd_max) ++#if defined(BUILD_FOR_RUBY) && !defined(HAVE_RB_FDSET_T) + #define fd_check(n) (((n) < FD_SETSIZE) ? 1 : 0*fprintf(stderr, "fd %d too large for select\n", (n))) + // These definitions are cribbed from include/ruby/intern.h in Ruby 1.9.3, + // with this change: any macros that read or write the nth element of an +--- a/ext/extconf.rb ++++ b/ext/extconf.rb +@@ -19,6 +19,9 @@ + add_define "HAVE_OLD_INOTIFY" if !inotify && have_macro('__NR_inotify_init', 'sys/syscall.h') + add_define 'HAVE_WRITEV' if have_func('writev', 'sys/uio.h') + have_func('rb_thread_check_ints') ++add_define 'HAVE_RB_THREAD_FD_SELECT' if have_func('rb_thread_fd_select') ++add_define 'HAVE_RB_FDSET_T' if have_type('rb_fdset_t', 'ruby/intern.h') ++ + have_func('rb_time_new') + + # Minor platform details between *nix and Windows: +@@ -147,4 +150,4 @@ + SRC + TRY_LINK.sub!('$(CXX)', '$(CC)') + +-create_makefile "rubyeventmachine" +\ No newline at end of file ++create_makefile "rubyeventmachine" diff -Nru ruby-eventmachine-0.12.10/debian/patches/0012-allocate-one-SelectData_t-per-reactor-to-avoid-heap-.patch ruby-eventmachine-0.12.10/debian/patches/0012-allocate-one-SelectData_t-per-reactor-to-avoid-heap-.patch --- ruby-eventmachine-0.12.10/debian/patches/0012-allocate-one-SelectData_t-per-reactor-to-avoid-heap-.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/0012-allocate-one-SelectData_t-per-reactor-to-avoid-heap-.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,158 @@ +From b5dc0f5675d501e3371a2a061f9b7b0aab3b8093 Mon Sep 17 00:00:00 2001 +From: Aman Gupta <[email protected]> +Date: Mon, 9 Feb 2015 23:59:11 -0800 +Subject: [PATCH 12/12] allocate one SelectData_t per reactor to avoid heap + allocation on every tick + +Conflicts: + ext/em.cpp + ext/em.h +--- + ext/em.cpp | 60 +++++++++++++++++++----------------------------------------- + ext/em.h | 4 +++- + 2 files changed, 22 insertions(+), 42 deletions(-) + +--- a/ext/em.cpp ++++ b/ext/em.cpp +@@ -100,6 +100,7 @@ + #endif + + _InitializeLoopBreaker(); ++ SelectData = new SelectData_t(); + } + + +@@ -129,6 +130,8 @@ + close (epfd); + if (kqfd != -1) + close (kqfd); ++ ++ delete SelectData; + } + + +@@ -838,43 +841,18 @@ + // epoll will be effective if we provide it as an alternative, + // however it has the same problem interoperating with Ruby + // threads that select does. +- +- //cerr << "X"; +- +- /* This protection is now obsolete, because we will ALWAYS +- * have at least one descriptor (the loop-breaker) to read. +- */ +- /* +- if (Descriptors.size() == 0) { +- #ifdef OS_UNIX +- timeval tv = {0, 200 * 1000}; +- EmSelect (0, NULL, NULL, NULL, &tv); +- return true; +- #endif +- #ifdef OS_WIN32 +- Sleep (200); +- return true; +- #endif +- } +- */ +- +- SelectData_t SelectData; +- /* +- fd_set fdreads, fdwrites; +- FD_ZERO (&fdreads); +- FD_ZERO (&fdwrites); +- +- int maxsocket = 0; +- */ ++ rb_fd_zero (&SelectData->fdreads); ++ rb_fd_zero (&SelectData->fdwrites); ++ rb_fd_zero (&SelectData->fderrors); + + // Always read the loop-breaker reader. + // Changed 23Aug06, provisionally implemented for Windows with a UDP socket + // running on localhost with a randomly-chosen port. (*Puke*) + // Windows has a version of the Unix pipe() library function, but it doesn't + // give you back descriptors that are selectable. +- rb_fd_set (LoopBreakerReader, &(SelectData.fdreads)); +- if (SelectData.maxsocket < LoopBreakerReader) +- SelectData.maxsocket = LoopBreakerReader; ++ rb_fd_set (LoopBreakerReader, &(SelectData->fdreads)); ++ if (SelectData->maxsocket < LoopBreakerReader) ++ SelectData->maxsocket = LoopBreakerReader; + + // prepare the sockets for reading and writing + size_t i; +@@ -887,27 +865,27 @@ + assert (sd != INVALID_SOCKET); + + if (ed->SelectForRead()) +- rb_fd_set (sd, &(SelectData.fdreads)); ++ rb_fd_set (sd, &(SelectData->fdreads)); + if (ed->SelectForWrite()) +- rb_fd_set (sd, &(SelectData.fdwrites)); ++ rb_fd_set (sd, &(SelectData->fdwrites)); + + #ifdef OS_WIN32 + /* 21Sep09: on windows, a non-blocking connect() that fails does not come up as writable. + Instead, it is added to the error set. See http://www.mail-archive.com/[email protected]/msg58500.html + */ +- rb_fd_set (sd, &(SelectData.fderrors)); ++ rb_fd_set (sd, &(SelectData->fderrors)); + #endif + +- if (SelectData.maxsocket < sd) +- SelectData.maxsocket = sd; ++ if (SelectData->maxsocket < sd) ++ SelectData->maxsocket = sd; + } + + + { // read and write the sockets + //timeval tv = {1, 0}; // Solaris fails if the microseconds member is >= 1000000. + //timeval tv = Quantum; +- SelectData.tv = _TimeTilNextEvent(); +- int s = SelectData._Select(); ++ SelectData->tv = _TimeTilNextEvent(); ++ int s = SelectData->_Select(); + //rb_thread_blocking_region(xxx,(void*)&SelectData,RUBY_UBF_IO,0); + //int s = EmSelect (SelectData.maxsocket+1, &(SelectData.fdreads), &(SelectData.fdwrites), NULL, &(SelectData.tv)); + //int s = SelectData.nSockets; +@@ -930,15 +908,15 @@ + continue; + assert (sd != INVALID_SOCKET); + +- if (rb_fd_isset (sd, &(SelectData.fdwrites))) ++ if (rb_fd_isset (sd, &(SelectData->fdwrites))) + ed->Write(); +- if (rb_fd_isset (sd, &(SelectData.fdreads))) ++ if (rb_fd_isset (sd, &(SelectData->fdreads))) + ed->Read(); +- if (rb_fd_isset (sd, &(SelectData.fderrors))) ++ if (rb_fd_isset (sd, &(SelectData->fderrors))) + ed->HandleError(); + } + +- if (rb_fd_isset (LoopBreakerReader, &(SelectData.fdreads))) ++ if (rb_fd_isset (LoopBreakerReader, &(SelectData->fdreads))) + _ReadLoopBreaker(); + } + else if (s < 0) { +--- a/ext/em.h ++++ b/ext/em.h +@@ -89,6 +89,8 @@ + rb_thread_select(fd_check((n)-1) ? (n) : FD_SETSIZE, (rfds), (wfds), (efds), (timeout)) + #endif + ++struct SelectData_t; ++ + /******************** + class EventMachine_t + ********************/ +@@ -228,6 +230,8 @@ + #endif + + private: ++ SelectData_t *SelectData; ++ + bool bEpoll; + int epfd; // Epoll file-descriptor + #ifdef HAVE_EPOLL diff -Nru ruby-eventmachine-0.12.10/debian/patches/series ruby-eventmachine-0.12.10/debian/patches/series --- ruby-eventmachine-0.12.10/debian/patches/series 2012-06-13 18:08:47.000000000 +0200 +++ ruby-eventmachine-0.12.10/debian/patches/series 2016-06-29 22:53:09.000000000 +0200 @@ -1 +1,13 @@ 0001-Format-error-strings-safely.patch +0002-use-ruby-select-api-with-expandable-fd-sets.patch +0003-add-stubs-with-warnings-for-1.8.7-and-1.9.0.patch +0004-add-comment-about-where-the-macros-came-from.patch +0005-Back-port-em_test_helper.rb-for-test_many_fds.rb.patch +0006-must-call-raw-select-from-thread_blocking_region.patch +0007-epoll-kqueue-on-older-rubies-without-rb_wait_for_sin.patch +0008-make-sure-to-clean-up-rb_fd_init-memory-during-shutd.patch +0009-keep-BUILD_FOR_RUBY-compat.patch +0010-use-rb_thread_fd_select-whenever-possible.patch +0011-fix-build-on-ruby-1.9.1.patch +0012-allocate-one-SelectData_t-per-reactor-to-avoid-heap-.patch +skip_tests_using_network.patch diff -Nru ruby-eventmachine-0.12.10/debian/patches/skip_tests_using_network.patch ruby-eventmachine-0.12.10/debian/patches/skip_tests_using_network.patch --- ruby-eventmachine-0.12.10/debian/patches/skip_tests_using_network.patch 1970-01-01 01:00:00.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/patches/skip_tests_using_network.patch 2016-06-29 22:53:09.000000000 +0200 @@ -0,0 +1,106 @@ +Description: disable tests requiring network connection + These tests should pass if network access is available +Bug-Debian: http://bugs.debian.org/710941 +Origin: vendor +Author: Cédric Boutillier <[email protected]> +Forwarded: not-needed +Last-Update: 2013-06-16 + +--- a/tests/test_basic.rb ++++ b/tests/test_basic.rb +@@ -187,7 +187,7 @@ + assert_equal($sent, $received) + end + +- def test_bind_connect ++ def est_bind_connect + local_ip = UDPSocket.open {|s| s.connect('google.com', 80); s.addr.last } + + bind_port = rand(33333)+1025 +--- a/tests/test_httpclient.rb ++++ b/tests/test_httpclient.rb +@@ -41,7 +41,7 @@ + + #------------------------------------- + +- def test_http_client ++ def est_http_client + ok = false + EventMachine.run { + c = EventMachine::Protocols::HttpClient.send :request, :host => "www.google.com", :port => 80 +@@ -56,7 +56,7 @@ + + #------------------------------------- + +- def test_http_client_1 ++ def est_http_client_1 + ok = false + EventMachine.run { + c = EventMachine::Protocols::HttpClient.send :request, :host => "www.google.com", :port => 80 +@@ -68,7 +68,7 @@ + + #------------------------------------- + +- def test_http_client_2 ++ def est_http_client_2 + ok = false + EventMachine.run { + c = EventMachine::Protocols::HttpClient.send :request, :host => "www.google.com", :port => 80 +@@ -192,7 +192,7 @@ + + # TODO, need a more intelligent cookie tester. + # In fact, this whole test-harness needs a beefier server implementation. +- def test_cookie ++ def est_cookie + ok = false + EM.run { + c = EM::Protocols::HttpClient.send :request, :host => "www.google.com", :port => 80, :cookie=>"aaa=bbb" +@@ -207,7 +207,7 @@ + + # We can tell the client to send an HTTP/1.0 request (default is 1.1). + # This is useful for suppressing chunked responses until those are working. +- def test_version_1_0 ++ def est_version_1_0 + ok = false + EM.run { + c = EM::P::HttpClient.request( +--- a/tests/test_httpclient2.rb ++++ b/tests/test_httpclient2.rb +@@ -77,7 +77,7 @@ + assert(err) + end + +- def test_get ++ def est_get + content = nil + EM.run { + http = EM::P::HttpClient2.connect "google.com", 80 +@@ -109,7 +109,7 @@ + assert(content) + end + +- def test_get_pipeline ++ def est_get_pipeline + headers, headers2 = nil, nil + EM.run { + http = EM::P::HttpClient2.connect "google.com", 80 +@@ -139,7 +139,7 @@ + } + end + +- def test_https_get ++ def est_https_get + d = nil + EM.run { + http = EM::P::HttpClient2.connect :host => 'www.amazon.com', :port => 443, :ssl => true +--- a/tests/test_pending_connect_timeout.rb ++++ b/tests/test_pending_connect_timeout.rb +@@ -33,7 +33,7 @@ + end + end + +- def test_for_real ++ def est_for_real + $timeout = nil + EM.run { + EM.heartbeat_interval = 0.1 diff -Nru ruby-eventmachine-0.12.10/debian/ruby-tests.rb ruby-eventmachine-0.12.10/debian/ruby-tests.rb --- ruby-eventmachine-0.12.10/debian/ruby-tests.rb 2012-02-02 23:57:06.000000000 +0100 +++ ruby-eventmachine-0.12.10/debian/ruby-tests.rb 2016-06-29 22:53:09.000000000 +0200 @@ -1 +1,13 @@ -system("#{ENV['RUBY_TEST_BIN']} ./tests/test_*.rb") or raise +EXCLUDED_TESTS=["tests/test_get_sock_opt.rb", + "tests/test_process_watch.rb", + "tests/test_processes.rb", + "tests/test_ssl_args.rb", + "tests/test_ssl_methods.rb", + "tests/test_ssl_verify.rb" + ] +(Dir["tests/test_*.rb"]-EXCLUDED_TESTS).each do |f| + puts "*** running #{f} ***" + begin + system("#{ENV['RUBY_TEST_BIN']} -Itests #{f}") || exit($?.exitstatus) + end +end

