Another fix for /usr/games/hack

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Another fix for /usr/games/hack

tonypony76
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 | Threaded
Open this post in threaded view
|

Re: Another fix for /usr/games/hack

tonypony76
Today I have discovered a second segmentation fault in /usr/games/hack.
In particular, if a game is saved while a potion of levitation is in
effect, then the restored game may crash when the potion wears off.
This problem is caused by the same sort of issue that caused the
previously-reported segmentation fault.  A patch for this new
segmentation fault is included below.

This patch, together with my previous two patches

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

are all that is needed to fix /usr/games/hack on OpenBSD 6.2.  The
patches can be applied in any order.


--- games/hack/hack.timeout.c.orig Sat Jan  9 18:33:15 2016
+++ games/hack/hack.timeout.c Sat Mar 10 23:11:05 2018
@@ -73,7 +73,7 @@
  if(Stoned) stoned_dialogue();
  for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++)
     if((upp->p_flgs & TIMEOUT) && !--upp->p_flgs) {
- if(upp->p_tofn) (*upp->p_tofn)();
+ if(upp->p_tofn) float_down();
  else switch(upp - u.uprops){
  case STONED:
  killer = "cockatrice";