The Z-machine specification says that it is illegal to use
@put_prop or @get_prop opcodes when a common property is longer than two bytes,
and that the result is unspecified.
Zip and Frotz follow Infocom interpreters in corrupting the object table when @put_prop is used,
but other interpreters give a variety of responses to either opcode.
Authors can, however, unwittingly compile such instructions,
for example when an additive property is accessed using the '.' operator
(see L61025 for an example in the library itself). It might be expected that Strict mode would check for this illegal access, but it doesn't. Add a new veneer routine that can produce a run-time error for property reading.
The following patch is based on the bi-platform compiler distributed as inform-6.21.4.tar.gz,
although the check is not actually needed in Glulx.
About Patches
Issue C62125
Strict check for property array access
Submitted by: Cedric Knight
Appeared in: Compiler 6.21 or before
Fixed in: Compiler 6.30
Problem
Solution
diff -u inform-6.21.4/src/expressc.c inform/src/expressc.c
--- inform-6.21.4/src/expressc.c Fri Aug 25 03:58:30 2000
+++ inform/src/expressc.c Sat Aug 9 12:21:20 2003
@@ -1666,7 +1666,9 @@
case PROPERTY_OP:
{ assembly_operand AO = ET[below].value;
if (runtime_error_checking_switch && (!veneer_mode))
- AO = check_nonzero_at_runtime(AO, -1, PROPERTY_RTE);
+ assemblez_3_to(call_vs_zc, veneer_routine(RT__ChPR_VR),
+ AO, ET[ET[below].right].value, temp_var1);
+ else
assemblez_2_to(get_prop_zc, AO,
ET[ET[below].right].value, temp_var1);
if (!void_flag) write_result_z(Result, temp_var1);
diff -u inform-6.21.4/src/header.h inform/src/header.h
--- inform-6.21.4/src/header.h Fri Jun 13 08:59:05 2003
+++ inform/src/header.h Sat Aug 9 11:55:15 2003
@@ -1632,7 +1632,7 @@
/* (must correspond to entries in the table in "veneer.c") */
/* ------------------------------------------------------------------------- */
-#define VENEER_ROUTINES 46
+#define VENEER_ROUTINES 47
#define Box__Routine_VR 0
@@ -1669,22 +1669,23 @@
#define RT__ChG_VR 29
#define RT__ChGt_VR 30
#define RT__ChPS_VR 31
-#define RT__TrPS_VR 32
-#define RT__ChLDB_VR 33
-#define RT__ChLDW_VR 34
-#define RT__ChSTB_VR 35
-#define RT__ChSTW_VR 36
-#define RT__ChPrintC_VR 37
-#define RT__ChPrintA_VR 38
-#define RT__ChPrintS_VR 39
-#define RT__ChPrintO_VR 40
+#define RT__ChPR_VR 32
+#define RT__TrPS_VR 33
+#define RT__ChLDB_VR 34
+#define RT__ChLDW_VR 35
+#define RT__ChSTB_VR 36
+#define RT__ChSTW_VR 37
+#define RT__ChPrintC_VR 38
+#define RT__ChPrintA_VR 39
+#define RT__ChPrintS_VR 40
+#define RT__ChPrintO_VR 41
/* Glulx-only veneer routines */
-#define OB__Move_VR 41
-#define OB__Remove_VR 42
-#define Print__Addr_VR 43
-#define Glk__Wrap_VR 44
-#define Dynam__String_VR 45
+#define OB__Move_VR 42
+#define OB__Remove_VR 43
+#define Print__Addr_VR 44
+#define Glk__Wrap_VR 45
+#define Dynam__String_VR 46
/* ------------------------------------------------------------------------- */
/* Run-time-error numbers (must correspond with RT__Err code in veneer) */
diff -u inform-6.21.4/src/veneer.c inform/src/veneer.c
--- inform-6.21.4/src/veneer.c Fri Jun 13 08:59:05 2003
+++ inform/src/veneer.c Sat Aug 9 11:56:52 2003
@@ -222,9 +222,10 @@
"obj identifier x;\
x = obj..&identifier;\
if (x==0)\
- { if (identifier >= 1 && identifier < 64)\
+ { if (identifier >= 1 && identifier < 64 && obj.#identifier <= 2)\
return obj.identifier;\
RT__Err(\"read\", obj, identifier); return; }\
+ if (obj.#identifier > 2) RT__Err(\"read\", obj, identifier, 2);\
return x-->0;\
]", "", "", "", "", ""
},
@@ -586,7 +587,8 @@
if (obj) @print_obj obj;else print \"nothing\";print\" \";}\
print \"(object number \", obj, \") \";\
if (id<0) print \"is not of class \", (name) -id;",
- "else\
+ "else if (size) print \".\", (property) id, \" is not of size 2\";\
+ else\
{ print \" has no property \", (property) id;\
p = #identifiers_table;\
size = p-->0;\
@@ -777,9 +779,9 @@
cause error and do nothing if not; otherwise make it */
"RT__ChPS",
- "obj prop val;\
- if (obj<5 || obj>(#largest_object-255) || obj in 1 || obj.&prop==0)\
- return RT__Err(\"set\", obj, prop);\
+ "obj prop val size;\
+ if (obj<5 || obj>(#largest_object-255) || obj in 1 || obj.&prop==0 || (size=obj.#prop)>2 )\
+ return RT__Err(\"set\", obj, prop, size);\
@put_prop obj prop val;",
"#ifdef INFIX;\
if (obj has infix__watching || (debug_flag & 15)) RT__TrPS(obj,prop,val);\
@@ -788,6 +790,16 @@
#endif; #endif;\
return val; ]", "", "", "", ""
},
+ { /* RT__ChPR: check at run-time that a proposed property read is legal
+ cause error and return 0 if not; otherwise read it */
+
+ "RT__ChPR",
+ "obj prop val size;\
+ if (obj<5 || obj>(#largest_object-255) || (size=obj.#prop)>2)\
+ {RT__Err(\"read\", obj, prop, size); obj=2;}\
+ @get_prop obj prop -> val;",
+ "return val; ]", "", "", "", ""
+ },
{ /* RT__TrPS: trace property settings */
"RT__TrPS",
@@ -1665,6 +1677,15 @@
return res;\
]", "", "", "", "", ""
},
+ { /* RT__ChPR: check at run-time that a proposed property read is legal.
+ cause error and return 0 if not; otherwise read it */
+ "RT__ChPR",
+ "obj prop val;\
+ if (obj==0 or Class or String or Routine or Object || Z_Region(obj)~=1 )\
+ {RT__Err(\"read\", obj, prop); obj=2;}\
+ val = RV__Pr(obj, prop);",
+ "return val; ]", "", "", "", ""
+ },
{ /* RT__TrPS: trace property settings */
"RT__TrPS",
@@ -1947,6 +1968,7 @@
case RT__ChT_VR:
case RT__ChG_VR:
case RT__ChGt_VR:
+ case RT__ChPR_VR:
mark_as_needed_z(RT__Err_VR);
return;
case RT__ChPS_VR:
@@ -2075,6 +2097,9 @@
mark_as_needed_g(RT__TrPS_VR);
mark_as_needed_g(WV__Pr_VR);
return;
+ case RT__ChPR_VR:
+ mark_as_needed_g(RT__Err_VR);
+ mark_as_needed_g(RV__Pr_VR); return;
case RT__ChLDB_VR:
case RT__ChLDW_VR:
case RT__ChSTB_VR:
Last updated 17 April 2013.
This site is no longer supported; information may be out of date.
Maintained as a historical archive by the Interactive Fiction Technology Foundation.
Copyright 1993-2018 IFTF, CC-BY-SA unless otherwise noted.
This page was originally managed by Roger Firth.