Inform - Support - Patches

About Patches  

Compiler  
Library  

DM4 Errata  

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

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.

Solution

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.

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.