From 5738e399c4a3271b7bb7cf82eb7c595a7647d3ca Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Thu, 27 Dec 2012 14:43:43 +0100 Subject: [PATCH] Make news item merging deterministic and safe for year 2038 News reporting merges news items into recent items with same contents. For that purpuse, we keep a small cache of recent items. When a new item can't be merged into an item in the cache, the oldest item gets evicted to make space for the new one. ncache() evicts the first item with the smallest timestamp (struct nwsstr member nws_when). Timestamps are in seconds, therefore clashes are common, and eviction depends on exact timing. Such indeterminism can make the smoke test fail. Moreover, ncache() assumes timestamps cannot exceed 0x7fffffff. If they do, it always evicts the slot 0. They will in 2038. Fix by evicting round robin. This always evicts the oldest item. --- src/lib/subs/nreport.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/lib/subs/nreport.c b/src/lib/subs/nreport.c index 716e81f4..b2ab2602 100644 --- a/src/lib/subs/nreport.c +++ b/src/lib/subs/nreport.c @@ -30,7 +30,7 @@ * Dave Pare, 1994 * Steve McClure, 1997 * Ron Koenderink, 2005 - * Markus Armbruster, 2004-2011 + * Markus Armbruster, 2004-2012 */ #include @@ -49,6 +49,7 @@ struct newscache { }; static struct newscache cache[MAXNOC][SLOTS]; +static unsigned char cache_oldest[MAXNOC]; static int news_tail; static struct newscache * @@ -157,18 +158,12 @@ ncache(int actor, int event, int victim, int times) { struct newscache *np; int i; - int oldslot; - time_t oldtime, dur; + unsigned oldslot; + time_t dur; time_t now = time(NULL); - oldslot = -1; - oldtime = 0x7fffffff; for (i = 0; i < SLOTS; i++) { np = &cache[actor][i]; - if (np->news.nws_when < oldtime) { - oldslot = i; - oldtime = np->news.nws_when; - } if (np->news.nws_vrb == 0) continue; dur = now - np->news.nws_when; @@ -181,11 +176,13 @@ ncache(int actor, int event, int victim, int times) return np; } } - if (CANT_HAPPEN(oldslot < 0)) - oldslot = 0; if (CANT_HAPPEN(!strstr(rpt[event].r_newstory[0], "%s") && victim != 0)) victim = 0; + oldslot = cache_oldest[actor]; + if (CANT_HAPPEN(oldslot >= SLOTS)) + oldslot = 0; np = &cache[actor][oldslot]; + cache_oldest[actor] = (oldslot + 1) % SLOTS; ef_blank(EF_NEWS, news_tail, &np->news); np->news.nws_ano = actor; np->news.nws_vrb = event;