]> granicus.if.org Git - nethack/commitdiff
Pending 3.7 edition of the naming overflow patch.
authorPatR <rankin@nethack.org>
Sat, 28 Jan 2023 00:35:35 +0000 (16:35 -0800)
committerPatR <rankin@nethack.org>
Sat, 28 Jan 2023 21:02:46 +0000 (13:02 -0800)
Like the 3.6.7 one, the original pieces have been combined into one
commit.  But it is separate from the one added to that version.

doc/fixes3-7-0.txt
src/do_name.c
src/invent.c
src/o_init.c
src/objnam.c

index 1915cd325c5f040863aae7e52c590efebef89794..73aa30191dcefb63a97b1b1c123088cc32b8e10a 100644 (file)
@@ -1,4 +1,4 @@
-HDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1051 $ $NHDT-Date: 1665130022 2022/10/07 08:07:02 $
+HDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.1093 $ $NHDT-Date: 1672605786 2023/01/01 20:43:06 $
 
 General Fixes and Modified Features
 -----------------------------------
@@ -1101,6 +1101,8 @@ eating garlic makes nearby monsters flee
 giants occasionally get a battle axe or a two-handed sword
 give gremlin the property it stole, if possible
 'F'orcefighting with a war hammer has a small chance of breaking iron bars
+player assigned name for monsters, specific objects, or object types could be
+       longer than what was intented to be allowed; for 'curses', much longer
 
 
 Fixes to 3.7.0-x Problems that Were Exposed Via git Repository
index ba1b352574369db7ea1a4d841d49db11e456e09a..670943d93c3717a2e642a916594d9eeca84e5003 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 do_name.c       $NHDT-Date: 1655663780 2022/06/19 18:36:20 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.254 $ */
+/* NetHack 3.7 do_name.c       $NHDT-Date: 1672605786 2023/01/01 20:43:06 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.280 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Pasi Kallinen, 2018. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -19,6 +19,7 @@ static void gloc_filter_done(void);
 static boolean gather_locs_interesting(coordxy, coordxy, int);
 static void gather_locs(coord **, int *, int);
 static void truncate_to_map(int *, int *, schar, schar);
+static char *name_from_player(char *, const char *, const char *);
 static void do_mgivenname(void);
 static boolean alreadynamed(struct monst *, char *, char *);
 static void do_oname(struct obj *);
@@ -1180,6 +1181,34 @@ safe_oname(struct obj *obj)
     return "";
 }
 
+/* get a name for a monster or an object from player;
+   truncate if longer than PL_PSIZ, then return it */
+static char *
+name_from_player(
+    char *outbuf,       /* output buffer, assumed to be at least BUFSZ long;
+                         * anything longer than PL_PSIZ will be truncated */
+    const char *prompt,
+    const char *defres) /* only used if EDIT_GETLIN is enabled; only useful
+                         * if windowport xxx's xxx_getlin() supports that */
+{
+    outbuf[0] = '\0';
+#ifdef EDIT_GETLIN
+    if (defres && *defres)
+        Strcpy(outbuf, defres); /* default response from getlin() */
+#else
+    nhUse(defres);
+#endif
+    getlin(prompt, outbuf);
+    if (!*outbuf || *outbuf == '\033')
+        return NULL;
+
+    /* strip leading and trailing spaces, condense internal sequences */
+    (void) mungspaces(outbuf);
+    if (strlen(outbuf) >= PL_PSIZ)
+        outbuf[PL_PSIZ - 1] = '\0';
+    return outbuf;
+}
+
 /* historical note: this returns a monster pointer because it used to
    allocate a new bigger block of memory to hold the monster and its name */
 struct monst *
@@ -1290,17 +1319,10 @@ do_mgivenname(void)
     /* special case similar to the one in lookat() */
     Sprintf(qbuf, "What do you want to call %s?",
             distant_monnam(mtmp, ARTICLE_THE, monnambuf));
-    buf[0] = '\0';
-#ifdef EDIT_GETLIN
-    /* if there's an existing name, make it be the default answer */
-    if (has_mgivenname(mtmp))
-        Strcpy(buf, MGIVENNAME(mtmp));
-#endif
-    getlin(qbuf, buf);
-    if (!*buf || *buf == '\033')
+    /* use getlin() to get a name string from the player */
+    if (!name_from_player(buf, qbuf,
+                          has_mgivenname(mtmp) ? MGIVENNAME(mtmp) : NULL))
         return;
-    /* strip leading and trailing spaces; unnames monster if all spaces */
-    (void) mungspaces(buf);
 
     /* Unique monsters have their own specific names or titles.
      * Shopkeepers, temple priests and other minions use alternate
@@ -1348,17 +1370,9 @@ do_oname(struct obj *obj)
     Sprintf(qbuf, "What do you want to name %s ",
             is_plural(obj) ? "these" : "this");
     (void) safe_qbuf(qbuf, qbuf, "?", obj, xname, simpleonames, "item");
-    buf[0] = '\0';
-#ifdef EDIT_GETLIN
-    /* if there's an existing name, make it be the default answer */
-    if (has_oname(obj))
-        Strcpy(buf, ONAME(obj));
-#endif
-    getlin(qbuf, buf);
-    if (!*buf || *buf == '\033')
+    /* use getlin() to get a name string from the player */
+    if (!name_from_player(buf, qbuf, safe_oname(obj)))
         return;
-    /* strip leading and trailing spaces; unnames item if all spaces */
-    (void) mungspaces(buf);
 
     /*
      * We don't violate illiteracy conduct here, although it is
@@ -1701,14 +1715,8 @@ docall(struct obj *obj)
                          docall_xname, simpleonames, "thing");
     /* pointer to old name */
     str1 = &(objects[obj->otyp].oc_uname);
-    buf[0] = '\0';
-#ifdef EDIT_GETLIN
-    /* if there's an existing name, make it be the default answer */
-    if (*str1)
-        Strcpy(buf, *str1);
-#endif
-    getlin(qbuf, buf);
-    if (!*buf || *buf == '\033')
+    /* use getlin() to get a name string from the player */
+    if (!name_from_player(buf, qbuf, *str1))
         return;
 
     /* clear old name */
index 6682d75f545dc84dbaacd996d7997d927556bf17..e144911c86a576893964517629f7ed28b53954db 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 invent.c        $NHDT-Date: 1661240719 2022/08/23 07:45:19 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.424 $ */
+/* NetHack 3.7 invent.c        $NHDT-Date: 1672827802 2023/01/04 10:23:22 $  $NHDT-Branch: naming-overflow-fix $:$NHDT-Revision: 1.439 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Derek S. Ray, 2015. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -2567,17 +2567,21 @@ prinv(const char *prefix, struct obj *obj, long quan)
 DISABLE_WARNING_FORMAT_NONLITERAL
 
 char *
-xprname(struct obj *obj,
-        const char *txt, /* text to print instead of obj */
-        char let,        /* inventory letter */
-        boolean dot,     /* append period; (dot && cost => Iu) */
-        long cost,       /* cost (for inventory of unpaid or expended items) */
-        long quan)       /* if non-0, print this quantity, not obj->quan */
+xprname(
+    struct obj *obj,
+    const char *txt, /* text to print instead of obj */
+    char let,        /* inventory letter */
+    boolean dot,     /* append period; (dot && cost => Iu) */
+    long cost,       /* cost (for inventory of unpaid or expended items) */
+    long quan)       /* if non-0, print this quantity, not obj->quan */
 {
     static char li[BUFSZ];
+    char suffix[80]; /* plenty of room for count and hallucinatory currency */
+    int sfxlen, txtlen; /* signed int for %*s formatting */
+    const char *fmt;
     boolean use_invlet = (flags.invlet_constant
                           && let != CONTAINED_SYM && let != HANDS_SYM);
-    long savequan = 0;
+    long savequan = 0L;
 
     if (quan && obj) {
         savequan = obj->quan;
@@ -2589,18 +2593,33 @@ xprname(struct obj *obj,
      *  *  Then obj == null and we are printing a total amount.
      *  >  Then the object is contained and doesn't have an inventory letter.
      */
-    if (cost != 0 || let == '*') {
+    fmt = "%c - %.*s%s";
+    if (!txt)
+        txt = doname(obj);
+    txtlen = (int) strlen(txt);
+
+    if (cost != 0L || let == '*') {
         /* if dot is true, we're doing Iu, otherwise Ix */
-        Sprintf(li,
-                iflags.menu_tab_sep ? "%c - %s\t%6ld %s"
-                                    : "%c - %-45s %6ld %s",
-                (dot && use_invlet ? obj->invlet : let),
-                (txt ? txt : doname(obj)), cost, currency(cost));
+        if (dot && use_invlet)
+            let = obj->invlet;
+        Sprintf(suffix, "%c%6ld %.50s", iflags.menu_tab_sep ? '\t' : ' ',
+                cost, currency(cost));
+        if (!iflags.menu_tab_sep) {
+            fmt = "%c - %-45.*s%s";
+            if (txtlen < 45)
+                txtlen = 45;
+        }
     } else {
         /* ordinary inventory display or pickup message */
-        Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let),
-                (txt ? txt : doname(obj)), (dot ? "." : ""));
+        if (use_invlet)
+            let = obj->invlet;
+        Strcpy(suffix, dot ? "." : "");
     }
+    sfxlen = (int) strlen(suffix);
+    if (txtlen > BUFSZ - 1 - (4 + sfxlen)) /* 4: "c - " prefix */
+        txtlen = BUFSZ - 1 - (4 + sfxlen);
+    Sprintf(li, fmt, let, txtlen, txt, suffix);
+
     if (savequan)
         obj->quan = savequan;
 
index 50526b83720b276ab116376cb57d6112dbe493cc..f3da16d9c76710100d978145abb1f1103bd1c470 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 o_init.c        $NHDT-Date: 1646950588 2022/03/10 22:16:28 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.56 $ */
+/* NetHack 3.7 o_init.c        $NHDT-Date: 1672829455 2023/01/04 10:50:55 $  $NHDT-Branch: naming-overflow-fix $:$NHDT-Revision: 1.68 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2011. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -11,6 +11,7 @@ static void shuffle_all(void);
 static int QSORTCALLBACK discovered_cmp(const genericptr, const genericptr);
 static char *sortloot_descr(int, char *);
 static char *disco_typename(int);
+static void disco_append_typename(char *, int);
 static char *oclass_to_name(char, char *);
 
 #ifdef TILES_IN_GLYPHMAP
@@ -651,6 +652,30 @@ disco_typename(int otyp)
     return result;
 }
 
+/* append typename(dis) to buf[], possibly truncating in the process */
+static void
+disco_append_typename(char *buf, int dis)
+{
+    unsigned len = (unsigned) strlen(buf);
+    char *p, *typnm = disco_typename(dis);
+
+    if (len + (unsigned) strlen(typnm) < BUFSZ) {
+        /* ordinary */
+        Strcat(buf, typnm);
+    } else if ((p = strrchr(typnm, '(')) != 0
+               && p > typnm && p[-1] == ' ' && strchr(p, ')') != 0) {
+        /* typename() returned "really long user-applied name (actual type)"
+           and we want to truncate from "really long user-applied name" while
+           keeping " (actual type)" intact */
+        --p; /* back up to space in front of open paren */
+        (void) strncat(buf, typnm, BUFSZ - 1 - (len + (unsigned) strlen(p)));
+        Strcat(buf, p);
+    } else {
+        /* unexpected; just truncate from end of typename */
+        (void) strncat(buf, typnm, BUFSZ - 1 - len);
+    }
+}
+
 /* the #known command - show discovered object types */
 int
 dodiscovered(void) /* free after Robert Viduya */
@@ -734,7 +759,7 @@ dodiscovered(void) /* free after Robert Viduya */
                 Strcpy(buf,  objects[dis].oc_pre_discovered ? "* " : "  ");
                 if (lootsort)
                     (void) sortloot_descr(dis, &buf[2]);
-                Strcat(buf, disco_typename(dis));
+                disco_append_typename(buf, dis);
 
                 if (!alphabetized && !lootsort)
                     putstr(tmpwin, 0, buf);
@@ -966,7 +991,7 @@ doclassdisco(void)
                 Strcpy(buf,  objects[dis].oc_pre_discovered ? "* " : "  ");
                 if (lootsort)
                     (void) sortloot_descr(dis, &buf[2]);
-                Strcat(buf, disco_typename(dis));
+                disco_append_typename(buf, dis);
 
                 if (!alphabetized && !lootsort)
                     putstr(tmpwin, 0, buf);
index 960247ac32f22313a750e89887f4b7057c757ec5..7385b65c10b6d003f98b89ffe3e3ab4b4766262d 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.7 objnam.c        $NHDT-Date: 1654557302 2022/06/06 23:15:02 $  $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.368 $ */
+/* NetHack 3.7 objnam.c        $NHDT-Date: 1672829441 2023/01/04 10:50:41 $  $NHDT-Branch: naming-overflow-fix $:$NHDT-Revision: 1.386 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /*-Copyright (c) Robert Patrick Rankin, 2011. */
 /* NetHack may be freely redistributed.  See license for details. */
@@ -35,6 +35,7 @@ struct _readobjnam_data {
 static char *strprepend(char *, const char *);
 static char *nextobuf(void);
 static void releaseobuf(char *);
+static void xcalled(char *, int, const char *, const char *);
 static char *xname_flags(struct obj *, unsigned);
 static char *minimal_xname(struct obj *);
 static void add_erosion_words(struct obj *, char *);
@@ -187,6 +188,7 @@ obj_typename(int otyp)
     if (!actualn)
         actualn = (otyp > 0 && otyp < MAXOCLASSES) ? "generic" : "object?";
 
+    buf[0] = '\0'; /* redundant */
     switch (ocl->oc_class) {
     case COIN_CLASS:
         Strcpy(buf, "coin");
@@ -217,7 +219,7 @@ obj_typename(int otyp)
         else
             Strcpy(buf, "amulet");
         if (un)
-            Sprintf(eos(buf), " called %s", un);
+            xcalled(buf, BUFSZ - (dn ? (int) strlen(dn) + 3 : 0), "", un);
         if (dn)
             Sprintf(eos(buf), " (%s)", dn);
         return buf;
@@ -226,8 +228,8 @@ obj_typename(int otyp)
             Strcpy(buf, actualn);
             if (GemStone(otyp))
                 Strcat(buf, " stone");
-            if (un)
-                Sprintf(eos(buf), " called %s", un);
+            if (un) /* 3: length of " (" + ")" which will enclose 'dn' */
+                xcalled(buf, BUFSZ - (dn ? (int) strlen(dn) + 3 : 0), "", un);
             if (dn)
                 Sprintf(eos(buf), " (%s)", dn);
         } else {
@@ -236,7 +238,7 @@ obj_typename(int otyp)
                 Strcat(buf,
                        (ocl->oc_material == MINERAL) ? " stone" : " gem");
             if (un)
-                Sprintf(eos(buf), " called %s", un);
+                xcalled(buf, BUFSZ, "", un);
         }
         return buf;
     }
@@ -247,8 +249,8 @@ obj_typename(int otyp)
         else
             Sprintf(eos(buf), " of %s", actualn);
     }
-    if (un)
-        Sprintf(eos(buf), " called %s", un);
+    if (un) /* 3: length of " (" + ")" which will enclose 'dn' */
+        xcalled(buf, BUFSZ - (dn ? (int) strlen(dn) + 3 : 0), "", un);
     if (dn)
         Sprintf(eos(buf), " (%s)", dn);
     return buf;
@@ -498,6 +500,24 @@ reorder_fruit(boolean forward)
     }
 }
 
+/* add "<pfx> called <sfx>" to end of buf, truncating if necessary */
+static void
+xcalled(
+    char *buf,       /* eos(obuf) or eos(&obuf[PREFIX]) */
+    int siz,         /* BUFSZ or BUFSZ-PREFIX */
+    const char *pfx, /* usually class string, sometimes more specific */
+    const char *sfx) /* user assigned type name */
+{
+    int bufsiz = siz - 1 - (int) strlen(buf),
+        pfxlen = (int) (strlen(pfx) + sizeof " called " - sizeof "");
+
+    if (pfxlen > bufsiz)
+        panic("xcalled: not enough room for prefix (%d > %d)",
+              pfxlen, bufsiz);
+
+    Sprintf(eos(buf), "%s called %.*s", pfx, bufsiz - pfxlen, sfx);
+}
+
 char *
 xname(struct obj* obj)
 {
@@ -530,7 +550,7 @@ xname_flags(
        for those; pacify static analyzer without resorting to impossible() */
     if (!actualn)
         actualn = (typ > 0 && typ < MAXOCLASSES) ? "generic" : "object?";
-    /* As of 3.6.2: this used to be part of 'dn's initialization, but it
+    /* 3.6.2: this used to be part of 'dn's initialization, but it
        needs to come after possibly overriding 'actualn' */
     if (!dn)
         dn = actualn;
@@ -592,7 +612,7 @@ xname_flags(
         else if (nn)
             Strcpy(buf, actualn);
         else if (un)
-            Sprintf(buf, "amulet called %s", un);
+            xcalled(buf, BUFSZ - PREFIX, "amulet", un);
         else
             Sprintf(buf, "%s amulet", dn);
         break;
@@ -611,11 +631,9 @@ xname_flags(
             Strcat(buf, dn);
         else if (nn)
             Strcat(buf, actualn);
-        else if (un) {
-            Strcat(buf, dn);
-            Strcat(buf, " called ");
-            Strcat(buf, un);
-        } else
+        else if (un)
+            xcalled(buf, BUFSZ - PREFIX, dn, un);
+        else
             Strcat(buf, dn);
 
         if (typ == FIGURINE && omndx != NON_PM) {
@@ -650,7 +668,7 @@ xname_flags(
         if (nn)
             Strcat(buf, actualn);
         else if (un)
-            Sprintf(eos(buf), "%s called %s", armor_simple_name(obj), un);
+            xcalled(buf, BUFSZ - PREFIX, armor_simple_name(obj), un);
         else
             Strcat(buf, dn);
         break;
@@ -750,8 +768,7 @@ xname_flags(
                 }
                 Strcat(buf, actualn);
             } else {
-                Strcat(buf, " called ");
-                Strcat(buf, un);
+                xcalled(buf, BUFSZ - PREFIX, "", un);
             }
         } else {
             Strcat(buf, dn);
@@ -766,8 +783,7 @@ xname_flags(
             Strcat(buf, " of ");
             Strcat(buf, actualn);
         } else if (un) {
-            Strcat(buf, " called ");
-            Strcat(buf, un);
+            xcalled(buf, BUFSZ - PREFIX, "", un);
         } else if (ocl->oc_magic) {
             Strcat(buf, " labeled ");
             Strcat(buf, dn);
@@ -782,7 +798,7 @@ xname_flags(
         else if (nn)
             Sprintf(buf, "wand of %s", actualn);
         else if (un)
-            Sprintf(buf, "wand called %s", un);
+            xcalled(buf, BUFSZ - PREFIX, "wand", un);
         else
             Sprintf(buf, "%s wand", dn);
         break;
@@ -793,7 +809,7 @@ xname_flags(
             else if (nn)
                 Strcpy(buf, actualn);
             else if (un)
-                Sprintf(buf, "novel called %s", un);
+                xcalled(buf, BUFSZ - PREFIX, "novel", un);
             else
                 Sprintf(buf, "%s book", dn);
             break;
@@ -805,7 +821,7 @@ xname_flags(
                 Strcpy(buf, "spellbook of ");
             Strcat(buf, actualn);
         } else if (un) {
-            Sprintf(buf, "spellbook called %s", un);
+            xcalled(buf, BUFSZ - PREFIX, "spellbook", un);
         } else
             Sprintf(buf, "%s spellbook", dn);
         break;
@@ -815,7 +831,7 @@ xname_flags(
         else if (nn)
             Sprintf(buf, "ring of %s", actualn);
         else if (un)
-            Sprintf(buf, "ring called %s", un);
+            xcalled(buf, BUFSZ - PREFIX, "ring", un);
         else
             Sprintf(buf, "%s ring", dn);
         break;
@@ -826,7 +842,7 @@ xname_flags(
             Strcpy(buf, rock);
         } else if (!nn) {
             if (un)
-                Sprintf(buf, "%s called %s", rock, un);
+                xcalled(buf, BUFSZ - PREFIX, rock, un);
             else
                 Sprintf(buf, "%s %s", dn, rock);
         } else {
@@ -879,7 +895,8 @@ xname_flags(
         Strcat(buf, " named ");
  nameit:
         obufp = eos(buf);
-        Strcat(buf, ONAME(obj));
+        (void) strncat(buf, ONAME(obj),
+                       BUFSZ - 1 - PREFIX - (unsigned) strlen(buf));
         /* downcase "The" in "<quest-artifact-item> named The ..." */
         if (obj->oartifact && !strncmp(obufp, "The ", 4))
             *obufp = lowc(*obufp); /* = 't'; */
@@ -1866,7 +1883,7 @@ just_an(char *outbuf, const char *str)
 }
 
 char *
-an(const charstr)
+an(const char *str)
 {
     char *buf = nextobuf();
 
@@ -1875,11 +1892,11 @@ an(const char* str)
         return strcpy(buf, "an []");
     }
     (void) just_an(buf, str);
-    return strcat(buf, str);
+    return strncat(buf, str, BUFSZ - 1 - Strlen(buf));
 }
 
 char *
-An(const charstr)
+An(const char *str)
 {
     char *tmp = an(str);
 
@@ -1950,9 +1967,7 @@ the(const char* str)
         Strcpy(buf, "the ");
     else
         buf[0] = '\0';
-    Strcat(buf, str);
-
-    return buf;
+    return strncat(buf, str, BUFSZ - 1 - Strlen(buf));
 }
 
 char *
@@ -3846,10 +3861,12 @@ readobjnam_postparse1(struct _readobjnam_data *d)
      */
     if ((d->p = strstri(d->bp, " named ")) != 0) {
         *d->p = 0;
+        /* note: if 'name' is too long, oname() will truncate it */
         d->name = d->p + 7;
     }
     if ((d->p = strstri(d->bp, " called ")) != 0) {
         *d->p = 0;
+        /* note: if 'un' is too long, obj lookup just won't match anything */
         d->un = d->p + 8;
         /* "helmet called telepathy" is not "helmet" (a specific type)
          * "shield called reflection" is not "shield" (a general type)