《Infidel》通过一个特殊的房间 ENDLESS‑DESERT 模拟广阔的空旷沙漠,该房间代表所有未映射的位置;当玩家在此处放置物品时,游戏会将它们的坐标和对象 ID 存储在名为 DESERT‑TABLE 的数组中,以便玩家返回同一位置时可以恢复。DESERT‑TO‑TABLE 例程执行此操作,遍历无尽沙漠中的所有可携带物品,并将每个物品的 ID 及其 SLOC 坐标写入表中。(来源:主要)
错误在于 ZIL 编译器对该例程可选 TBL 参数的处理方式。该参数应默认为 DESERT‑TABLE 的地址,但编译器在例程开始时将常量值 30(全局 DESERT‑TABLE 变量的索引号)存入 TBL。因此,当 DESERT‑TO‑TABLE 写入物品数据时,它实际上写入起始地址为 30 的内存位置,而不是预期的地址 11129,从而形成野指针,损坏低内存。(来源:主要)
由于 Z‑machine 版本 3 的前 64 字节存储头部数据,地址 30‑63 未被使用,但地址 64 开始的是用于文本压缩的缩写表。在无尽沙漠中放置九个或更多物品会覆盖该表的起始部分,导致第一个缩写(“the”)被写入的任意字节模式替换——在游戏输出中观察到 “You” 取代了 “the”。在某些情况下,损坏会使打印例程进入无限循环,导致解释器崩溃。由于极少玩家会在荒芜的无尽沙漠中放置超过八个物品,因此此内存损坏多年未被发现。(来源:主要)
类似的缺陷也存在于配对的 TABLE‑TO‑DESERT 例程中,它从同一个错误地址读取数据;此外,PROP‑TO‑TBL / TBL‑TO‑PROP 配对与 PROP‑TBL 表共享同样的模式。修复此问题的方法是:要么移除 TBL 的默认值并在例程开头插入 <SET TBL ,DESERT‑TABLE>,要么在调用时显式将 DESERT‑TABLE 作为第二个参数传递。(来源:主要)
