]> granicus.if.org Git - nethack/commitdiff
fix #Q159 - segfault with super long item names
authornethack.rankin <nethack.rankin>
Sat, 10 Feb 2007 04:05:47 +0000 (04:05 +0000)
committernethack.rankin <nethack.rankin>
Sat, 10 Feb 2007 04:05:47 +0000 (04:05 +0000)
     From a bug report, putting an object with
really long specific and type names into a container with really long
specific and type names caused the program to crash.  pline() overflowed
the buffer it formatted into, and even though it was able to send that
for output and trigger a --More-- prompt, eventually a segfault occurred.
Give vpline and vraw_printf a much bigger working buffer, then truncate
the formatted text to BUFSZ - 1 characters so that we don't just push the
long line trouble into the separate interfaces.

doc/fixes34.4
src/pline.c

index 4d5d019e26f956b7aabc98fe2d4ecc177b246fd3..02316e4951d7cf2a34ffcfa4f1c9d4e06ef7c91f 100644 (file)
@@ -313,6 +313,8 @@ surviving choking while eating various foods (cockatrice egg, fortune cookie,
        wolfsbane, others) didn't carry through to those foods' side-effects
 shapechangers who take on mimic or hider form will mimic or hide when feasible
 avoid War message if tinning a Rider corpse fails
+prevent long messages from triggering access violation or segmentation fault
+       due to buffer overflow in pline()
 
 
 Platform- and/or Interface-Specific Fixes
index eee589505a08691803b8287722a7fde1963d8813..df8920ae2819195d76f83c71cf93c65db42a5a0d 100644 (file)
@@ -1,4 +1,4 @@
-/*     SCCS Id: @(#)pline.c    3.5     2007/01/17      */
+/*     SCCS Id: @(#)pline.c    3.5     2007/02/09      */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -41,7 +41,8 @@ void
 pline VA_DECL(const char *, line)
 #endif /* USE_STDARG | USE_VARARG */
 
-       char pbuf[BUFSZ];
+       char pbuf[3*BUFSZ];
+       int ln;
 /* Do NOT use VA_START and VA_END in here... see above */
 
        if (!line || !*line) return;
@@ -56,6 +57,20 @@ pline VA_DECL(const char *, line)
            Vsprintf(pbuf,line,VA_ARGS);
            line = pbuf;
        }
+       if ((ln = (int)strlen(line)) > BUFSZ-1) {
+           if (line != pbuf)   /* no '%' was present */
+               (void)strncpy(pbuf, line, BUFSZ-1); /* caveat: unterminated */
+           /* truncate, preserving the final 3 characters:
+              "___ extremely long text" -> "___ extremely l...ext"
+              (this may be suboptimal if overflow is less than 3) */
+           (void)strncpy(pbuf + BUFSZ-1 - 6, "...", 3);
+           /* avoid strncpy; buffers could overlap if excess is small */
+           pbuf[BUFSZ-1 - 3] = line[ln - 3];
+           pbuf[BUFSZ-1 - 2] = line[ln - 2];
+           pbuf[BUFSZ-1 - 1] = line[ln - 1];
+           pbuf[BUFSZ-1] = '\0';
+           line = pbuf;
+       }
        if (!iflags.window_inited) {
            raw_print(line);
            return;
@@ -263,15 +278,21 @@ vraw_printf(line, the_args) const char *line; va_list the_args; {
 void
 raw_printf VA_DECL(const char *, line)
 #endif
+
+       char pbuf[3*BUFSZ];
+       int ln;
 /* Do NOT use VA_START and VA_END in here... see above */
 
-       if(!index(line, '%'))
-           raw_print(line);
-       else {
-           char pbuf[BUFSZ];
+       if (index(line, '%')) {
            Vsprintf(pbuf,line,VA_ARGS);
-           raw_print(pbuf);
+           line = pbuf;
+       }
+       if ((ln = (int)strlen(line)) > BUFSZ-1) {
+           if (line != pbuf) line = strncpy(pbuf, line, BUFSZ-1);
+           /* unlike pline, we don't futz around to keep last few chars */
+           pbuf[BUFSZ-1] = '\0'; /* terminate strncpy or truncate vsprintf */
        }
+       raw_print(line);
 }