From cdf7ddacd56d8d31fb9a23b94a8b8f317a8a1066 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 6 Mar 2012 15:19:24 -0800 Subject: [PATCH] readtokens: avoid core dumps with unusual calling patterns Reported by Xu Zhongxing in . * lib/readtokens.c: Include limits.h. (word, bits_per_word, get_nth_bit, set_nth_bit): New. (readtoken): Don't cache the delimiters; the cache code was buggy if !delim && saved_delim, or if the new n_delim differs from the old. Also, it wasn't thread-safe. --- ChangeLog | 10 +++++++++ lib/readtokens.c | 56 +++++++++++++++++++++--------------------------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0e612de402..9a5b065fb5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2012-03-06 Paul Eggert + + readtokens: avoid core dumps with unusual calling patterns + Reported by Xu Zhongxing in . + * lib/readtokens.c: Include limits.h. + (word, bits_per_word, get_nth_bit, set_nth_bit): New. + (readtoken): Don't cache the delimiters; the cache code was buggy + if !delim && saved_delim, or if the new n_delim differs from the old. + Also, it wasn't thread-safe. + 2012-03-07 Bruno Haible quote: Adhere to common module description layout. diff --git a/lib/readtokens.c b/lib/readtokens.c index 705a62b90c..f11d3f6c7b 100644 --- a/lib/readtokens.c +++ b/lib/readtokens.c @@ -26,6 +26,7 @@ #include "readtokens.h" +#include #include #include #include @@ -46,6 +47,22 @@ init_tokenbuffer (token_buffer *tokenbuffer) tokenbuffer->buffer = NULL; } +typedef size_t word; +enum { bits_per_word = sizeof (word) * CHAR_BIT }; + +static bool +get_nth_bit (size_t n, word const *bitset) +{ + return bitset[n / bits_per_word] >> n % bits_per_word & 1; +} + +static void +set_nth_bit (size_t n, word *bitset) +{ + size_t one = 1; + bitset[n / bits_per_word] |= one << n % bits_per_word; +} + /* Read a token from STREAM into TOKENBUFFER. A token is delimited by any of the N_DELIM bytes in DELIM. Upon return, the token is in tokenbuffer->buffer and @@ -68,42 +85,17 @@ readtoken (FILE *stream, char *p; int c; size_t i, n; - static const char *saved_delim = NULL; - static char isdelim[256]; - bool same_delimiters; - - if (delim == NULL && saved_delim == NULL) - abort (); + word isdelim[(UCHAR_MAX + bits_per_word) / bits_per_word]; - same_delimiters = false; - if (delim != saved_delim && saved_delim != NULL) + memset (isdelim, 0, sizeof isdelim); + for (i = 0; i < n_delim; i++) { - same_delimiters = true; - for (i = 0; i < n_delim; i++) - { - if (delim[i] != saved_delim[i]) - { - same_delimiters = false; - break; - } - } - } - - if (!same_delimiters) - { - size_t j; - saved_delim = delim; - memset (isdelim, 0, sizeof isdelim); - for (j = 0; j < n_delim; j++) - { - unsigned char ch = delim[j]; - isdelim[ch] = 1; - } + unsigned char ch = delim[i]; + set_nth_bit (ch, isdelim); } - /* FIXME: don't fool with this caching. Use strchr instead. */ /* skip over any leading delimiters */ - for (c = getc (stream); c >= 0 && isdelim[c]; c = getc (stream)) + for (c = getc (stream); c >= 0 && get_nth_bit (c, isdelim); c = getc (stream)) { /* empty */ } @@ -124,7 +116,7 @@ readtoken (FILE *stream, p[i] = 0; break; } - if (isdelim[c]) + if (get_nth_bit (c, isdelim)) { p[i] = 0; break; -- 2.39.5