From f484411f1a48386975f55d1273750ca3c926aa9a Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Wed, 27 Oct 2021 18:11:41 +0200 Subject: [PATCH] string: Introduce arr_realloc() and check for integer overflow. Use __builtin_mul_overflow() for the check. This builtin was introduced in gcc-5, so we need to bump the lowest supported version. Re-implement para_realloc() as a trivial wrapper for arr_realloc() to simplify and to avoid duplicating the size check. --- aft.c | 4 ++-- audiod.c | 9 +++------ bitstream.c | 4 ++-- client.c | 2 +- flac_afh.c | 4 ++-- interactive.c | 4 ++-- mood.c | 4 ++-- mp3_afh.c | 4 ++-- ogg_afh_common.c | 4 ++-- string.c | 43 +++++++++++++++++++++++++++++++------------ string.h | 1 + web/manual.md | 4 ++-- 12 files changed, 52 insertions(+), 35 deletions(-) diff --git a/aft.c b/aft.c index 215e8bf2..991cb777 100644 --- a/aft.c +++ b/aft.c @@ -1317,8 +1317,8 @@ static int prepare_ls_row(struct osl_row *row, void *ls_opts) if (options->num_matching_paths > options->array_size) { options->array_size++; options->array_size *= 2; - options->data = para_realloc(options->data, options->array_size - * sizeof(*options->data)); + options->data = arr_realloc(options->data, options->array_size, + sizeof(*options->data)); } d = options->data + tmp; ret = get_afsi_of_row(aft_row, &d->afsi); diff --git a/audiod.c b/audiod.c index 2a59d56a..4aef61b0 100644 --- a/audiod.c +++ b/audiod.c @@ -835,12 +835,9 @@ static int add_filter(int format, const char *cmdline) struct lls_parse_result *flpr; filter_num = filter_setup(cmdline, &cfg, &flpr); - a->filter_lpr = para_realloc(a->filter_lpr, - (nf + 1) * sizeof(flpr)); - a->filter_conf = para_realloc(a->filter_conf, - (nf + 1) * sizeof(void *)); - a->filter_nums = para_realloc(a->filter_nums, - (nf + 1) * sizeof(unsigned)); + a->filter_lpr = arr_realloc(a->filter_lpr, nf + 1, sizeof(flpr)); + a->filter_conf = arr_realloc(a->filter_conf, nf + 1, sizeof(void *)); + a->filter_nums = arr_realloc(a->filter_nums, nf + 1, sizeof(unsigned)); a->filter_nums[nf] = filter_num; a->filter_conf[nf] = cfg; diff --git a/bitstream.c b/bitstream.c index dfc1e55e..a1c7c943 100644 --- a/bitstream.c +++ b/bitstream.c @@ -46,8 +46,8 @@ static void alloc_table(struct vlc *vlc, int size) vlc->table_size += size; if (vlc->table_size > vlc->table_allocated) { vlc->table_allocated += (1 << vlc->bits); - vlc->table = para_realloc(vlc->table, - sizeof(int16_t) * 2 * vlc->table_allocated); + vlc->table = arr_realloc(vlc->table, vlc->table_allocated, + sizeof(int16_t) * 2); } } diff --git a/client.c b/client.c index 20c9971a..5cb2309d 100644 --- a/client.c +++ b/client.c @@ -341,7 +341,7 @@ static void setatt_completer(struct i9e_completion_info *ci, if (ret < 0) goto out; num_atts = ret; - sl = para_realloc(sl, (2 * num_atts + 1) * sizeof(char *)); + sl = arr_realloc(sl, 2 * num_atts + 1, sizeof(char *)); for (i = 0; i < num_atts; i++) { char *orig = sl[i]; sl[i] = make_message("%s+", orig); diff --git a/flac_afh.c b/flac_afh.c index 730f954b..2b5b6c1d 100644 --- a/flac_afh.c +++ b/flac_afh.c @@ -374,8 +374,8 @@ static int flac_afh_read_chunks(struct private_flac_afh_data *pfad) goto free_decoder; if (c >= chunk_table_size) { chunk_table_size = 2 * chunk_table_size + 100; - afhi->chunk_table = para_realloc(afhi->chunk_table, - chunk_table_size * sizeof(uint32_t)); + afhi->chunk_table = arr_realloc(afhi->chunk_table, + chunk_table_size, sizeof(uint32_t)); } afhi->chunk_table[c] = pos; diff --git a/interactive.c b/interactive.c index ee4878fb..98882ce6 100644 --- a/interactive.c +++ b/interactive.c @@ -656,8 +656,8 @@ int i9e_extract_completions(const char *word, char **string_list, match_count++; if (match_count >= matches_len) { matches_len *= 2; - matches = para_realloc(matches, - matches_len * sizeof(char *)); + matches = arr_realloc(matches, matches_len, + sizeof(char *)); } matches[match_count - 1] = para_strdup(*p); } diff --git a/mood.c b/mood.c index 161d8df0..bcc9bc57 100644 --- a/mood.c +++ b/mood.c @@ -363,8 +363,8 @@ static int add_if_admissible(struct osl_row *aft_row, void *data) if (statistics.num >= aa->size) { aa->size *= 2; aa->size += 100; - aa->array = para_realloc(aa->array, - aa->size * sizeof(struct osl_row *)); + aa->array = arr_realloc(aa->array, aa->size, + sizeof(struct osl_row *)); } aa->array[statistics.num] = aft_row; return add_afs_statistics(aft_row); diff --git a/mp3_afh.c b/mp3_afh.c index 1e105b7e..a42042e9 100644 --- a/mp3_afh.c +++ b/mp3_afh.c @@ -633,8 +633,8 @@ static int mp3_read_info(unsigned char *map, size_t numbytes, int fd, total_time = tmp; if (afhi->chunks_total >= chunk_table_size) { chunk_table_size *= 2; - afhi->chunk_table = para_realloc(afhi->chunk_table, - chunk_table_size * sizeof(uint32_t)); + afhi->chunk_table = arr_realloc(afhi->chunk_table, + chunk_table_size, sizeof(uint32_t)); } afhi->chunk_table[afhi->chunks_total] = fpos; afhi->chunks_total++; diff --git a/ogg_afh_common.c b/ogg_afh_common.c index 3909a291..0570656e 100644 --- a/ogg_afh_common.c +++ b/ogg_afh_common.c @@ -179,9 +179,9 @@ int oac_get_file_info(char *map, size_t numbytes, struct afh_info *afhi, j++; if (j >= ct_size) { ct_size *= 2; - afhi->chunk_table = para_realloc( + afhi->chunk_table = arr_realloc( afhi->chunk_table, - ct_size * sizeof(uint32_t)); + ct_size, sizeof(uint32_t)); } afhi->chunk_table[j] = oss.returned; } diff --git a/string.c b/string.c index bbc322eb..f98b199b 100644 --- a/string.c +++ b/string.c @@ -14,6 +14,35 @@ #include "string.h" #include "error.h" +/** + * Reallocate an array, abort on failure or bugs. + * + * \param ptr Pointer to the memory block, may be NULL. + * \param nmemb Number of elements. + * \param size The size of one element in bytes. + * + * A wrapper for realloc(3) which aborts on invalid arguments or integer + * overflow. The wrapper also terminates the current process on allocation + * errors, so the caller does not need to check for failure. + * + * \return A pointer to newly allocated memory which is suitably aligned for + * any kind of variable and may be different from ptr. + * + * \sa realloc(3). + */ +__must_check void *arr_realloc(void *ptr, size_t nmemb, size_t size) +{ + size_t pr; + + assert(size > 0); + assert(nmemb > 0); + assert(!__builtin_mul_overflow(nmemb, size, &pr)); + assert(pr != 0); + ptr = realloc(ptr, pr); + assert(ptr); + return ptr; +} + /** * Paraslash's version of realloc(). * @@ -30,17 +59,7 @@ */ __must_check void *para_realloc(void *p, size_t size) { - /* - * No need to check for NULL pointers: If p is NULL, the call - * to realloc is equivalent to malloc(size) - */ - assert(size); - if (!(p = realloc(p, size))) { - PARA_EMERG_LOG("realloc failed (size = %zu), aborting\n", - size); - exit(EXIT_FAILURE); - } - return p; + return arr_realloc(p, 1, size); } /** @@ -734,7 +753,7 @@ static int create_argv_offset(int offset, const char *buf, const char *delim, goto err; if (!ret) break; - argv = para_realloc(argv, (i + 2) * sizeof(char*)); + argv = arr_realloc(argv, i + 2, sizeof(char*)); argv[i] = word; } argv[i] = NULL; diff --git a/string.h b/string.h index 29dc388f..45c359f3 100644 --- a/string.h +++ b/string.h @@ -67,6 +67,7 @@ int for_each_line(unsigned flags, char *buf, size_t size, } \ ) +__must_check void *arr_realloc(void *ptr, size_t nmemb, size_t size); __must_check void *para_realloc(void *p, size_t size); __must_check __malloc void *alloc(size_t size); __must_check __malloc void *zalloc(size_t size); diff --git a/web/manual.md b/web/manual.md index 78834a4d..b5329ea0 100644 --- a/web/manual.md +++ b/web/manual.md @@ -309,8 +309,8 @@ repository with git clone git://git.tuebingen.mpg.de/lopsub - [gcc](ftp://ftp.gnu.org/pub/gnu/gcc) or -[clang](http://clang.llvm.org). All gcc versions >= 4.2 are currently -supported. Clang version 1.1 or newer should work as well. +[clang](http://clang.llvm.org). All gcc versions >= 5.4 are currently +supported. Moderately recent versions of clang should work as well. - [gnu make](ftp://ftp.gnu.org/pub/gnu/make) is also shipped with the disto. On BSD systems the gnu make executable is often called gmake. -- 2.39.2