kaitai-io / kaitai_struct_ruby_runtime

Kaitai Struct: runtime for Ruby

Home Page:https://rubygems.org/gems/kaitai-struct

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Possible inconsistent lazy evaluation of instances compared to Java runtime.

ams-tschoening opened this issue · comments

I've found the following because I wondered about some wrong output in the Ruby visualizer, but I believe that the underlying problem is in the runtime.

I have a structure consisting of an arbitrary length of blocks and implemented a look-ahead approach to check if another block is following or not. It's simply a list of blocks where the last read block tells if there's a next block coming or not. This works, the data is parsed as expected and the data itself is shown in the right way in the visualizer. The following code is used to implement the look-ahead in KSY and is called in a repeat-until:

  look_ahead_next_byte:
    pos:  _io.pos
    type: u1
  next_isnt_vdb:
    value:  _io.eof                           or
            (
              (look_ahead_next_byte == 0x0F)  or
              (look_ahead_next_byte == 0x1F)
            )

The problem in the visualizer is that next_isnt_vdb is always shown as true, even for those blocks were it is false on runtime. And it must be false on runtime, because else it wouldn't work AND because only if _io.eof is false the byte is actually read and that is shown in the visualizer as well. Only at the very last element that byte is not shown, simply because _io.eof is correctly true in that case.

Look at the following screenshot, where element 19 should print false, one can see that a byte has been read and that's not the case for element 20. Whenever I try to open look_ahead_next_byte of element 20 an error message is shown that 1 byte couldn't be read. That's expected behaviour, because the stream is already at eof when I'm doing this, the true of element 19 and less is not.

next_isnt_vdb is wrongly true

The Ruby runtime generates the following code:

def next_isnt_vdb
  return @next_isnt_vdb if @next_isnt_vdb
  @next_isnt_vdb = _io.eof? || look_ahead_next_byte == 15 || look_ahead_next_byte == 31
  @next_isnt_vdb
end

I don't know Ruby, but from my Perl background this is very likely caching the value only in case it's true, not if it has been evaluated to false successfully before. There's most likely a difference between a defined variable with a false value and and undefined one. Pretty much the same like with null vs. a Boolean object evaluating to true or false in Java.

So the current implementation in Ruby simply always evaluates that instance until true is reached, which is the case when I'm browsing the structure in the visualizer. This doesn't seem to be inline with your behaviour in Java and simply shows wrong data in the visualizer.

SO says that there's an explicit check for undefined or such in Ruby as well using defined?. So in theory this could be fixed unless there's a reason for this behaviour I'm not aware of. If so, how to deal with the wrong data shown in the visualizer?

You're really amazing on how you find all that bugs! Thanks!
Indeed, this one stems from a long time ago, where we had no idea of having boolean type at all, so it is completely missed. I'll fix it asap.

I guess it should be fixed now, please take a look. Stupid GitHub has only 2 states for the issue, so it opted to close it already :(

It is, thanks.

next_isnt_vdb