On Thu, 7 Sep 2006, Tim Pease wrote: > $ cat mmap-abort.rb > > require 'mmap' > require 'fileutils' > > FileUtils.touch 'output.txt' > File.open('mmap.bin', 'w') {|f| f.truncate 16} unless File.exist? 'mmap.bin' > > m = Mmap.new 'output.txt', 'rw' > > (0...4).each do |x| > fork do > mmap = Mmap.new 'mmap.bin', 'rw' > range = (x*4)...(x*4+4) > val = mmap[range].unpack('N')[0] > mmap[range] = [val+x].pack('N') > mmap.unmap > end > end > > m << "Done!\n" > > # EOF > $ ruby mmap-abort.rb > mmap-abort.rb:20: [BUG] Bus Error > ruby 1.8.4 (2005-12-24) [powerpc-linux] > > Aborted (core dumped) > $ > > The line at the end -- m << "Done!\n" -- is causing the abort. I'm > seeing this behavior on all the Unix platforms I have access to ... > > SunOS ravenclaw 5.9 Generic_112233-12 sun4u sparc SUNW,Sun-Blade-1500 > > Linux panic 2.6.17-1.2157_FC5 #1 SMP Tue Jul 11 23:03:20 EDT 2006 > ppc64 ppc64 ppc64 GNU/Linux > > Linux pong 2.6.17-1.2142_FC4 #1 Tue Jul 11 22:41:14 EDT 2006 i686 i686 > i386 GNU/Linux > > > So, the interesting part is that if I open the "output.txt" file and > add a single character to it, the problem disappears ... > > $ echo 'x' > output.txt > $ ruby mmap-abort.rb > $ cat output.txt > x > Done! > $ > > I can also make the problem go away by creating the mmap to output.txt > after the each/fork block. > > I can also make the problem go away by commenting out the "mmap.unmap" > line at the end of the fork block. > > The bus error is being caused by a call to memcpy in the "mm_cat" > method of the mmap source code -- line 1480 of mmap.c > > Any patches out there? harp:~ > cat a.rb require 'mmap' require 'fileutils' FileUtils.touch 'output.txt' File.open('mmap.bin', 'w') {|f| f.truncate 16} unless File.exist? 'mmap.bin' m = Mmap.new 'output.txt', 'rw' (0...4).each do |x| fork do mmap = Mmap.new 'mmap.bin', 'rw' range = (x*4)...(x*4+4) val = mmap[range].unpack('N')[0] mmap[range] = [val+x].pack('N') p mmap.to_str mmap.unmap exit! # don't let child unmap automatically end Process.wait # if you don't do this it'll be non-deterministic end m << "Done!\n" harp:~ > ruby a.rb "\000\000\000\000\000\000\000\010\000\000\000\020\000\000\000\030" "\000\000\000\000\000\000\000\t\000\000\000\020\000\000\000\030" "\000\000\000\000\000\000\000\t\000\000\000\022\000\000\000\030" "\000\000\000\000\000\000\000\t\000\000\000\022\000\000\000\e" basically, you can't carry the mmap across the fork and hope that the child's at_exit handlers don't interfere with the parent. check this out: harp:~ > cat a.rb require 'mmap' STDOUT.sync = true Mmap.new __FILE__, 'r' fork{ 42 } and Process.wait harp:~ > strace -f ruby a.rb 2>&1|egrep 'map|:[ABCD]:'|tail -3 mmap2(NULL, 88, PROT_READ, MAP_SHARED, 3, 0) = 0xb75ae000 [pid 2544] munmap(0xb75ae000, 88) = 0 munmap(0xb75ae000, 88) = 0 and with exit! harp:~ > cat a.rb require 'mmap' STDOUT.sync = true Mmap.new __FILE__, 'r' fork{ 42 and exit! } and Process.wait harp:~ > strace -f ruby a.rb 2>&1|egrep 'map|:[ABCD]:'|tail -3 old_mmap(0xbab000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x7000) = 0xbab000 mmap2(NULL, 98, PROT_READ, MAP_SHARED, 3, 0) = 0xb75af000 munmap(0xb75af000, 98) = 0 note the double munmap. i don't know if this is os specific or not or if it's expected or not - but preventing the child from freeing the map seems to fix it. kind regards. -a -- what science finds to be nonexistent, we must accept as nonexistent; but what science merely does not find is a completely different matter... it is quite clear that there are many, many mysterious things. - h.h. the 14th dalai lama