aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/compat_ohash.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2014-06-20 02:24:40 +0000
committerIngo Schwarze <schwarze@openbsd.org>2014-06-20 02:24:40 +0000
commitc2201e153e701130fbd08c75765b330f9280144f (patch)
tree2486817a616731edd1f5e98834c12ed2b786a044 /compat_ohash.c
parent4b68a3c80b4d2c00a2dd66f531e52f4677a118c6 (diff)
downloadmandoc-c2201e153e701130fbd08c75765b330f9280144f.tar.gz
mandoc-c2201e153e701130fbd08c75765b330f9280144f.tar.zst
mandoc-c2201e153e701130fbd08c75765b330f9280144f.zip
Merge from OpenBSD - Marc Espie improved the ohash interface:
* rename the halloc callback to calloc, provide overflow protection * rename the hfree callback to free, drop the useless size argument * prevent integer overflows in ohash_resize
Diffstat (limited to 'compat_ohash.c')
-rw-r--r--compat_ohash.c32
1 files changed, 18 insertions, 14 deletions
diff --git a/compat_ohash.c b/compat_ohash.c
index 33c57afc..0992b365 100644
--- a/compat_ohash.c
+++ b/compat_ohash.c
@@ -29,6 +29,7 @@ int dummy;
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include "compat_ohash.h"
struct _ohash_record {
@@ -69,8 +70,7 @@ ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
void
ohash_delete(struct ohash *h)
{
- (h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
- h->info.data);
+ (h->info.free)(h->t, h->info.data);
#ifndef NDEBUG
h->t = NULL;
#endif
@@ -80,13 +80,17 @@ static void
ohash_resize(struct ohash *h)
{
struct _ohash_record *n;
- unsigned int ns, j;
+ size_t ns;
+ unsigned int j;
unsigned int i, incr;
- if (4 * h->deleted < h->total)
- ns = h->size << 1;
- else if (3 * h->deleted > 2 * h->total)
- ns = h->size >> 1;
+ if (4 * h->deleted < h->total) {
+ if (h->size >= (UINT_MAX >> 1U))
+ ns = UINT_MAX;
+ else
+ ns = h->size << 1U;
+ } else if (3 * h->deleted > 2 * h->total)
+ ns = h->size >> 1U;
else
ns = h->size;
if (ns < MINSIZE)
@@ -95,7 +99,8 @@ ohash_resize(struct ohash *h)
STAT_HASH_EXPAND++;
STAT_HASH_SIZE += ns - h->size;
#endif
- n = (h->info.halloc)(sizeof(struct _ohash_record) * ns, h->info.data);
+
+ n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data);
if (!n)
return;
@@ -112,8 +117,7 @@ ohash_resize(struct ohash *h)
n[i].p = h->t[j].p;
}
}
- (h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
- h->info.data);
+ (h->info.free)(h->t, h->info.data);
h->t = n;
h->size = ns;
h->total -= h->deleted;
@@ -199,12 +203,12 @@ ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
#endif
/* Copy info so that caller may free it. */
h->info.key_offset = info->key_offset;
- h->info.halloc = info->halloc;
- h->info.hfree = info->hfree;
+ h->info.calloc = info->calloc;
+ h->info.free = info->free;
h->info.alloc = info->alloc;
h->info.data = info->data;
- h->t = (h->info.halloc)(sizeof(struct _ohash_record) * h->size,
- h->info.data);
+ h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record),
+ h->info.data);
h->total = h->deleted = 0;
}