From 298331fe04bc301873a0a29daa0289c33a814d39 Mon Sep 17 00:00:00 2001 From: PatR Date: Sat, 23 May 2020 12:51:01 -0700 Subject: [PATCH] improved regexp handling If regex_compile() fails, free the regexp before doing anything else in case failure reason is "out of memory". Feedback to the user is highly likely to panic or crash after memory runs out; this should let the regex failure message be issued and the game continue. User sound regular expressions were never freed. This frees them when FREE_ALL_MEMORY is enabled. --- include/extern.h | 3 +- src/files.c | 6 ++-- src/options.c | 78 ++++++++++++++++++++++++++++++------------------ src/save.c | 9 ++++-- src/sounds.c | 36 +++++++++++++++++----- 5 files changed, 91 insertions(+), 41 deletions(-) diff --git a/include/extern.h b/include/extern.h index 6c7bf4f0e..3b5aeaeaf 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1,4 +1,4 @@ -/* NetHack 3.6 extern.h $NHDT-Date: 1588798973 2020/05/06 21:02:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.842 $ */ +/* NetHack 3.6 extern.h $NHDT-Date: 1590263447 2020/05/23 19:50:47 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.843 $ */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ @@ -2459,6 +2459,7 @@ E int NDECL(tiphat); #ifdef USER_SOUNDS E int FDECL(add_sound_mapping, (const char *)); E void FDECL(play_sound_for_message, (const char *)); +E void NDECL(release_sound_mappings); #endif /* ### sp_lev.c ### */ diff --git a/src/files.c b/src/files.c index ee2628396..39fb919c5 100644 --- a/src/files.c +++ b/src/files.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 files.c $NHDT-Date: 1589580856 2020/05/15 22:14:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.313 $ */ +/* NetHack 3.7 files.c $NHDT-Date: 1590263451 2020/05/23 19:50:51 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.314 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Derek S. Ray, 2015. */ /* NetHack may be freely redistributed. See license for details. */ @@ -120,7 +120,7 @@ extern char *FDECL(translate_path_variables, (const char *, char *)); #endif #ifdef USER_SOUNDS -extern char *sounddir; +extern char *sounddir; /* defined in sounds.c */ #endif #if defined(UNIX) && defined(QT_GRAPHICS) @@ -2885,6 +2885,8 @@ char *origbuf; #endif /*AMIGA*/ #ifdef USER_SOUNDS } else if (match_varname(buf, "SOUNDDIR", 8)) { + if (sounddir) + free((genericptr_t) sounddir); sounddir = dupstr(bufp); } else if (match_varname(buf, "SOUND", 5)) { add_sound_mapping(bufp); diff --git a/src/options.c b/src/options.c index 7159a3647..a75775e99 100644 --- a/src/options.c +++ b/src/options.c @@ -1,4 +1,4 @@ -/* NetHack 3.7 options.c $NHDT-Date: 1589326675 2020/05/12 23:37:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.464 $ */ +/* NetHack 3.7 options.c $NHDT-Date: 1590263453 2020/05/23 19:50:53 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.465 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2008. */ /* NetHack may be freely redistributed. See license for details. */ @@ -5447,7 +5447,7 @@ handler_menu_colors(VOID_ARGS) if (*mcbuf == '\033') goto menucolors_done; if (*mcbuf - && test_regex_pattern(mcbuf, (const char *)0) + && test_regex_pattern(mcbuf, "MENUCOLORS regex") && (mcclr = query_color((char *) 0)) != -1 && (mcattr = query_attr((char *) 0)) != -1 && !add_menu_coloring_parsed(mcbuf, mcclr, mcattr)) { @@ -5529,7 +5529,7 @@ handler_msgtype(VOID_ARGS) if (*mtbuf == '\033') return TRUE; if (*mtbuf - && test_regex_pattern(mtbuf, (const char *)0) + && test_regex_pattern(mtbuf, "MSGTYPE regex") && (mttyp = query_msgtype()) != -1 && !msgtype_add(mttyp, mtbuf)) { pline("Error adding the message type."); @@ -6671,16 +6671,20 @@ msgtype_add(typ, pattern) int typ; char *pattern; { + static const char *re_error = "MSGTYPE regex error"; struct plinemsg_type *tmp = (struct plinemsg_type *) alloc(sizeof *tmp); tmp->msgtype = typ; tmp->regex = regex_init(); + /* test_regex_pattern() has already validated this regexp but parsing + it again could conceivably run out of memory */ if (!regex_compile(pattern, tmp->regex)) { - static const char *re_error = "MSGTYPE regex error"; + const char *re_error_desc = regex_error_desc(tmp->regex); - config_error_add("%s: %s", re_error, regex_error_desc(tmp->regex)); + /* free first in case reason for failure was insufficient memory */ regex_free(tmp->regex); free((genericptr_t) tmp); + config_error_add("%s: %s", re_error, re_error_desc); return FALSE; } tmp->pattern = dupstr(pattern); @@ -6805,30 +6809,40 @@ char *str; return FALSE; } +/* parse 'str' as a regular expression to check whether it's valid; + compiled regexp gets thrown away regardless of the outcome */ static boolean test_regex_pattern(str, errmsg) const char *str; const char *errmsg; { - static const char re_error[] = "Regex error"; + static const char def_errmsg[] = "NHregex error"; struct nhregex *match; - boolean retval = TRUE; + const char *re_error_desc; + boolean retval; if (!str) return FALSE; + if (!errmsg) + errmsg = def_errmsg; match = regex_init(); if (!match) { - config_error_add("NHregex error"); + config_error_add("%s", errmsg); return FALSE; } - if (!regex_compile(str, match)) { - config_error_add("%s: %s", errmsg ? errmsg : re_error, - regex_error_desc(match)); - retval = FALSE; - } + retval = regex_compile(str, match); + /* get potential error message before freeing regexp and free regexp + before issuing message in case the error is "ran out of memory" + since message delivery might need to allocate some memory */ + re_error_desc = !retval ? regex_error_desc(match) : 0; + /* discard regexp; caller will re-parse it after validating other stuff */ regex_free(match); + /* if returning failure, tell player */ + if (!retval) + config_error_add("%s: %s", errmsg, re_error_desc); + return retval; } @@ -6844,19 +6858,23 @@ int c, a; return FALSE; tmp = (struct menucoloring *) alloc(sizeof *tmp); tmp->match = regex_init(); + /* test_regex_pattern() has already validated this regexp but parsing + it again could conceivably run out of memory */ if (!regex_compile(str, tmp->match)) { - config_error_add("%s: %s", re_error, regex_error_desc(tmp->match)); + const char *re_error_desc = regex_error_desc(tmp->match); + + /* free first in case reason for regcomp failure was out-of-memory */ regex_free(tmp->match); - free(tmp); + free((genericptr_t) tmp); + config_error_add("%s: %s", re_error, re_error_desc); return FALSE; - } else { - tmp->next = g.menu_colorings; - tmp->origstr = dupstr(str); - tmp->color = c; - tmp->attr = a; - g.menu_colorings = tmp; - return TRUE; } + tmp->next = g.menu_colorings; + tmp->origstr = dupstr(str); + tmp->color = c; + tmp->attr = a; + g.menu_colorings = tmp; + return TRUE; } /* parse '"regex_string"=color&attr' and add it to menucoloring */ @@ -6935,6 +6953,7 @@ free_menu_coloring() free((genericptr_t) tmp->origstr); free((genericptr_t) tmp); } + g.menu_colorings = (struct menucoloring *) 0; } static void @@ -7752,13 +7771,14 @@ const char *mapping; ape = (struct autopickup_exception *) alloc(sizeof *ape); ape->regex = regex_init(); if (!regex_compile(text, ape->regex)) { - config_error_add("%s: %s", APE_regex_error, - regex_error_desc(ape->regex)); + const char *re_error_desc = regex_error_desc(ape->regex); + + /* free first in case reason for failure was insufficient memory */ regex_free(ape->regex); free((genericptr_t) ape); + config_error_add("%s: %s", APE_regex_error, re_error_desc); return 0; } - ape->pattern = dupstr(text); ape->grab = grab; ape->next = g.apelist; @@ -7796,10 +7816,10 @@ free_autopickup_exceptions() struct autopickup_exception *ape; while ((ape = g.apelist) != 0) { - regex_free(ape->regex); - free((genericptr_t) ape->pattern); - g.apelist = ape->next; - free((genericptr_t) ape); + free((genericptr_t) ape->pattern); + regex_free(ape->regex); + g.apelist = ape->next; + free((genericptr_t) ape); } } diff --git a/src/save.c b/src/save.c index b3fe86656..2876a4c41 100644 --- a/src/save.c +++ b/src/save.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 save.c $NHDT-Date: 1581886866 2020/02/16 21:01:06 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.153 $ */ +/* NetHack 3.6 save.c $NHDT-Date: 1590263454 2020/05/23 19:50:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.158 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2009. */ /* NetHack may be freely redistributed. See license for details. */ @@ -1058,7 +1058,8 @@ NHFILE *nhfp; if (nhfp->structlevel) { bufoff(nhfp->fd); /* bwrite() before bufon() uses plain write() */ - bwrite(nhfp->fd, (genericptr_t) &sfsaveinfo, (unsigned) sizeof sfsaveinfo); + bwrite(nhfp->fd, (genericptr_t) &sfsaveinfo, + (unsigned) sizeof sfsaveinfo); bufon(nhfp->fd); } return; @@ -1149,7 +1150,11 @@ freedynamicdata() /* miscellaneous */ /* free_pickinv_cache(); -- now done from really_done()... */ free_symsets(); +#ifdef USER_SOUNDS + release_sound_mappings(); +#endif #endif /* FREE_ALL_MEMORY */ + if (VIA_WINDOWPORT()) status_finish(); #ifdef DUMPLOG diff --git a/src/sounds.c b/src/sounds.c index 1e0673ea0..28c3369fd 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 sounds.c $NHDT-Date: 1582061574 2020/02/18 21:32:54 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.96 $ */ +/* NetHack 3.6 sounds.c $NHDT-Date: 1590263455 2020/05/23 19:50:55 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.97 $ */ /* Copyright (c) 1989 Janet Walz, Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ @@ -1269,7 +1269,7 @@ typedef struct audio_mapping_rec { static audio_mapping *soundmap = 0; -char *sounddir = "."; +char *sounddir = 0; /* set in files.c */ /* adds a sound file mapping, returns 0 on failure, 1 on success */ int @@ -1285,24 +1285,29 @@ const char *mapping; filename, &volume) == 3) { audio_mapping *new_map; - if (strlen(sounddir) + strlen(filename) > 254) { + if (!sounddir) + sounddir = dupstr("."); + + if (strlen(sounddir) + 1 + strlen(filename) >= sizeof filespec) { raw_print("sound file name too long"); return 0; } Sprintf(filespec, "%s/%s", sounddir, filename); if (can_read_file(filespec)) { - new_map = (audio_mapping *) alloc(sizeof(audio_mapping)); + new_map = (audio_mapping *) alloc(sizeof *new_map); new_map->regex = regex_init(); new_map->filename = dupstr(filespec); new_map->volume = volume; new_map->next = soundmap; if (!regex_compile(text, new_map->regex)) { - raw_print(regex_error_desc(new_map->regex)); + const char *re_error_desc = regex_error_desc(new_map->regex); + regex_free(new_map->regex); - free(new_map->filename); - free(new_map); + free((genericptr_t) new_map->filename); + free((genericptr_t) new_map); + raw_print(re_error_desc); return 0; } else { soundmap = new_map; @@ -1334,6 +1339,23 @@ const char *msg; } } +void +release_sound_mappings() +{ + audio_mapping *nextsound = 0; + + while (soundmap) { + nextsound = soundmap->next; + regex_free(soundmap->regex); + free((genericptr_t) soundmap->filename); + free((genericptr_t) soundmap); + soundmap = nextsound; + } + + if (sounddir) + free((genericptr_t) sounddir), sounddir = 0; +} + #endif /* USER_SOUNDS */ /*sounds.c*/