diff options
Diffstat (limited to 'src/common/util.c')
-rw-r--r-- | src/common/util.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/src/common/util.c b/src/common/util.c index 2371ad3649..77102837db 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -195,33 +195,40 @@ tor_malloc_zero_(size_t size DMALLOC_PARAMS) return result; } +/* The square root of SIZE_MAX + 1. If a is less than this, and b is less + * than this, then a*b is less than SIZE_MAX. (For example, if size_t is + * 32 bits, then SIZE_MAX is 0xffffffff and this value is 0x10000. If a and + * b are less than this, then their product is at most (65535*65535) == + * 0xfffe0001. */ +#define SQRT_SIZE_MAX_P1 (((size_t)1) << (sizeof(size_t)*4)) + +/** Return non-zero if and only if the product of the arguments is exact. */ +static INLINE int +size_mul_check(const size_t x, const size_t y) +{ + /* This first check is equivalent to + (x < SQRT_SIZE_MAX_P1 && y < SQRT_SIZE_MAX_P1) + + Rationale: if either one of x or y is >= SQRT_SIZE_MAX_P1, then it + will have some bit set in its most significant half. + */ + return ((x|y) < SQRT_SIZE_MAX_P1 || + y == 0 || + x <= SIZE_MAX / y); +} + /** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill * the memory with zero bytes, and return a pointer to the result. * Log and terminate the process on error. (Same as * calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.) - * - * XXXX This implementation probably asserts in cases where it could - * work, because it only tries dividing SIZE_MAX by size (according to - * the calloc(3) man page, the size of an element of the nmemb-element - * array to be allocated), not by nmemb (which could in theory be - * smaller than size). Don't do that then. + * The second argument (<b>size</b>) should preferably be non-zero + * and a compile-time constant. */ void * tor_calloc_(size_t nmemb, size_t size DMALLOC_PARAMS) { - /* You may ask yourself, "wouldn't it be smart to use calloc instead of - * malloc+memset? Perhaps libc's calloc knows some nifty optimization trick - * we don't!" Indeed it does, but its optimizations are only a big win when - * we're allocating something very big (it knows if it just got the memory - * from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero - * for big stuff, so we don't bother with calloc. */ - void *result; - size_t max_nmemb = (size == 0) ? SIZE_MAX : SIZE_MAX/size; - - tor_assert(nmemb < max_nmemb); - - result = tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS); - return result; + tor_assert(size_mul_check(nmemb, size)); + return tor_malloc_zero_((nmemb * size) DMALLOC_FN_ARGS); } /** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b> @@ -264,7 +271,7 @@ tor_reallocarray_(void *ptr, size_t sz1, size_t sz2 DMALLOC_PARAMS) { /* XXXX we can make this return 0, but we would need to check all the * reallocarray users. */ - tor_assert(sz2 == 0 || sz1 < SIZE_T_CEILING / sz2); + tor_assert(size_mul_check(sz1, sz2)); return tor_realloc(ptr, (sz1 * sz2) DMALLOC_FN_ARGS); } @@ -3458,8 +3465,8 @@ format_win_cmdline_argument(const char *arg) smartlist_add(arg_chars, (void*)&backslash); /* Allocate space for argument, quotes (if needed), and terminator */ - formatted_arg = tor_calloc(sizeof(char), - (smartlist_len(arg_chars) + (need_quotes ? 2 : 0) + 1)); + formatted_arg = tor_calloc((smartlist_len(arg_chars) + (need_quotes ? 2 : 0) + 1), + sizeof(char)); /* Add leading quote */ i=0; @@ -5097,7 +5104,7 @@ tor_check_port_forwarding(const char *filename, for each smartlist element (one for "-p" and one for the ports), and one for the final NULL. */ args_n = 1 + 2*smartlist_len(ports_to_forward) + 1; - argv = tor_calloc(sizeof(char *), args_n); + argv = tor_calloc(args_n, sizeof(char *)); argv[argv_index++] = filename; SMARTLIST_FOREACH_BEGIN(ports_to_forward, const char *, port) { |