Why is this NOT causing a run-time error message?

I am mystified by the output of the following:

I7 source with puzzling output
"Crosscheck"

Place is a room.

[make sure that compiler and VM agree on start of read-only boundary]
To say static memory start from header:
    (- print (BlkPrintHexadecimal) HDR_STATICMEMORY-->0; -).

To say static memory start from compiler:
    (- print (BlkPrintHexadecimal) #static_memory_offset; -).

[make sure that compiler and VM agree on start of packed address boundary]
To say high memory start from header:
    (- print (BlkPrintHexadecimal) HDR_HIGHMEMORY-->0; -).

To say high memory start from compiler:
    (- print (BlkPrintHexadecimal) #readable_memory_offset; -).


[phrases for memory access using word and byte indexing from start of memory] 
To say memory value at word (N - number): [This is perhaps surprisingly allowed.]
    (- print 0-->{N}, "^"; -).

To say memory value at byte (N - number): [This is perhaps unsurprisingly not allowed.]
    (- print 0->{N}, "^"; -).


[make sure that nothing weird is happening in the arithmetic]
To validate equivalency:
    (- if ((0+(-4)) == (0+2*(-2))) print "YES"; else print "NO"; new_line; -).

When play begins:
    say "static memory start (header) : [static memory start from header][line break]";
    say "static memory start (compiler) : [static memory start from compiler][line break]";
    say "high memory start (header) : [high memory start from header][line break]";
    say "high memory start (compiler) : [high memory start from compiler][line break]";
    validate equivalency;
    say "This next bit looks illegal...";
    say memory value at word -2; [note that generated I6 code embeds the -2 as a constant]
    say "So why no RTE?";
    say "And this next bit looks to be governed the same way by veneer code...";
    say memory value at byte -4; [note that generated I6 code embeds the -4 as a constant]
    say "So why does *that* get an RTE?".

The resulting output looks like this:

static memory start (header) : 7D57
static memory start (compiler) : 7D57
high memory start (header) : 9058
high memory start (compiler) : 9058
YES
This next bit looks illegal...
4503
So why no RTE?
And this next bit looks to be governed the same way by veneer code...

[** Programming error: tried to read outside memory using -> **]
1
So why does *that* get an RTE?

Crosscheck
An Interactive Fiction
Release 1 / Serial number 211223 / Inform 7 build 6M62 (I6/v6.33 lib 6/12N) SD

The strange part is the line that says “4503”. This is apparently the result of the result of I6 command:

print 0-->-2

If someone can offer insight as to why this command is not generating an RTE but the very similar command:

print 0->-4

does generate one (that’s the [** Programming error: tried to read outside memory using -> **] message), I would be very grateful.

For the benefit of anyone taking a look at this, the generated I6 code for the when play begins rule is:

I6 code produced
! ----------------------------------------------------------------------------------------------------
! Rule 1/1 ! When play begins:
! ----------------------------------------------------------------------------------------------------
! No specific request
! When play begins:
[ R_773 ;
    if (debug_rules) DB_Rule(R_773, 773);
    ! [2: say ~static memory start (header) : [static memory start from header][line break]~]
    say__p=1;! [3: ~static memory start (header) : ~]
    ParaContent(); print "static memory start (header) : ";! [4: static memory start from header]
    ParaContent(); print (BlkPrintHexadecimal) HDR_STATICMEMORY-->0;! [5: line break]
    ParaContent(); new_line; .L_Say1; .L_SayX1;! [6: say ~static memory start (compiler) : [static memory start from compiler][line break]~]
    say__p=1;! [7: ~static memory start (compiler) : ~]
    ParaContent(); print "static memory start (compiler) : ";! [8: static memory start from compiler]
    ParaContent(); print (BlkPrintHexadecimal) #static_memory_offset;! [9: line break]
    ParaContent(); new_line; .L_Say2; .L_SayX2;! [10: say ~high memory start (header) : [high memory start from header][line break]~]
    say__p=1;! [11: ~high memory start (header) : ~]
    ParaContent(); print "high memory start (header) : ";! [12: high memory start from header]
    ParaContent(); print (BlkPrintHexadecimal) HDR_HIGHMEMORY-->0;! [13: line break]
    ParaContent(); new_line; .L_Say3; .L_SayX3;! [14: say ~high memory start (compiler) : [high memory start from compiler][line break]~]
    say__p=1;! [15: ~high memory start (compiler) : ~]
    ParaContent(); print "high memory start (compiler) : ";! [16: high memory start from compiler]
    ParaContent(); print (BlkPrintHexadecimal) #readable_memory_offset;! [17: line break]
    ParaContent(); new_line; .L_Say4; .L_SayX4;! [18: validate equivalency]
    if ((0+(-4)) == (0+2*(-2))) print "YES"; else print "NO"; new_line;
    ! [19: say ~This next bit looks illegal...~]
    say__p=1;! [20: ~This next bit looks illegal...~]
    ParaContent(); print "This next bit looks illegal..."; new_line; .L_Say5; .L_SayX5;! [21: say memory value at word -2]
    say__p=1;! [22: memory value at word -2]
    ParaContent(); print 0-->-2, "^"; .L_Say6; .L_SayX6;! [23: say ~So why no RTE?~]     ! <------- ** HARDCODED **
    say__p=1;! [24: ~So why no RTE?~]
    ParaContent(); print "So why no RTE?"; new_line; .L_Say7; .L_SayX7;! [25: say ~And this next bit looks to be governed the same way by veneer code...~]
    say__p=1;! [26: ~And this next bit looks to be governed the same way by veneer code...~]
    ParaContent(); print "And this next bit looks to be governed the same way by veneer code..."; new_line; .L_Say8; .L_SayX8;! [27: say memory value at byte -4]
    say__p=1;! [28: memory value at byte -4]
    ParaContent(); print 0->-4, "^"; .L_Say9; .L_SayX9;! [29: say ~So why does *that* get an RTE?~]     ! <------- ** HARDCODED **
    say__p=1;! [30: ~So why does *that* get an RTE?~]
    ParaContent(); print "So why does *that* get an RTE?"; new_line; .L_Say10; .L_SayX10;rfalse;
];
! ----------------------------------------------------------------------------------------------------

to which I’ve added two comments to highlight the points of interest.

1 Like

Because the I7 template layer throws out I6’s array-bounds checking, even when strict mode is on.

See ZMachine.i6t: Veneer.

Thank you very much! Another blind spot filled – it did not occur to me that the I7 templates might include that sort of thing.