X-Git-Url: http://git.tuebingen.mpg.de/?a=blobdiff_plain;f=string.c;h=2c6d35d60e7c69900826f8ddbbd7b1e16fb8cbd4;hb=539d39f36549c10656d8b31f3dea32702e9649df;hp=f80331900de09fccf573c18666c3fa007f8ca6bf;hpb=d8001cbdfbfab818018cb55b75260034cd341b43;p=paraslash.git diff --git a/string.c b/string.c index f8033190..2c6d35d6 100644 --- a/string.c +++ b/string.c @@ -15,78 +15,124 @@ #include "error.h" /** - * Paraslash's version of realloc(). + * Reallocate an array, abort on failure or bugs. * - * \param p Pointer to the memory block, may be \p NULL. - * \param size The desired new size. + * \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). It calls \p exit(\p EXIT_FAILURE) on errors, - * i.e. there is no need to check the return value in the caller. + * 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 \a p. + * any kind of variable and may be different from ptr. * * \sa realloc(3). */ -__must_check void *para_realloc(void *p, size_t size) +__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; +} + +/** + * Allocate an array, abort on failure or bugs. + * + * \param nmemb See \ref arr_realloc(). + * \param size See \ref arr_realloc(). + * + * Like \ref arr_realloc(), this aborts on invalid arguments, integer overflow + * and allocation errors. + * + * \return A pointer to newly allocated memory which is suitably aligned for + * any kind of variable. + * + * \sa See \ref arr_realloc(). + */ +__must_check __malloc void *arr_alloc(size_t nmemb, size_t size) +{ + return arr_realloc(NULL, nmemb, size); +} + +/** + * Allocate and initialize an array, abort on failure or bugs. + * + * \param nmemb See \ref arr_realloc(). + * \param size See \ref arr_realloc(). + * + * This calls \ref arr_alloc() and zeroes-out the array. + * + * \return See \ref arr_alloc(). + */ +__must_check __malloc void *arr_zalloc(size_t nmemb, size_t size) +{ + void *ptr = arr_alloc(nmemb, size); + /* - * No need to check for NULL pointers: If p is NULL, the call - * to realloc is equivalent to malloc(size) + * This multiplication can not overflow because the above call to \ref + * arr_alloc() aborts on overflow. */ - assert(size); - if (!(p = realloc(p, size))) { - PARA_EMERG_LOG("realloc failed (size = %zu), aborting\n", - size); - exit(EXIT_FAILURE); - } - return p; + memset(ptr, 0, nmemb * size); + return ptr; } /** - * Paraslash's version of malloc(). + * Allocate and initialize memory. * * \param size The desired new size. * - * A wrapper for malloc(3) which exits on errors. - * - * \return A pointer to the allocated memory, which is suitably aligned for any - * kind of variable. + * \return A pointer to the allocated and zeroed-out memory, which is suitably + * aligned for any kind of variable. * - * \sa malloc(3). + * \sa \ref alloc(), calloc(3). */ -__must_check __malloc void *para_malloc(size_t size) +__must_check void *zalloc(size_t size) { - void *p; - - assert(size); - p = malloc(size); - if (!p) { - PARA_EMERG_LOG("malloc failed (size = %zu), aborting\n", - size); - exit(EXIT_FAILURE); - } - return p; + return arr_zalloc(1, size); } /** - * Paraslash's version of calloc(). + * Paraslash's version of realloc(). * + * \param p Pointer to the memory block, may be \p NULL. * \param size The desired new size. * - * A wrapper for calloc(3) which exits on errors. + * A wrapper for realloc(3). It calls \p exit(\p EXIT_FAILURE) on errors, + * i.e. there is no need to check the return value in the caller. * - * \return A pointer to the allocated and zeroed-out memory, which is suitably - * aligned for any kind of variable. + * \return A pointer to newly allocated memory which is suitably aligned for + * any kind of variable and may be different from \a p. * - * \sa calloc(3) + * \sa realloc(3). */ -__must_check __malloc void *para_calloc(size_t size) +__must_check void *para_realloc(void *p, size_t size) { - void *ret = para_malloc(size); + return arr_realloc(p, 1, size); +} - memset(ret, 0, size); - return ret; +/** + * Paraslash's version of malloc(). + * + * \param size The desired new size. + * + * A wrapper for malloc(3) which exits on errors. + * + * \return A pointer to the allocated memory, which is suitably aligned for any + * kind of variable. + * + * \sa malloc(3). + */ +__must_check __malloc void *alloc(size_t size) +{ + return arr_alloc(1, size); } /** @@ -94,22 +140,23 @@ __must_check __malloc void *para_calloc(size_t size) * * \param s The string to be duplicated. * - * A wrapper for strdup(3). It calls \p exit(EXIT_FAILURE) on errors, i.e. - * there is no need to check the return value in the caller. + * A strdup(3)-like function which aborts if insufficient memory was available + * to allocate the duplicated string, absolving the caller from the + * responsibility to check for failure. * - * \return A pointer to the duplicated string. If \a s was the \p NULL pointer, - * an pointer to an empty string is returned. + * \return A pointer to the duplicated string. Unlike strdup(3), the caller may + * pass NULL, in which case the function returns a pointer to an empty string. + * Regardless of whether or not NULL was passed, the returned string is + * allocated on the heap and has to be freed by the caller. * - * \sa strdup(3) + * \sa strdup(3). */ __must_check __malloc char *para_strdup(const char *s) { - char *ret; + char *dupped_string = strdup(s? s: ""); - if ((ret = strdup(s? s: ""))) - return ret; - PARA_EMERG_LOG("strdup failed, aborting\n"); - exit(EXIT_FAILURE); + assert(dupped_string); + return dupped_string; } /** @@ -137,7 +184,7 @@ __printf_2_0 unsigned xvasprintf(char **result, const char *fmt, va_list ap) size_t size = 150; va_list aq; - *result = para_malloc(size + 1); + *result = alloc(size + 1); va_copy(aq, ap); ret = vsnprintf(*result, size, fmt, aq); va_end(aq); @@ -339,7 +386,7 @@ int for_each_line(unsigned flags, char *buf, size_t size, if (!(flags & FELF_DISCARD_FIRST) || start != buf) { if (flags & FELF_READ_ONLY) { size_t s = end - start; - char *b = para_malloc(s + 1); + char *b = alloc(s + 1); memcpy(b, start, s); b[s] = '\0'; ret = line_handler(b, private_data); @@ -443,7 +490,7 @@ __printf_2_3 int para_printf(struct para_buffer *b, const char *fmt, ...) int ret, sz_off = (b->flags & PBF_SIZE_PREFIX)? 5 : 0; if (!b->buf) { - b->buf = para_malloc(128); + b->buf = alloc(128); b->size = 128; b->offset = 0; } @@ -552,37 +599,6 @@ int para_atoi32(const char *str, int32_t *value) return 1; } -static inline int loglevel_equal(const char *arg, const char * const ll) -{ - return !strncasecmp(arg, ll, strlen(ll)); -} - -/** - * Compute the loglevel number from its name. - * - * \param txt The name of the loglevel (debug, info, ...). - * - * \return The numeric representation of the loglevel name. - */ -int get_loglevel_by_name(const char *txt) -{ - if (loglevel_equal(txt, "debug")) - return LL_DEBUG; - if (loglevel_equal(txt, "info")) - return LL_INFO; - if (loglevel_equal(txt, "notice")) - return LL_NOTICE; - if (loglevel_equal(txt, "warning")) - return LL_WARNING; - if (loglevel_equal(txt, "error")) - return LL_ERROR; - if (loglevel_equal(txt, "crit")) - return LL_CRIT; - if (loglevel_equal(txt, "emerg")) - return LL_EMERG; - return -E_BAD_LL; -} - static int get_next_word(const char *buf, const char *delim, char **word) { enum line_state_flags {LSF_HAVE_WORD = 1, LSF_BACKSLASH = 2, @@ -591,7 +607,7 @@ static int get_next_word(const char *buf, const char *delim, char **word) char *out; int ret, state = 0; - out = para_malloc(strlen(buf) + 1); + out = alloc(strlen(buf) + 1); *out = '\0'; *word = out; for (in = buf; *in; in++) { @@ -723,7 +739,7 @@ void free_argv(char **argv) static int create_argv_offset(int offset, const char *buf, const char *delim, char ***result) { - char *word, **argv = para_malloc((offset + 1) * sizeof(char *)); + char *word, **argv = arr_alloc(offset + 1, sizeof(char *)); const char *p; int i, ret; @@ -735,7 +751,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; @@ -831,7 +847,7 @@ int para_regcomp(regex_t *preg, const char *regex, int cflags) if (ret == 0) return 1; size = regerror(ret, preg, NULL, 0); - buf = para_malloc(size); + buf = alloc(size); regerror(ret, preg, buf, size); PARA_ERROR_LOG("%s\n", buf); free(buf); @@ -857,7 +873,7 @@ char *safe_strdup(const char *src, size_t len) char *p; assert(len < (size_t)-1); - p = para_malloc(len + 1); + p = alloc(len + 1); if (len > 0) memcpy(p, src, len); p[len] = '\0'; @@ -1011,7 +1027,7 @@ __must_check int strwidth(const char *s, size_t *result) return -ERRNO_TO_PARA_ERROR(errno); if (num_wchars == 0) return 0; - dest = para_malloc((num_wchars + 1) * sizeof(*dest)); + dest = arr_alloc(num_wchars + 1, sizeof(*dest)); src = s; memset(&state, 0, sizeof(state)); num_wchars = mbsrtowcs(dest, &src, num_wchars, &state); @@ -1066,7 +1082,7 @@ __must_check int sanitize_str(const char *src, size_t max_width, num_wchars = mbsrtowcs(NULL, &src, 0, &state); if (num_wchars == (size_t)-1) return -ERRNO_TO_PARA_ERROR(errno); - wcs = para_malloc((num_wchars + 1) * sizeof(*wcs)); + wcs = arr_alloc(num_wchars + 1, sizeof(*wcs)); memset(&state, 0, sizeof(state)); num_wchars = mbsrtowcs(wcs, &src, num_wchars + 1, &state); assert(num_wchars != (size_t)-1); @@ -1077,7 +1093,7 @@ __must_check int sanitize_str(const char *src, size_t max_width, } wcs[n] = L'\0'; n = wcstombs(NULL, wcs, 0) + 1; - *result = para_malloc(n); + *result = alloc(n); num_wchars = wcstombs(*result, wcs, n); assert(num_wchars != (size_t)-1); free(wcs);