]> granicus.if.org Git - nethack/commitdiff
Qt tombstone bugs
authorPatR <rankin@nethack.org>
Thu, 20 Aug 2020 23:56:50 +0000 (16:56 -0700)
committerPatR <rankin@nethack.org>
Thu, 20 Aug 2020 23:56:50 +0000 (16:56 -0700)
Infrastructure bits:  Qt tombstone uses a short buffer; make sure that
the plname value fits instead of relying on snprintf() to truncate it.
A warning about gold, if any, was iffy but this should guarantee no
reason for future complaint.  Year was safe but a compiler sensitive
to buffer overflows wouldn't know that.

Actual bugs:  Qt used money in inventory for gold amount on tombstone;
that overlooks gold in containers and will be 0 by tombstone stage if
bones get saved.  Year was recalculated from current date+time instead
of using the value that gets passed in--blindly flagging that variable
as UNUSED was a mistake.

doc/fixes37.0
include/wincurs.h
src/rip.c
win/Qt/qt_menu.cpp
win/X11/wintext.c
win/curses/cursmain.c

index 64988cf116ee482037d3c956619642d40ed5bdee..4a638b5f0ea75fea3c4d868871f1972e25e0e5e3 100644 (file)
@@ -1,4 +1,4 @@
-NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.288 $ $NHDT-Date: 1597707740 2020/08/17 23:42:20 $
+NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.289 $ $NHDT-Date: 1597967807 2020/08/20 23:56:47 $
 
 General Fixes and Modified Features
 -----------------------------------
@@ -383,6 +383,12 @@ Qt: "paper doll" subset of persistent inventory has undergone several changes:
        first active light source in a previously unused slot on lower right;
        show first leash-in-use in a previously unused slot on lower left
 Qt: paper doll inventory view was inconsistently updated during Hallucination
+Qt: when hero died, gold on tombstone only included gold in inventory, not
+       any additional gold inside carried containers; also, inventory gold
+       will be zero if bones get created for all 3.6.x and for 3.4.x+GOLDOBJ
+Qt: tombstone showed newly constructed date instead of the value set up at
+       time of death; it only shows year but that could be wrong if player
+       stared at or ignored prior --More-- for long enough on 31 December
 Qt+QSX: fix control key
 Qt+OSX: rename menu entry "nethack->Preferences..." for invoking nethack's
        'O' command to "Game->Run-time options" and entry "Game->Qt settings"
index ad7be208392e57a0e22e086f9ccefe5696554de3..4e5ce4e78645b548e054748f5e780d65b840d80c 100644 (file)
@@ -105,7 +105,7 @@ extern void curses_number_pad(int state);
 extern void curses_delay_output(void);
 extern void curses_start_screen(void);
 extern void curses_end_screen(void);
-extern void curses_outrip(winid wid, int how);
+extern void curses_outrip(winid wid, int how, time_t when);
 extern void genl_outrip(winid tmpwin, int how, time_t when);
 extern void curses_preference_update(const char *pref);
 extern void curs_reset_windows(boolean, boolean);
index 2996d21a26f72c2b2d93af98aa85f66bcbc2fd1e..dca074720970d98dd95a5099bf942a8521f5d5b8 100644 (file)
--- a/src/rip.c
+++ b/src/rip.c
@@ -1,4 +1,4 @@
-/* NetHack 3.7 rip.c   $NHDT-Date: 1596498204 2020/08/03 23:43:24 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.32 $ */
+/* NetHack 3.7 rip.c   $NHDT-Date: 1597967808 2020/08/20 23:56:48 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.33 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2017. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -60,12 +60,10 @@ static const char *rip_txt[] = {
 };
 #define STONE_LINE_CENT 19 /* char[] element of center of stone face */
 #endif                     /* NH320_DEDICATION */
-#define STONE_LINE_LEN                               \
-    16               /* # chars that fit on one line \
-                      * (note 1 ' ' border)          \
-                      */
-#define NAME_LINE 6  /* *char[] line # for player name */
-#define GOLD_LINE 7  /* *char[] line # for amount of gold */
+#define STONE_LINE_LEN  16 /* # chars that fit on one line
+                            * (note 1 ' ' border)           */
+#define NAME_LINE  6 /* *char[] line # for player name */
+#define GOLD_LINE  7 /* *char[] line # for amount of gold */
 #define DEATH_LINE 8 /* *char[] line # for death description */
 #define YEAR_LINE 12 /* *char[] line # for year */
 
@@ -90,9 +88,9 @@ time_t when;
     register char **dp;
     register char *dpx;
     char buf[BUFSZ];
-    long year;
     register int x;
-    int line;
+    int line, year;
+    long cash;
 
     g.rip = dp = (char **) alloc(sizeof(rip_txt));
     for (x = 0; rip_txt[x]; ++x)
@@ -100,13 +98,15 @@ time_t when;
     dp[x] = (char *) 0;
 
     /* Put name on stone */
-    Sprintf(buf, "%s", g.plname);
-    buf[STONE_LINE_LEN] = 0;
+    Sprintf(buf, "%.*s", (int) STONE_LINE_LEN, g.plname);
     center(NAME_LINE, buf);
 
     /* Put $ on stone */
-    Sprintf(buf, "%ld Au", g.done_money);
-    buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */
+    cash = max(g.done_money, 0L);
+    /* arbitrary upper limit; practical upper limit is quite a bit less */
+    if (cash > 999999999L)
+        cash = 999999999L;
+    Sprintf(buf, "%ld Au", cash);
     center(GOLD_LINE, buf);
 
     /* Put together death description */
@@ -114,11 +114,11 @@ time_t when;
 
     /* Put death type on stone */
     for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; line++) {
-        register int i, i0;
         char tmpchar;
+        int i, i0 = (int) strlen(dpx);
 
-        if ((i0 = strlen(dpx)) > STONE_LINE_LEN) {
-            for (i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--)
+        if (i0 > STONE_LINE_LEN) {
+            for (i = STONE_LINE_LEN; (i > 0) && (i0 > STONE_LINE_LEN); --i)
                 if (dpx[i] == ' ')
                     i0 = i;
             if (!i)
@@ -135,8 +135,8 @@ time_t when;
     }
 
     /* Put year on stone */
-    year = yyyymmdd(when) / 10000L;
-    Sprintf(buf, "%4ld", year);
+    year = (int) ((yyyymmdd(when) / 10000L) % 10000L);
+    Sprintf(buf, "%4d", year);
     center(YEAR_LINE, buf);
 
 #ifdef DUMPLOG
index b3d192eb188b8975bff4241f013e7bcaf2ae360d..817449ee7f3727bcc3fd0ffda3c22f3054935b68 100644 (file)
@@ -653,7 +653,7 @@ bool NetHackQtTextWindow::Destroy()
     return !isVisible();
 }
 
-void NetHackQtTextWindow::UseRIP(int how, time_t when UNUSED)
+void NetHackQtTextWindow::UseRIP(int how, time_t when)
 {
 // Code from X11 windowport
 #define STONE_LINE_LEN 16    /* # chars that fit on one line */
@@ -677,41 +677,63 @@ static char** rip_line=0;
     int line;
 
     /* Put name on stone */
-    snprintf(rip_line[NAME_LINE], STONE_LINE_LEN+1, "%s", g.plname);
-
-    /* Put $ on stone */
-    snprintf(rip_line[GOLD_LINE], STONE_LINE_LEN+1, "%ld Au", money_cnt(g.invent));
+    (void) snprintf(rip_line[NAME_LINE], STONE_LINE_LEN + 1,
+                    "%.*s", STONE_LINE_LEN, g.plname);
+
+    /* Put $ on stone;
+       to keep things safe and relatively simple, impose an arbitrary
+       upper limit that's the same for 64 bit and 32 bit configurations
+       (also 16 bit configurations provided they use 32 bit long); the
+       upper limit for directly carried gold is somewhat less than 300K
+       due to carrying capacity, but end-of-game handling has already
+       added in gold from containers, so the amount could be much more
+       (simplest case: ~300K four times in a blessed bag of holding, so
+       ~1.2M; in addition to the hassle of getting such a thing set up,
+       it would need many gold-rich bones levels or wizard mode wishing) */
+    long cash = std::max(g.done_money, 0L);
+    /* force less that 10 digits to satisfy elaborate format checking;
+       it's arbitrary but still way, way more than could ever be needed */
+    if (cash > 999999999L)
+        cash = 999999999L;
+    (void) snprintf(rip_line[GOLD_LINE], STONE_LINE_LEN + 1, "%ld Au", cash);
 
     /* Put together death description */
     formatkiller(buf, sizeof buf, how, FALSE);
     //str_copy(buf, killer, SIZE(buf));
 
     /* Put death type on stone */
-    for (line=DEATH_LINE, dpx = buf; line<YEAR_LINE; line++) {
-       int i,i0;
+    for (line = DEATH_LINE, dpx = buf; line < YEAR_LINE; ++line) {
        char tmpchar;
-
-       if ( (i0=strlen(dpx)) > STONE_LINE_LEN) {
-           for(i = STONE_LINE_LEN;
-               ((i0 > STONE_LINE_LEN) && i); i--)
-               if(dpx[i] == ' ') i0 = i;
-           if(!i) i0 = STONE_LINE_LEN;
+       int i, i0 = (int) strlen(dpx);
+
+       if (i0 > STONE_LINE_LEN) {
+           for (i = STONE_LINE_LEN; (i > 0) && (i0 > STONE_LINE_LEN); --i)
+               if (dpx[i] == ' ')
+                    i0 = i;
+           if (!i)
+                i0 = STONE_LINE_LEN;
        }
        tmpchar = dpx[i0];
        dpx[i0] = 0;
-       str_copy(rip_line[line], dpx, STONE_LINE_LEN+1);
+       (void) str_copy(rip_line[line], dpx, STONE_LINE_LEN + 1);
        if (tmpchar != ' ') {
            dpx[i0] = tmpchar;
            dpx= &dpx[i0];
-       } else  dpx= &dpx[i0+1];
+       } else {
+            dpx= &dpx[i0 + 1];
+        }
     }
 
-    /* Put year on stone */
-    snprintf(rip_line[YEAR_LINE], STONE_LINE_LEN+1, "%4d", getyear());
-
-    rip.setLines(rip_line,YEAR_LINE+1);
+    /* Put year on stone;
+       64 bit configuration with 64 bit int is capable of overflowing
+       STONE_LINE_LEN characters; a compiler might warn about that,
+       so force a value that it can recognize as fitting within buffer's
+       range ("%4d" imposes a minimum number of digits, not a maximum) */
+    int year = (int) ((yyyymmdd(when) / 10000L) % 10000L); /* Y10K bug! */
+    (void) snprintf(rip_line[YEAR_LINE], STONE_LINE_LEN + 1, "%4d", year);
 
-    use_rip=true;
+    rip.setLines(rip_line, YEAR_LINE + 1);
+    use_rip = true;
 }
 
 void NetHackQtTextWindow::Clear()
@@ -820,8 +842,9 @@ void NetHackQtMenuOrTextWindow::StartMenu()
     if (!actual) actual=new NetHackQtMenuWindow(parent);
     actual->StartMenu();
 }
-void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr,
-       const QString& str, unsigned itemflags)
+void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier,
+                                        char ch, char gch, int attr,
+                                        const QString& str, unsigned itemflags)
 {
     if (!actual) impossible("AddMenu called before we know if Menu or Text");
     actual->AddMenu(glyph,identifier,ch,gch,attr,str,itemflags);
index 2a8f19315c412ff30e827dd12b027b410e5bb91f..a6c2737b84ac45860914bfb4cb020a9e26129d06 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 wintext.c       $NHDT-Date: 1596498376 2020/08/03 23:46:16 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.21 $ */
+/* NetHack 3.7 wintext.c       $NHDT-Date: 1597967808 2020/08/20 23:56:48 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.22 $ */
 /* Copyright (c) Dean Luick, 1992                                */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -489,14 +489,20 @@ calculate_rip_text(int how, time_t when)
 
     char buf[BUFSZ];
     char *dpx;
-    int line;
-    long year;
+    int line, year;
+    long cash;
 
     /* Put name on stone */
     Sprintf(rip_line[NAME_LINE], "%s", g.plname);
 
     /* Put $ on stone */
-    Sprintf(rip_line[GOLD_LINE], "%ld Au", g.done_money);
+    cash = max(g.done_money, 0L);
+    /* arbitrary upper limit; practical upper limit is quite a bit less */
+    if (cash > 999999999L)
+        cash = 999999999L;
+    Sprintf(buf, "%ld Au", cash);
+    Sprintf(rip_line[GOLD_LINE], "%ld Au", cash);
+
     /* Put together death description */
     formatkiller(buf, sizeof buf, how, FALSE);
 
@@ -523,8 +529,8 @@ calculate_rip_text(int how, time_t when)
     }
 
     /* Put year on stone */
-    year = yyyymmdd(when) / 10000L;
-    Sprintf(rip_line[YEAR_LINE], "%4ld", year);
+    year = (int) ((yyyymmdd(when) / 10000L) % 10000L);
+    Sprintf(rip_line[YEAR_LINE], "%4d", year);
 }
 
 /*
index e098e163a6c33ced6deb79bed77bee8aec81b68f..4035b3c9f42e08bca366dd0eaf332e2a7e0f318a 100644 (file)
@@ -898,12 +898,13 @@ curses_end_screen()
 
 /*
 outrip(winid, int)
-            -- The tombstone code.  If you want the traditional code use
-               genl_outrip for the value and check the #if in rip.c.
+                -- The tombstone code.  We use genl_outrip() from rip.c
+                   instead of rolling our own.
 */
 void
 curses_outrip(winid wid UNUSED,
-              int how UNUSED)
+              int how UNUSED,
+              time_t when UNUSED)
 {
      return;
 }