timer validations

Add the contributed code that checks for attempting to start a
duplicate timer.  It's based on a comment which must have been there
at least 25 years and doesn't solve any known problems, but it is
conceptually similar to the large amount of sanity checking which has
gone into 3.6.x.

It didn't work as is because it was comparing two unions with '=='.
I don't know offhand whether C++ supports that but C doesn't (through
C11 at least; don't know about C17).  The union ('anything') is simple
enough that two instances can be compared without jumping through hoops.

I've also added another check for timer 'kind' (level, object, monster,
or global).
This commit is contained in:
PatR
2019-07-27 16:12:24 -07:00
parent a607ea2b7f
commit ed18ebc545
3 changed files with 34 additions and 13 deletions

View File

@@ -1,4 +1,4 @@
/* NetHack 3.6 timeout.c $NHDT-Date: 1559664953 2019/06/04 16:15:53 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.90 $ */
/* NetHack 3.6 timeout.c $NHDT-Date: 1564269133 2019/07/27 23:12:13 $ $NHDT-Branch: NetHack-3.6 $:$NHDT-Revision: 1.91 $ */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/*-Copyright (c) Robert Patrick Rankin, 2018. */
/* NetHack may be freely redistributed. See license for details. */
@@ -1868,13 +1868,32 @@ short kind;
short func_index;
anything *arg;
{
timer_element *gnu;
timer_element *gnu, *dup;
if (func_index < 0 || func_index >= NUM_TIME_FUNCS)
panic("start_timer");
if (kind < 0 || kind >= NUM_TIMER_KINDS
|| func_index < 0 || func_index >= NUM_TIME_FUNCS)
panic("start_timer (%s: %d)", kind_name(kind), (int) func_index);
gnu = (timer_element *) alloc(sizeof(timer_element));
(void) memset((genericptr_t)gnu, 0, sizeof(timer_element));
/* fail if <arg> already has a <func_index> timer running */
for (dup = timer_base; dup; dup = dup->next)
if (dup->kind == kind
&& dup->func_index == func_index
&& dup->arg.a_void == arg->a_void)
break;
if (dup) {
char idbuf[QBUFSZ];
#ifdef VERBOSE_TIMER
Sprintf(idbuf, "%s timer", timeout_funcs[func_index].name);
#else
Sprintf(idbuf, "%s timer (%d)", kind_name(kind), (int) func_index);
#endif
impossible("Attempted to start duplicate %s, aborted.", idbuf);
return FALSE;
}
gnu = (timer_element *) alloc(sizeof *gnu);
(void) memset((genericptr_t) gnu, 0, sizeof *gnu);
gnu->next = 0;
gnu->tid = timer_id++;
gnu->timeout = monstermoves + when;
@@ -1887,7 +1906,6 @@ anything *arg;
if (kind == TIMER_OBJECT) /* increment object's timed count */
(arg->a_obj)->timed++;
/* should check for duplicates and fail if any */
return TRUE;
}