With Ben Cressey we made some investigations to learn more about it,
trying it on different OS and hardware (trying indifferently gargoyle,
when available, or console git/glulxe):
- Linux (32 bit): the bug is present
- Linux (64 bit): works perfectly
- Linux PPC: works perfectly
- Windows 32 bit: works perfectly
- Haiku (32 bit): works perfectly
- FreeBSD (32 bit): works perfectly
When trying to compile the source code (located at
http://code.google.com/p/rovers-day-out/), it even crashes gnome-inform7
(but I can release it anyway).
Basically, it's present only on Linux 32 bit. Why? The same interpreters
source code and the same game are used on all the tested plateforms.
The I7 code which is problematic is this part:
To say (dialogue - some text) in metaspeak:
if Real Thing is happening or Boarding Party is happening or Back on
Mars is happening:
the rule succeeds;
otherwise:
say paragraph break;
say first custom style;
say "[dialogue in fancyprint]";
say roman type;
say variable letter spacing;
say paragraph break.
To say (dialogue - some text) in fancyprint:
(- FancyPrint ({dialogue}); -).
Include (-
Constant SPACE = 32;
Constant RIGHTMARGIN = 60;
Array BigBuffer -> 1024; !big enough to hold the largest metatext
[FancyPrint caption i linelen;
caption.print_to_array(BigBuffer);
linelen = 0;
for (i=WORDSIZE : i < BigBuffer-->0+WORDSIZE : i++){
if (BigBuffer->i == '*'){
print "^";
linelen = 0;
continue;
}
if (linelen > (RIGHTMARGIN - 5) && BigBuffer->i == SPACE){
print "^ ";
linelen = 7;
continue;
}
print (char) BigBuffer->i;
linelen++;
}
rtrue;
];
-).
If I replace: say "[dialogue in fancyprint]";
by : say "[dialogue]";
the whole text is displayed on linux 32 (even if not formatted as
expected), and I can compile it in gnome-inform7.
Could it be related to how memory is handled on those different OS?
[Some I7 code snipped]
> Array BigBuffer -> 1024; !big enough to hold the largest metatext
>
> [FancyPrint caption i linelen;
> caption.print_to_array(BigBuffer);
<pedant>
I'd suggest replacing the above line with "caption.print_to_array
(BigBuffer, 1024);".
</pedant>
I seriously doubt this is in any way related to the problems you've
encountered, but as I haven't managed to reproduce them on my
(relatively-ancient) 32-bit Linux box, I've not been able to confirm
that. ;)
> linelen = 0;
> for (i=WORDSIZE : i < BigBuffer-->0+WORDSIZE : i++){
> if (BigBuffer->i == '*'){
> print "^";
> linelen = 0;
> continue;
> }
> if (linelen > (RIGHTMARGIN - 5) && BigBuffer->i == SPACE){
> print "^ ";
> linelen = 7;
> continue;
> }
> print (char) BigBuffer->i;
> linelen++;
> }
> rtrue;
> ];
>
> -).
>
--
Matthew
hey, that's great, because thanks to your suggestion, there is no longer
this bug in the display.
It doesn't explain why we had this bug on several 32 bit linux systems
(could it be related to the kernel used and the way it handles memory?)
Matthew looked at this further and then contacted me. As it turns out,
if you call print_to_array() with a single argument -- an address,
but no array size -- then the I6 code does something stupid. It
starts writing to an array of length $7FFFFFFF.
In my reference Glk libraries, this happens to work -- as long as you
don't in fact write past the end of the array. Of course, this is a
serious bug waiting to happen. An overflow could crash the game, or
crash the interpreter. A malicious overflow could conceivably eat your
computer.
More generally, this constrains the VM implementation. It should be
legal for the interpreter to allocate the string array separately, and
then copy it back to Glulx memory when the printing is complete. (This
is already how Unicode print-buffering works, due to endian issues.)
Such a strategy is liable to go squish in the face of a two-gigabyte
string array.
(It's the Glulx Inform veneer code being stupid. All my fault.
I'm sure I thought about this in 1998, and decided it wouldn't be a
big problem. Like all small problems that are ignored, it has grown.)
Anyhow. I have implemented a small patch to Glulxe which checks for
this sort of overflow, and treats it as a fatal error.
For the I6 Glulx author, this means that the String class's
print_to_array() method *must* be called with two arguments. The
one-argument form will die. And this applies to old Glulx games as
well; it's an interpreter change, not a compiler change.
The I7 compiler does not use print_to_array(), and I don't believe it
ever has. So this does not directly impact I7 authors. However, as you
can see above, some authors may be using I6 code with this idiom. Or
it might be in extensions.
My clever plan at this point is to put out the updated interpreter,
and try to find out how many existing games it breaks. If it's not
many, or if they can plausibly be fixed, I'll make the patch
permanent.
The alternate solution is for the interpreter to accept Stupidly Long
Arrays, and silently truncate them at the end of VM memory. This would
rule out interpreter crashes and security holes, but an overflowing
print_to_array() could still corrupt game state.
The Glulxe interpreter source patch is up at
<http://eblong.com/zarf/tmp/arraylimit.patch>,
or get the whole source package at
<http://github.com/erkyrath/glulxe/tree/arraylimit>.
--Z
--
"And Aholibamah bare Jeush, and Jaalam, and Korah: these were the borogoves..."
*
> Could it be related to how memory is handled on those different OS?
I also had a problem compiling the game under 5Z71. I was able to get
an output file but the compiler came up with the printanytoarray error
in
the Mac and Windows compiler.