I recently wrote a patch that makes /usr/games/hack playable again.

 http://marc.info/?l=openbsd-tech&m=151986187422137

But now I've noticed that hack crashes with a segmentation fault when
the user requests the inventory list while playing a previously-saved
game.  I've discovered that when hack saves a game, it saves pointers to
addresses inside the executable, under the assumption that those
pointers will always be the same "as long as we use only one version of
Hack".  In OpenBSD, this assumption is not valid, and it causes a
segmentation fault when one process attempts to use a pointer that was
saved by another process.

A patch that fixes this problem is included below.


--- games/hack/hack.o_init.c.orig       Sat Jan  9 21:54:11 2016
+++ games/hack/hack.o_init.c    Sun Mar  4 20:20:19 2018
@@ -173,18 +173,29 @@
 {
        int i;
        unsigned len;
+       unsigned zero = 0;
 
        bwrite(fd, bases, sizeof bases);
        bwrite(fd, objects, sizeof objects);
-       /* as long as we use only one version of Hack/Quest we
-          need not save oc_name and oc_descr, but we must save
-          oc_uname for all objects */
        for(i=0; i < SIZE(objects); i++) {
+               if(objects[i].oc_name) {
+                       len = strlen(objects[i].oc_name)+1;
+                       bwrite(fd, &len, sizeof len);
+                       bwrite(fd, objects[i].oc_name, len);
+               } else
+                       bwrite(fd, &zero, sizeof len);
+               if(objects[i].oc_descr) {
+                       len = strlen(objects[i].oc_descr)+1;
+                       bwrite(fd, &len, sizeof len);
+                       bwrite(fd, objects[i].oc_descr, len);
+               } else
+                       bwrite(fd, &zero, sizeof len);
                if(objects[i].oc_uname) {
                        len = strlen(objects[i].oc_uname)+1;
                        bwrite(fd, &len, sizeof len);
                        bwrite(fd, objects[i].oc_uname, len);
-               }
+               } else
+                       bwrite(fd, &zero, sizeof len);
        }
 }
 
@@ -196,10 +207,25 @@
 
        mread(fd, (char *) bases, sizeof bases);
        mread(fd, (char *) objects, sizeof objects);
-       for(i=0; i < SIZE(objects); i++) if(objects[i].oc_uname) {
+       for(i=0; i < SIZE(objects); i++) {
                mread(fd, (char *) &len, sizeof len);
-               objects[i].oc_uname = (char *) alloc(len);
-               mread(fd, objects[i].oc_uname, len);
+               if(len) {
+                       objects[i].oc_name = (char *) alloc(len);
+                       mread(fd, objects[i].oc_name, len);
+               } else
+                       objects[i].oc_name = 0;
+               mread(fd, (char *) &len, sizeof len);
+               if(len) {
+                       objects[i].oc_descr = (char *) alloc(len);
+                       mread(fd, objects[i].oc_descr, len);
+               } else 
+                       objects[i].oc_descr = 0;
+               mread(fd, (char *) &len, sizeof len);
+               if(len) {
+                       objects[i].oc_uname = (char *) alloc(len);
+                       mread(fd, objects[i].oc_uname, len);
+               } else 
+                       objects[i].oc_uname = 0;
        }
 }
 

Reply via email to