From: Joel VanderWerf Date: 2002-11-08T09:54:23+09:00 Subject: Re: bug in Fox or in Ruby -- round 2 This is a multi-part message in MIME format. --------------030003080008060708030809 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit An update on the bug. Problem 1: Joel VanderWerf wrote: > > If I run this and press the "Pow!" button twice, I get a segfault. I've > tried whittling the example down, but everything seems to play a role... Problem 2: Maur�cio wrote: > Hi, > > An application I'm creating crashes ruby 1.73 (I'm using the windows > distribution from Pragmatic Programmers). > The lines where the crash occurs (at least that's what the message > says) are: > > def float_translator (str) > str.gsub(/([\d\+\-\.]+) (\+ | \-) (\d*) (\| | $)/ix){$1 + 'E' + $2 + > $3 + $4}.to_f > end Now, I can recreate the former and maybe also the latter problem with a fairly simple script. It uses FXRuby. Versions: FXRuby-1.0.14 fox-1.0.26 ruby-1.7.3 linux-mandrake 8.1 Some observations: * On my box, the segfault happens pretty reliably after 341 iterations. The message is: ./bug2.rb:66: [BUG] rb_gc_mark() called for broken object ruby 1.7.3 (2002-09-27) [i686-linux] zsh: abort ./bug2.rb The line in question is a case statement involving regexes, which is what suggests to me that this is related to Mauricio's bug. My original app was much more complex, and the problem came up much sooner. So there seems to be some connection with code complexity. * GC.disable seems to prevent it from happening (well, I run out of swap first, anyway). Looks like a ruby object isn't getting marked, or malloced data is getting freed improperly. * I tried to recreate the problem without FXRuby, but couldn't. * I can't whittle the example down much farther in any dimension. For example, the two lines old_nr = @table.numRows old_nc = @table.numCols define local vars which are never used, but taking them out prevents the bug (or delays it for more than 1000 iterations). Another example, there is an unused branch of a case statement which cannot be removed without losing the bug: case entry when /\A(.*\.)(.*)\z/ entry = sprintf("%10.5f", entry.to_f). sub(/\.(\d*?)(0*)$/) { ".#{$1}#{$2.gsub("0", " ")}" } when /\d+/ entry << " " * 6 end The first 'when' is never taken, but somehow parsing it is necessary to expose the bug at iteration 341. *** Can anyone shed any light on this murky situation? *** --------------030003080008060708030809 Content-Type: text/plain; name="bug2.rb" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="bug2.rb" #!/usr/bin/env ruby require "fox" include Fox if false puts "disabling GC" GC.disable ### prevents bug end class BugWindow < FXMainWindow include Responder def initialize(app) super(app, "Bug2", nil, nil, DECOR_ALL, 0, 0, 0, 0) contents = FXHorizontalFrame.new(self, LAYOUT_SIDE_TOP|FRAME_NONE|LAYOUT_FILL_X|LAYOUT_FILL_Y) @table = FXTable.new(contents, 0, 0, nil, 0, TABLE_COL_SIZABLE|TABLE_ROW_SIZABLE|LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 2,2,2,2) end def onPow(sender, sel, index) 1000.times do |i| p i item = nil @table.setTableSize 0,0 @header_row = ["foo"]*10 @data_lines = [] 100.times { @data_lines << ["1"]*10 } old_nr = @table.numRows old_nc = @table.numCols # resize the table nr = @data_lines.size + 2 nc = @header_row.size + 2 @table.setTableSize(nr, nc) @table.leadingRows = 1 @table.leadingCols = 1 @table.trailingRows = 1 @table.trailingCols = 1 # The corners are just buttons @table.setItemText(0, 0, "") @table.getItem(0, 0).setButton(true) @table.setItemText(0, nc-1, "") @table.getItem(0, nc-1).setButton(true) @table.setItemText(nr-1, 0, "") @table.getItem(nr-1, 0).setButton(true) @table.setItemText(nr-1, nc-1, "") @table.setItemText(0, nc-1, "") # Initialize scrollable part of table entry = nil (1..nr-2).each { |r| (1..nc-2).each { |c| entry = @data_lines[r-1][c-1] case entry when /\A(.*\.)(.*)\z/ entry = sprintf("%10.5f", entry.to_f). sub(/\.(\d*?)(0*)$/) { ".#{$1}#{$2.gsub("0", " ")}" } when /\d+/ entry << " " * 6 end @table.setItemText(r, c, entry) } } end return 1 end def create position(200, 200, 600, 400) super show end end application = FXApp.new("TEST", "TEST") application.init(ARGV) window = BugWindow.new(application) application.create window.onPow(nil, nil, nil) --------------030003080008060708030809--