about summary refs log tree commit homepage
path: root/test
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2010-02-12 23:59:55 -0800
committerEric Wong <normalperson@yhbt.net>2010-02-13 00:31:52 -0800
commitb30ae5c5f01c36f39b9c301e59d8ad9fb24f7c1b (patch)
tree221140413a957ecce9cb34040320c6aa0a8bed6b /test
parent47c50ed7ebb2a97c2d289eede169f3e2e3f5e89b (diff)
downloadunicorn-b30ae5c5f01c36f39b9c301e59d8ad9fb24f7c1b.tar.gz
First off, this memory leak DOES NOT affect Unicorn itself.
Unicorn allocates the HttpParser once and always reuses it
in every sequential request.

This leak affects applications which repeatedly allocate a new
HTTP parser.  Thus this bug affects _all_ deployments of
Rainbows! and Zbatery.  These servers allocate a new parser for
every client connection.

I misread the Data_Make_Struct/Data_Wrap_Struct documentation
and ended up passing NULL as the "free" argument instead of -1,
causing the memory to never be freed.

From README.EXT in the MRI source which I misread:
> The free argument is the function to free the pointer
> allocation.  If this is -1, the pointer will be just freed.
> The functions mark and free will be called from garbage
> collector.
Diffstat (limited to 'test')
-rw-r--r--test/unit/test_http_parser.rb18
1 files changed, 17 insertions, 1 deletions
diff --git a/test/unit/test_http_parser.rb b/test/unit/test_http_parser.rb
index 0443b46..5b0ca9f 100644
--- a/test/unit/test_http_parser.rb
+++ b/test/unit/test_http_parser.rb
@@ -527,5 +527,21 @@ class HttpParserTest < Test::Unit::TestCase
     end
 
   end
-end
 
+  # so we don't  care about the portability of this test
+  # if it doesn't leak on Linux, it won't leak anywhere else
+  # unless your C compiler or platform is otherwise broken
+  LINUX_PROC_PID_STATUS = "/proc/self/status"
+  def test_memory_leak
+    match_rss = /^VmRSS:\s+(\d+)/
+    if File.read(LINUX_PROC_PID_STATUS) =~ match_rss
+      before = $1.to_i
+      1000000.times { Unicorn::HttpParser.new }
+      File.read(LINUX_PROC_PID_STATUS) =~ match_rss
+      after = $1.to_i
+      diff = after - before
+      assert(diff < 10000, "memory grew more than 10M: #{diff}")
+    end
+  end if RUBY_PLATFORM =~ /linux/ && test(?r, LINUX_PROC_PID_STATUS)
+
+end