]> granicus.if.org Git - nethack/commitdiff
option parsing crash: 'playmode' without value
authorPatR <rankin@nethack.org>
Fri, 5 Aug 2016 00:42:26 +0000 (17:42 -0700)
committerPatR <rankin@nethack.org>
Fri, 5 Aug 2016 00:42:26 +0000 (17:42 -0700)
Reported directly to devteam, specifying the playmode option without
appending a value caused a segfault during options parsing.  The
argument passed to string_for_opt() ought to have been False for
"not optional" to trigger a "bad syntax" message, but even then the
playmode parsing needs to check for Null to prevent the crash.

"Bad syntax" is awfully vague.  In cases like this, we can be more
precise.  Now it will say "Missing value" instead.

doc/fixes36.1
src/options.c

index cbf74c283f9c826cd60014adf45a73381a312caa..d6031ea65b6a3d05153cac0beb999dc62b61d0a2 100644 (file)
@@ -328,6 +328,7 @@ eating the corpse of a unique non-named monster (Wizard of Yendor, Oracle,
        Chromatic Dragon, others) gave "The the <monster corpse> tastes ..."
 when escaping the dungeon, change "you were here" annotation in dungeon
        overview to "you left from here"
+option parsing will crash if 'playmode' option is present without a value
 
 
 Fixes to Post-3.6.0 Problems that Were Exposed Via git Repository
index 1245c276b71443ae3150f387140b0ff62ae3dd85..4edc94fe0b5a8baa895da194db8526c7c4039dd4 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 options.c       $NHDT-Date: 1461102048 2016/04/19 21:40:48 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.268 $ */
+/* NetHack 3.6 options.c       $NHDT-Date: 1470357737 2016/08/05 00:42:17 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.279 $ */
 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
 /* NetHack may be freely redistributed.  See license for details. */
 
@@ -500,6 +500,7 @@ static boolean initial, from_file;
 STATIC_DCL void FDECL(nmcpy, (char *, const char *, int));
 STATIC_DCL void FDECL(escapes, (const char *, char *));
 STATIC_DCL void FDECL(rejectoption, (const char *));
+STATIC_DCL void FDECL(badoptmsg, (const char *, const char *));
 STATIC_DCL void FDECL(badoption, (const char *));
 STATIC_DCL char *FDECL(string_for_opt, (char *, BOOLEAN_P));
 STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *, BOOLEAN_P));
@@ -927,40 +928,43 @@ const char *optname;
 }
 
 STATIC_OVL void
-badoption(opts)
+badoptmsg(opts, reason)
 const char *opts;
+const char *reason; /* "Bad syntax" or "Missing value" */
 {
+    const char *linesplit = "";
+
     if (!initial) {
         if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1))
             option_help();
         else
-            pline("Bad syntax: %s.  Enter \"?g\" for help.", opts);
+            pline("%s: %s.  Enter \"?g\" for help.", reason, opts);
         return;
-    }
 #ifdef MAC
-    else
+    } else {
         return;
 #endif
+    }
 
-    if (from_file)
-        raw_printf("Bad syntax in OPTIONS in %s: %s%s.\n", configfile,
 #ifdef WIN32
-                    "\n",
-#else
-                    "",
+    linesplit = "\n";
 #endif
-                    opts);
+    if (from_file)
+        raw_printf("%s in OPTIONS in %s: %s%s.\n",
+                   reason, configfile, linesplit, opts);
     else
-        raw_printf("Bad syntax in NETHACKOPTIONS: %s%s.\n",
-#ifdef WIN32
-                    "\n",
-#else
-                    "",
-#endif
-                    opts);
+        raw_printf("%s in NETHACKOPTIONS: %s%s.\n",
+                   reason, linesplit, opts);
     wait_synch();
 }
 
+STATIC_OVL void
+badoption(opts)
+const char *opts;
+{
+    badoptmsg(opts, "Bad syntax");
+}
+
 STATIC_OVL char *
 string_for_opt(opts, val_optional)
 char *opts;
@@ -975,7 +979,7 @@ boolean val_optional;
 
     if (!colon || !*++colon) {
         if (!val_optional)
-            badoption(opts);
+            badoptmsg(opts, "Missing value");
         return (char *) 0;
     }
     return colon;
@@ -2700,7 +2704,9 @@ boolean tinitial, tfrom_file;
             bad_negation(fullname, FALSE);
         if (duplicate || negated)
             return;
-        op = string_for_opt(opts, TRUE);
+        op = string_for_opt(opts, FALSE);
+        if (!op)
+            return;
         if (!strncmpi(op, "normal", 6) || !strcmpi(op, "play")) {
             wizard = discover = FALSE;
         } else if (!strncmpi(op, "explore", 6)