Skip to content

Commit

Permalink
added a bunch of new unit tests for the allocation subsystem and
Browse files Browse the repository at this point in the history
fixed a critical bug resulting in incorrect return value from
hebi_alloc_query when an allocid hadn't yet been cached for the thread
  • Loading branch information
suiginsoft committed Jan 8, 2017
1 parent b8d6403 commit a38afc5
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 5 deletions.
14 changes: 12 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ BENCH_BIN := $(BENCH_P_BIN)
BENCH_OBJ := bench/bench.o
BENCH_DEPS := $(DEPS) bench/bench.h

CHECK_ALLOC := \
valid \
query \
addremove \
fixed \

CHECK_P := \
pcmp \
pcopy \
Expand Down Expand Up @@ -312,9 +318,10 @@ CHECK_SRC := \
zdirty \
zpermutation

CHECK_ALLOC_BIN := $(CHECK_ALLOC:%=check/alloc/%)
CHECK_P_BIN := $(CHECK_P:%=check/p/%)
CHECK_Z_BIN := $(CHECK_Z:%=check/z/%)
CHECK_BIN := $(CHECK_P_BIN) $(CHECK_Z_BIN)
CHECK_BIN := $(CHECK_ALLOC_BIN) $(CHECK_P_BIN) $(CHECK_Z_BIN)
CHECK_OBJ := $(CHECK_SRC:%=check/%.o)
CHECK_DEPS := $(DEPS) check/check.h

Expand All @@ -325,7 +332,7 @@ Q := $(Q_$(V))
.SUFFIXES:
.SUFFIXES: .c .s .o .po

.PHONY: all config check check/p check/z \
.PHONY: all config check check/alloc check/p check/z \
clean scrub dist install uninstall options

all: $(LIBS)
Expand Down Expand Up @@ -377,6 +384,9 @@ bench/libbench.a: $(BENCH_DEPS) $(BENCH_OBJ)
check: $(CHECK_BIN)
@sh runtests.sh "check" $(CHECK_BIN)

check/alloc: $(CHECK_ALLOC_BIN)
@sh runtests.sh "check/alloc" $(CHECK_ALLOC_BIN)

check/p: $(CHECK_P_BIN)
@sh runtests.sh "check/p" $(CHECK_P_BIN)

Expand Down
110 changes: 110 additions & 0 deletions check/alloc/addremove.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/*
* hebimath - arbitrary precision arithmetic library
* See LICENSE file for copyright and license details
*/

#include "../check.h"

enum { MAX_ITERATIONS = 256 };
enum { MAX_ALLOCATORS = 1024 };

static hebi_allocid allocators[MAX_ALLOCATORS];
static hebi_allocid previous_allocators[MAX_ALLOCATORS];
static int allocation_counts[MAX_ALLOCATORS];
static hebi_packet allocation_packets[MAX_ALLOCATORS];

static void *
customalloc(void *arg, size_t alignment, size_t size)
{
assert((uintptr_t)arg < MAX_ALLOCATORS);
assert(alignment == HEBI_PACKET_ALIGNMENT);
assert(size == sizeof(hebi_packet));
allocation_counts[(uintptr_t)arg]++;
return &allocation_packets[(uintptr_t)arg];
}

static void
customfree(void *arg, void *ptr, size_t size)
{
assert((uintptr_t)arg < MAX_ALLOCATORS);
assert(ptr == &allocation_packets[(uintptr_t)arg]);
assert(size == sizeof(hebi_packet));
allocation_counts[(uintptr_t)arg]--;
}

int
main(int argc, char *argv[])
{
hebi_allocid id;
const struct hebi_allocfnptrs *fp;
struct hebi_allocfnptrs fnptrs;
size_t iteration;
hebi_packet *p;
size_t i;

for (iteration = 0; iteration < MAX_ITERATIONS; iteration++) {
for (i = 0; i < MAX_ALLOCATORS; i++) {
fnptrs.ha_alloc = &customalloc;
fnptrs.ha_free = &customfree;
fnptrs.ha_arg = (void *)(uintptr_t)i;
allocators[i] = hebi_alloc_add(&fnptrs);
assert(allocators[i] > 0);
assert(!iteration || allocators[i] != previous_allocators[i]);
}

for (i = 0; i < MAX_ALLOCATORS; i++) {
assert(hebi_alloc_valid(allocators[i]));
assert(!iteration || !hebi_alloc_valid(previous_allocators[i]));
}

for (i = 0; i < MAX_ALLOCATORS; i++) {
assert(allocation_counts[i] == 0);
p = hebi_alloc(allocators[i], HEBI_PACKET_ALIGNMENT, sizeof(hebi_packet));
assert(allocation_counts[i] == 1);
assert(p == &allocation_packets[i]);
}

for (i = MAX_ALLOCATORS; i > 0; i--) {
assert(allocation_counts[i-1] == 1);

fp = hebi_alloc_query(&id, allocators[i-1]);
assert(id == allocators[i-1]);
assert(fp && fp->ha_alloc == &customalloc &&
fp->ha_free == &customfree &&
fp->ha_arg == (void *)(uintptr_t)(i-1));

p = hebi_allocfp(fp, HEBI_PACKET_ALIGNMENT, sizeof(hebi_packet));
assert(allocation_counts[i-1] == 2);
assert(p == &allocation_packets[i-1]);
}

for (i = 0; i < MAX_ALLOCATORS; i++) {
assert(allocation_counts[i] == 2);

fp = hebi_alloc_query(&id, allocators[i]);
assert(id == allocators[i]);
assert(fp && fp->ha_alloc == &customalloc &&
fp->ha_free == &customfree &&
fp->ha_arg == (void *)(uintptr_t)i);

hebi_freefp(fp, &allocation_packets[i], sizeof(hebi_packet));
assert(allocation_counts[i] == 1);
}

for (i = MAX_ALLOCATORS; i > 0; i--) {
assert(allocation_counts[i-1] == 1);
hebi_free(allocators[i-1], &allocation_packets[i-1], sizeof(hebi_packet));
assert(allocation_counts[i-1] == 0);
}

for (i = 0; i < MAX_ALLOCATORS; i++) {
previous_allocators[i] = allocators[i];
hebi_alloc_remove(allocators[i]);
assert(!hebi_alloc_valid(allocators[i]));
}
}

(void)argc;
(void)argv;
return 0;
}
55 changes: 55 additions & 0 deletions check/alloc/fixed.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* hebimath - arbitrary precision arithmetic library
* See LICENSE file for copyright and license details
*/

#include "../check.h"

int
main(int argc, char *argv[])
{
char fixedbuf[80];
void* p;

const struct hebi_allocfnptrs *fp;
struct hebi_errstate es;
struct hebi_error err;
jmp_buf env;
int i;

fp = hebi_alloc_query(NULL, HEBI_ALLOC_FIXED);
assert(fp && fp->ha_alloc && fp->ha_free);

hebi_error_save(&es);

p = NULL;
i = setjmp(env);

if (i > 0) {
assert(hebi_error_last(&err));
assert(err.he_domain == HEBI_ERRDOM_HEBI && err.he_code == HEBI_ENOMEM);
}

if (i == 0) {
hebi_error_jmp(env, 1);
hebi_freefp(fp, NULL, 0);
hebi_freefp(fp, fixedbuf, sizeof(fixedbuf));
p = hebi_allocfp(fp, 8, 32);
assert(!"allocating with HEBI_ALLOC_FIXED didn't raise an error");
} else if (i == 1) {
hebi_error_jmp(env, 2);
hebi_free(HEBI_ALLOC_FIXED, NULL, 0);
hebi_free(HEBI_ALLOC_FIXED, fixedbuf, sizeof(fixedbuf));
p = hebi_alloc(HEBI_ALLOC_FIXED, 16, 64);
assert(!"allocating with HEBI_ALLOC_FIXED didn't raise an error");
}

assert(i == 2);
assert(p == NULL);

hebi_error_restore(&es);

(void)argc;
(void)argv;
return 0;
}
91 changes: 91 additions & 0 deletions check/alloc/query.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* hebimath - arbitrary precision arithmetic library
* See LICENSE file for copyright and license details
*/

#include "../check.h"
#include <limits.h>

static void
testvalid(void)
{
const struct hebi_allocfnptrs *fp;
const struct hebi_allocfnptrs *sfp;
const struct hebi_allocfnptrs *dfp;
const struct hebi_allocfnptrs *ffp;
hebi_allocid id;

fp = hebi_alloc_query(NULL, HEBI_ALLOC_STDLIB);
assert(fp && fp->ha_alloc && fp->ha_free);

dfp = hebi_alloc_query(NULL, HEBI_ALLOC_DEFAULT);
sfp = hebi_alloc_query(NULL, HEBI_ALLOC_SCRATCH);
assert(dfp && sfp && fp == dfp && dfp == sfp);

ffp = hebi_alloc_query(NULL, HEBI_ALLOC_FIXED);
assert(ffp && ffp != fp && ffp->ha_alloc && ffp->ha_free);

fp = hebi_alloc_query(&id, HEBI_ALLOC_STDLIB);
assert(fp == dfp && id == HEBI_ALLOC_STDLIB);

dfp = hebi_alloc_query(&id, HEBI_ALLOC_DEFAULT);
assert(fp == dfp && id == HEBI_ALLOC_STDLIB);

sfp = hebi_alloc_query(&id, HEBI_ALLOC_SCRATCH);
assert(fp == sfp && id == HEBI_ALLOC_STDLIB);

ffp = hebi_alloc_query(&id, HEBI_ALLOC_FIXED);
assert(ffp && ffp != fp && id == HEBI_ALLOC_FIXED);
}

static void
testinvalid(void)
{
enum { NUM_INVALID = 8 };

static const hebi_allocid invalid_ids[NUM_INVALID] = {
HEBI_ALLOC_INVALID,
INT_MIN,
INT_MAX,
1,
2,
16384,
-25,
-28415
};

struct hebi_errstate es;
struct hebi_error err;
hebi_allocid id;
jmp_buf env;
int i;

hebi_error_save(&es);

i = setjmp(env);

if (i > 0) {
assert(hebi_error_last(&err));
assert(err.he_domain == HEBI_ERRDOM_HEBI && err.he_code == HEBI_EBADVALUE);
}

if (i >= 0 && i < NUM_INVALID) {
hebi_error_jmp(env, i + 1);
(void)hebi_alloc_query(&id, invalid_ids[(size_t)i]);
assert(!"hebi_alloc_query didn't raise an error");
}

assert(i == NUM_INVALID);

hebi_error_restore(&es);
}

int
main(int argc, char *argv[])
{
testvalid();
testinvalid();
(void)argc;
(void)argv;
return 0;
}
24 changes: 24 additions & 0 deletions check/alloc/valid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* hebimath - arbitrary precision arithmetic library
* See LICENSE file for copyright and license details
*/

#include "../check.h"
#include <limits.h>

int
main(int argc, char *argv[])
{
assert(hebi_alloc_valid(HEBI_ALLOC_DEFAULT));
assert(hebi_alloc_valid(HEBI_ALLOC_SCRATCH));
assert(hebi_alloc_valid(HEBI_ALLOC_STDLIB));
assert(hebi_alloc_valid(HEBI_ALLOC_FIXED));
assert(!hebi_alloc_valid(HEBI_ALLOC_INVALID));
assert(!hebi_alloc_valid(1));
assert(!hebi_alloc_valid(INT_MAX));
assert(!hebi_alloc_valid(INT_MIN));

(void)argc;
(void)argv;
return 0;
}
2 changes: 1 addition & 1 deletion config.def.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
* allocators to (MAX_PAGES * PAGE_SIZE) % MAX_ALLOCATORS where
* MAX_ALLOCATORS is the number of unique allocator handles that can
* be stored in a hebi_integer. On 32-bit platforms MAX_ALLOCATORS is
* 2^24-2 and on 64-bit platforms MAX_ALLOCATORS is INT_MAX-1.
* 1024 and on 64-bit platforms MAX_ALLOCATORS is 65536.
*
* These values must be powers of 2.
*/
Expand Down
8 changes: 6 additions & 2 deletions src/alloc_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ hebi_alloc_query(hebi_allocid *rid, hebi_allocid id)
unsigned int used;
unsigned int tested;
unsigned int hashcode;
int found;
#endif

/* query the allocator key and handle builtin allocators */
Expand Down Expand Up @@ -520,13 +521,16 @@ hebi_alloc_query(hebi_allocid *rid, hebi_allocid id)
used = ctx->allocused;
if (used) {
tested = 0;
found = 0;
while (ctx->allockeys[i] > 0 && tested < used) {
if (ctx->allockeys[i] == key)
if (ctx->allockeys[i] == key) {
found = 1;
break;
}
i = (i + 1) & ALLOC_CACHE_MASK;
tested++;
}
if (tested < used) {
if (found) {
if (rid)
*rid = id;
return ctx->allocvalues[i];
Expand Down

0 comments on commit a38afc5

Please sign in to comment.