Project

General

Profile

Actions

Bug #10646

closed

wmap_final_func の xrealloc で確保するメモリのサイズが1足りないためSEGV

Added by ngoto (Naohisa Goto) almost 10 years ago. Updated over 9 years ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 2.2.0dev (2014-12-25) [sparc64-solaris2.10]
[ruby-dev:48779]

Description

Solaris にて、以下のようにメモリリークを発見するデバッグ用のmallocを使用すると、WeakRefのfinalize中にSEGVが発生します。
(r48972 にて確認)

$ LD_PRELOAD=libumem.so UMEM_OPTIONS="backend=mmap" /usr/bin/time /XXXXX/bin/ruby -r weakref -e 'a = Object.new; 150_000.times { WeakRef.new(a) }'
/XXXXX/lib/ruby/2.2.0/weakref.rb:87: [BUG] Segmentation fault at 0x7fffffff7806a000
ruby 2.2.0dev (2014-12-24) [sparc64-solaris2.10]

-- Control frame information -----------------------------------------------
c:0008 p:---- s:0022 e:000021 CFUNC  :finalize
c:0007 p:---- s:0020 e:000019 CFUNC  :call
c:0006 p:0039 s:0018 e:000017 METHOD /XXXXX/lib/ruby/2.2.0/weakref.rb:87 [FINISH]
c:0005 p:---- s:0014 e:000013 CFUNC  :new
c:0004 p:0015 s:0010 e:000009 BLOCK  -e:1 [FINISH]
c:0003 p:---- s:0008 e:000007 CFUNC  :times
c:0002 p:0017 s:0005 E:001398 EVAL   -e:1 [FINISH]
c:0001 p:0000 s:0002 E:000e50 TOP    [FINISH]

-- Ruby level backtrace information ----------------------------------------
-e:1:in `<main>'
-e:1:in `times'
-e:1:in `block in <main>'
-e:1:in `new'
/XXXXX/lib/ruby/2.2.0/weakref.rb:87:in `initialize'
/XXXXX/lib/ruby/2.2.0/weakref.rb:87:in `call'
/XXXXX/lib/ruby/2.2.0/weakref.rb:87:in `finalize'

-- Other runtime information -----------------------------------------------

* Loaded script: -e

* Loaded features:

    0 enumerator.so
    1 rational.so
    2 complex.so
    3 /XXXXX/lib/ruby/2.2.0/sparc64-solaris2.10/enc/encdb.so
    4 /XXXXX/lib/ruby/2.2.0/sparc64-solaris2.10/enc/trans/transdb.so
    5 /XXXXX/lib/ruby/2.2.0/unicode_normalize.rb
    6 /XXXXX/lib/ruby/2.2.0/sparc64-solaris2.10/rbconfig.rb
    7 thread.rb
    8 /XXXXX/lib/ruby/2.2.0/sparc64-solaris2.10/thread.so
    9 /XXXXX/lib/ruby/2.2.0/rubygems/compatibility.rb
   10 /XXXXX/lib/ruby/2.2.0/rubygems/defaults.rb
   11 /XXXXX/lib/ruby/2.2.0/rubygems/deprecate.rb
   12 /XXXXX/lib/ruby/2.2.0/rubygems/errors.rb
   13 /XXXXX/lib/ruby/2.2.0/rubygems/version.rb
   14 /XXXXX/lib/ruby/2.2.0/rubygems/requirement.rb
   15 /XXXXX/lib/ruby/2.2.0/rubygems/platform.rb
   16 /XXXXX/lib/ruby/2.2.0/rubygems/basic_specification.rb
   17 /XXXXX/lib/ruby/2.2.0/rubygems/stub_specification.rb
   18 /XXXXX/lib/ruby/2.2.0/rubygems/util/stringio.rb
   19 /XXXXX/lib/ruby/2.2.0/rubygems/specification.rb
   20 /XXXXX/lib/ruby/2.2.0/rubygems/exceptions.rb
   21 /XXXXX/lib/ruby/2.2.0/rubygems/core_ext/kernel_gem.rb
   22 /XXXXX/lib/ruby/2.2.0/monitor.rb
   23 /XXXXX/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb
   24 /XXXXX/lib/ruby/2.2.0/rubygems.rb
   25 /XXXXX/lib/ruby/2.2.0/delegate.rb
   26 /XXXXX/lib/ruby/2.2.0/weakref.rb

[NOTE]
You may have encountered a bug in the Ruby interpreter or extension libraries.
Bug reports are welcome.
For details: http://www.ruby-lang.org/bugreport.html

time: command terminated abnormally.

real       33.2
user       21.3
sys        11.5
$ 

デバッガ上にて起動すると発生位置を特定できました。
配列の範囲外にアクセスしていました。

$ dbx /XXXXX/bin/ruby 
For information about new features see `help changes'
To remove this message, put `dbxenv suppress_startup_message 7.5' in your .dbxrc
Reading ruby
Reading ld.so.1
Reading libumem.so.1
Reading libpthread.so.1
Reading librt.so.1
Reading libgmp.so.10.1.3
Reading libsocket.so.1
Reading libdl.so.1
Reading libcrypt_d.so.1
Reading libm.so.2
Reading libc.so.1
Reading libaio.so.1
Reading libmd.so.1
Reading libnsl.so.1
Reading libgen.so.1
(dbx) run -r  weakref -e 'a = Object.new; 150_000.times { WeakRef.new(a) }'
Running: ruby -r weakref -e "a = Object.new; 150_000.times { WeakRef.new(a) }" 
(process id 6241)
Reading libc_psr.so.1
Reading encdb.so
Reading transdb.so
Reading thread.so
t@1 (l@1) signal SEGV (access to address exceeded protections) in wmap_final_func at line 7666 in file "gc.c"
 7666           if (ptr[i] != wmap) {
(dbx) print i
i = 103422U
(dbx) print j
j = 103421U
(dbx) print wmap
wmap = 9223372034650698920U
(dbx) print ptr
ptr = 0x7fffffff77200010
(dbx) print ptr[0]
ptr[0] = 103422U
(dbx) print ptr[i]
dbx: cannot access address 0x7fffffff772ca000
(dbx) print ptr[j]
ptr[j] = 9223372034650719480U
(dbx) print ptr[103422]
dbx: cannot access address 0x7fffffff772ca000
(dbx) print ptr[103421]
ptr[103421] = 9223372034650719480U

ptr[0]がその配列ptrの要素数を格納する場所ですが、この数字はptr[0]の場所を考慮しない要素数、つまりptr[1]からptr[ptr[0]]までアクセスされる可能性があります。
このため、ptr[0]の数+1のメモリを確保する必要がありますが、wmap_final_func() 内の ruby_sized_xrealloc2() での確保時に +1 が忘れ去られていました。

以下のパッチでSEGVは出なくなりました。

Index: gc.c
===================================================================
--- gc.c	(revision 48988)
+++ gc.c	(working copy)
@@ -7672,7 +7672,7 @@
 	return ST_DELETE;
     }
     if (j < i) {
-	ptr = ruby_sized_xrealloc2(ptr, j, sizeof(VALUE), i);
+	ptr = ruby_sized_xrealloc2(ptr, j + 1, sizeof(VALUE), i);
 	ptr[0] = j;
 	*value = (st_data_t)ptr;
     }

今回、たまたまSolarisにて露見しましたが、本来はOSやCPUとは無関係のバグです。

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0