fidgit icon indicating copy to clipboard operation
fidgit copied to clipboard

Exceptions inside of blocks

Open JosephAustin opened this issue 10 years ago • 24 comments

In many cases it appears that exceptions getting thrown within a do block will cause the program to hang, instead of reporting the backtrace. It then continuously increases in memory use. The problem can also be triggered by using a rescue and trying to print out the exception's message, which leads me to think its message is either very large or generates recursively somehow.

ex:

      button "Purge", parent:packer do
        blah = not_existing_variable
        Dir.glob(File.join($window.trashFolder, "*.*")).each do |file|
          if(!File.directory? file)
            File.delete file
          end
        end
      end

The above code crashes like you would expect on that second line, but at that point the code totally freezes. If I print out its backtrace I get:

../lib/fidgit/event.rb:128:in `call'

../lib/fidgit/event.rb:128:in `block in publish'

../lib/fidgit/event.rb:127:in `reverse_each'

../lib/fidgit/event.rb:127:in `publish'

../lib/fidgit/states/gui_state.rb:284:in `redirect_released_mouse_button'

etc...

Seems to me that something goes totally batty in the event handling. I'm on x86-64 Linux using Ruby 2.1.2p95

EDIT

The issue appears to be caused by the destruction order of widgets in any sort of list. An empty list finishes faster, but the problem is exponential. Manually catching issues inside of event blocks and clearing the list widgets with @widget.parent.clear and then setting the widget itself to nil immediately works, and the error can then be thrown. This provides a troublesome but functional work-around.

JosephAustin avatar Oct 06 '14 23:10 JosephAustin

Does the exception handling work with 1.9.3 or not? (That is the last version I tested it on). I do some funky stuff to make those blocks work, which may possibly be fubar in newer versions.

bil-bas avatar Oct 06 '14 23:10 bil-bas

Hmm, not sure. I will make an attempt. I'm guessing it will and that'll turn out to be what happened. I'll have to roll back somehow or other.

JosephAustin avatar Oct 06 '14 23:10 JosephAustin

I really don't know myself. It is still reasonably likely to be a fault in fidgit, rather than something that went "wrong" with Ruby since I wrote it.

bil-bas avatar Oct 06 '14 23:10 bil-bas

Building it now. Well, you know how it goes, something could have gone 'right' in Ruby since you wrote it that turned what you did wrong :P These things happen.

JosephAustin avatar Oct 06 '14 23:10 JosephAustin

Aye! That is probably the case :blush:

bil-bas avatar Oct 06 '14 23:10 bil-bas

As an aside, the Ruby idiom is:

File.delete file unless File.directory? file

bil-bas avatar Oct 06 '14 23:10 bil-bas

Yes, I'm still learning ;) Ive been doing that more often now.

I just fired up 1.9.3's irb and got my app to load up, and it handles the exceptions. so there we go.

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

Well, that is "good" news, though I have no idea why it shouldn't work on 2.1 (I haven't used 2.0+ very much at all).

p.s. Drop IRB and start using Pry instead ;)

bil-bas avatar Oct 07 '14 00:10 bil-bas

I'm presuming that https://github.com/Spooner/fidgit/blob/master/lib/fidgit/redirector.rb is what is faulty, which is what is used to create those "clever" blocks (in a really dumb way). Might be obvious what is wrong if I knew anything about the newer Ruby versions.

bil-bas avatar Oct 07 '14 00:10 bil-bas

Okay then, I'll have a look at it and if I fix it I'll send you a patch :) There's a workaround by doing exception handling inside every block manually

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

Another workaround would be to not use the blocks (they just make things easier) :stuck_out_tongue:

bil-bas avatar Oct 07 '14 00:10 bil-bas

And i was wrong, i corrected myself and it -does- lock up in the older ruby. It says

"NameError:"

and freezes.

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

And then the memory use goes up, up , up.... ctrl-c gives me the proper dump. So some recursive or infinite loop happens.

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

Hmm - do you have a full chunk of code that fails in this way that you could show me? Not sure I'd have any luck, but I can take a look.

bil-bas avatar Oct 07 '14 00:10 bil-bas

Hrm. It's something I did because i just tried to recreate the issue from scratch and couldn't. I would guess it has to do with all the threading stuff i have going on. This simple snippet:

require 'fidgit'

class TestState < Fidgit::GuiState def initialize super

horizontal do
  vertical do |packer|
    button "Test", parent:packer do
      hdkjshfk = djxhf
    end
  end
end

end end

class Window < Chingu::Window def initialize super 800, 600, false push_game_state TestState end end

$Window = Window.new $Window.show

works fine

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

ugh, that formatted nicely.

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

Fidgit is definitely not thread-safe code.

bil-bas avatar Oct 07 '14 00:10 bil-bas

Yeah but it's not running any of that in an actual thread, i just happen to have a few running off to the side loading thumbnails. Okay, I'm going to just say don't sweat it for now. If I figure out a specific cause I'll let you know.

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

I'd recommend you use fibers rather than Threads anyway (except if there is blocking, such as in sockets, and then there are managed ways to manage that so you shouldn't ever need threads).

bil-bas avatar Oct 07 '14 00:10 bil-bas

Oh, I didn't know about these. They look like c# coroutines. Thanks!

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

Yes, very similar I think. Saves on a lot of the horrors of manual thread usage ;) Best of luck!

bil-bas avatar Oct 07 '14 00:10 bil-bas

Found it. It has something to do with having a file list. I copied mine from your default and modified it, but even yours causes the bug. Here's the code:

http://pastebin.com/9N4HsfBg

Now you can see. Changing File Dialog to File Browser has the same effect

JosephAustin avatar Oct 07 '14 00:10 JosephAustin

Well I'm off for now. I'll keep poking, but it looks like it has to do with the presence of a list. When I deleted everything but the list it still hung, but for an even more negligible amount of time. It probably has something to do with recursively cleaning up the list and the associated event handlers.

It's interesting that if you rescue from where the issue happens and raise 'messed up' instead, it crashes smoothly, but if you do a rescue => e and then puts e, you get the same issue on the print statement. Wild.

I'm going to go wander the Mojave wasteland now.

JosephAustin avatar Oct 07 '14 01:10 JosephAustin

Okay, got a workaround:

      button "Purge", parent:packer do
        begin
          jkh = hjh
          Dir.glob(File.join($window.trashFolder, "*.*")).each do |file|
            File.delete file unless File.directory? file
          end
        rescue => y
          @folderBrowser.parent.clear
          @folderBrowser = nil
          raise y
        end
      end

This causes an immediate crash... as it ought. As long as the list is manually removed from the system and destroyed before raising the issue, it works.

So the 'message' of the exception is not problematic, but when it is requested, it seems that Ruby wants to finishes destructing everything first, and somehow lists make this an exponentially larger process, so it hangs. GC.start doesn't do it, so it isn't the collector.

JosephAustin avatar Oct 07 '14 23:10 JosephAustin