[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Wheezy update of ruby-eventmachine?



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 <zeha@debian.org>:
>> Hi,
>>
>> * Bálint Réczey <balint@balintreczey.hu> [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 <balint@balintreczey.hu>  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 <pkg-ruby-extras-maintainers@lists.alioth.debian.org>
 Uploaders: Daigo Moriwaki <daigo@debian.org>, Ryan Niebur <ryanryan52@gmail.com>, Laurent Arnoud <laurent@spkdev.net>, Paul van Tilburg <paulvt@debian.org>, Per Andersson <avtobiff@gmail.com>
-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 <patrick.reynolds@github.com>
+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/openssl-users@openssl.org/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 <patrick.reynolds@github.com>
+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 <patrick.reynolds@github.com>
+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 <balint@balintreczey.hu>
+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 <aman@tmm1.net>
+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 <aman@tmm1.net>
+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 <aman@tmm1.net>
+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 <aman@tmm1.net>
+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 <aman@tmm1.net>
+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 <aman@tmm1.net>
+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 <aman@tmm1.net>
+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/openssl-users@openssl.org/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 <boutil@debian.org>
+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

Reply to: