Forum: Ruby-dev [ruby-trunk - Bug #10646] [Open] wmap_final_func の xrealloc で確保するメモリのサイズが1足りないためSEGV

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
205ca9566e14fb669ed977cae5af88e0?d=identicon&s=25 unknown (Guest)
on 2014-12-25 09:28
(Received via mailing list)
Issue #10646 has been reported by Naohisa Goto.

----------------------------------------
Bug #10646: wmap_final_func の xrealloc で確保するメモリのサイズが1足りないためSEGV
https://bugs.ruby-lang.org/issues/10646

* Author: Naohisa Goto
* Status: Open
* Priority: Normal
* Assignee:
* Category:
* Target version:
* ruby -v: ruby 2.2.0dev (2014-12-25) [sparc64-solaris2.10]
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------
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とは無関係のバグです。
This topic is locked and can not be replied to.