X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Ftally%2Ftally.c;h=28a66a9f7fa0ebf384c62d69de8b04b396f71cad;hp=b89b0600ac301d0f5d088cb5a31176c841e1c8c3;hb=252bd427f813c2709c07e64378d5a6c67f51a922;hpb=60b47bf5e0878f014eb1e33e7784c92e43e2fcb6 diff --git a/ccan/tally/tally.c b/ccan/tally/tally.c index b89b0600..28a66a9f 100644 --- a/ccan/tally/tally.c +++ b/ccan/tally/tally.c @@ -1,4 +1,4 @@ -#include "config.h" +/* Licensed under LGPLv3+ - see LICENSE file for details */ #include #include #include @@ -7,6 +7,7 @@ #include #include #include +#include #define SIZET_BITS (sizeof(size_t)*CHAR_BIT) @@ -24,29 +25,36 @@ struct tally *tally_new(unsigned buckets) struct tally *tally; /* There is always 1 bucket. */ - if (buckets == 0) + if (buckets == 0) { buckets = 1; + } + + /* Overly cautious check for overflow. */ + if (sizeof(*tally) * buckets / sizeof(*tally) != buckets) { + return NULL; + } - /* Check for overflow. */ - if (buckets && SIZE_MAX / buckets < sizeof(tally->counts[0])) + tally = (struct tally *)malloc( + sizeof(*tally) + sizeof(tally->counts[0])*(buckets-1)); + if (tally == NULL) { return NULL; - tally = malloc(sizeof(*tally) + sizeof(tally->counts[0])*(buckets-1)); - if (tally) { - tally->max = ((size_t)1 << (SIZET_BITS - 1)); - tally->min = ~tally->max; - tally->total[0] = tally->total[1] = 0; - tally->buckets = buckets; - tally->step_bits = 0; - memset(tally->counts, 0, sizeof(tally->counts[0])*buckets); } + + tally->max = ((size_t)1 << (SIZET_BITS - 1)); + tally->min = ~tally->max; + tally->total[0] = tally->total[1] = 0; + tally->buckets = buckets; + tally->step_bits = 0; + memset(tally->counts, 0, sizeof(tally->counts[0])*buckets); return tally; } static unsigned bucket_of(ssize_t min, unsigned step_bits, ssize_t val) { /* Don't over-shift. */ - if (step_bits == SIZET_BITS) + if (step_bits == SIZET_BITS) { return 0; + } assert(step_bits < SIZET_BITS); return (size_t)(val - min) >> step_bits; } @@ -55,8 +63,9 @@ static unsigned bucket_of(ssize_t min, unsigned step_bits, ssize_t val) static ssize_t bucket_min(ssize_t min, unsigned step_bits, unsigned b) { /* Don't over-shift. */ - if (step_bits == SIZET_BITS) + if (step_bits == SIZET_BITS) { return min; + } assert(step_bits < SIZET_BITS); return min + ((ssize_t)b << step_bits); } @@ -64,8 +73,9 @@ static ssize_t bucket_min(ssize_t min, unsigned step_bits, unsigned b) /* Does shifting by this many bits truncate the number? */ static bool shift_overflows(size_t num, unsigned bits) { - if (bits == 0) + if (bits == 0) { return false; + } return ((num << bits) >> 1) != (num << (bits - 1)); } @@ -78,8 +88,9 @@ static void renormalize(struct tally *tally, unsigned int i, old_min; /* Uninitialized? Don't do anything... */ - if (tally->max < tally->min) + if (tally->max < tally->min) { goto update; + } /* If we don't have sufficient range, increase step bits until * buckets cover entire range of ssize_t anyway. */ @@ -127,15 +138,17 @@ void tally_add(struct tally *tally, ssize_t val) new_max = val; need_renormalize = true; } - if (need_renormalize) + if (need_renormalize) { renormalize(tally, new_min, new_max); + } /* 128-bit arithmetic! If we didn't want exact mean, we could just * pull it out of counts. */ - if (val > 0 && tally->total[0] + val < tally->total[0]) + if (val > 0 && tally->total[0] + val < tally->total[0]) { tally->total[1]++; - else if (val < 0 && tally->total[0] + val > tally->total[0]) + } else if (val < 0 && tally->total[0] + val > tally->total[0]) { tally->total[1]--; + } tally->total[0] += val; tally->counts[bucket_of(tally->min, tally->step_bits, val)]++; } @@ -322,7 +335,7 @@ ssize_t tally_total(const struct tally *tally, ssize_t *overflow) } /* If result is negative, make sure we can represent it. */ - if (tally->total[1] & (1 << (SIZET_BITS-1))) { + if (tally->total[1] & ((size_t)1 << (SIZET_BITS-1))) { /* Must have only underflowed once, and must be able to * represent result at ssize_t. */ if ((~tally->total[1])+1 != 0 @@ -448,7 +461,7 @@ char *tally_histogram(const struct tally *tally, largest_bucket = tally->counts[i]; } - p = graph = malloc(height * (width + 1) + 1); + p = graph = (char *)malloc(height * (width + 1) + 1); if (!graph) { free(tmp); return NULL;