summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorpeter <peter@pmikkelsen.com>2026-09-04 19:45:05 +0000
committerpeter <peter@pmikkelsen.com>2026-09-04 19:45:05 +0000
commit4d1f519e1bcca659100a2593bd7ca7f2f4983ffe (patch)
treedf2b96f6bb871c8a52c8eda2ac2e2d87387d91bc /src
parentcde3778df1f5086052d01bf770910b2e05d0a1e1 (diff)
Add a test which runs all the scripts in tests/scripts/good to meaure how many memory allocations they perform, and then rerun them with a mode that causes the memory allocator to fail after N allocations. The scripts are run for all values of N from 0 to the number of allocations they need to succeed.
FossilOrigin-Name: ed1953c203d3493d9c1adbcb9256d7d380bc1fdcfc7856f03f9d801291f478cd
Diffstat (limited to 'src')
-rw-r--r--src/bin/aplwc_repl.h1
-rw-r--r--src/bin/main.c61
-rw-r--r--src/bin/util.c16
-rw-r--r--src/include/aplwc.h1
-rw-r--r--src/lib/main.c4
-rw-r--r--src/lib/memory.c11
6 files changed, 78 insertions, 16 deletions
diff --git a/src/bin/aplwc_repl.h b/src/bin/aplwc_repl.h
index 7de1c59..31a0516 100644
--- a/src/bin/aplwc_repl.h
+++ b/src/bin/aplwc_repl.h
@@ -32,6 +32,7 @@
/* util.c */
unsigned long getenv_ulong(const char *, unsigned long);
+long getenv_long(const char *, long);
/* wrappers.c */
void *wrapped_malloc(size_t);
diff --git a/src/bin/main.c b/src/bin/main.c
index 02b3d0a..481874c 100644
--- a/src/bin/main.c
+++ b/src/bin/main.c
@@ -23,6 +23,9 @@
#include <errno.h>
#include "aplwc_repl.h"
+static uint64_t alloc_count;
+static long memdbg;
+
static void *
my_alloc(size_t min, size_t max, size_t *actual)
{
@@ -61,6 +64,16 @@ my_dealloc(void *p)
free(p);
}
+static int
+hook_alloc(void)
+{
+ alloc_count++;
+ if((memdbg >= 0) && (alloc_count > ((uint64_t)memdbg)))
+ return 0;
+ else
+ return 1;
+}
+
int
main(int argc, char *argv[])
{
@@ -84,9 +97,12 @@ main(int argc, char *argv[])
exit_code = 0;
line_number = 0;
+ memdbg = getenv_long("APLWC_ALLOC_FAIL_AFTER", -2);
+
memset(&fns, 0, sizeof(fns));
fns.alloc = my_alloc;
fns.dealloc = my_dealloc;
+ fns.hook_alloc = hook_alloc;
while((opt = getopt(argc, argv, "x")) != -1){
switch(opt){
@@ -96,7 +112,8 @@ main(int argc, char *argv[])
default:
usage:
fprintf(stderr, "Usage: %s [-x] [file]\n", argv[0]);
- return 1;
+ exit_code = 1;
+ goto end;
}
}
@@ -105,7 +122,8 @@ usage:
f = fopen(argv[optind], "r");
if(f == NULL){
fprintf(stderr, "Could not open file: %s: %s\n", argv[optind], strerror(errno));
- return 1;
+ exit_code = 1;
+ goto end;
}
}else if(optind == argc)
f = stdin;
@@ -115,14 +133,16 @@ usage:
aplwc = aplwc_new(fns, &ret);
if(ret){
fprintf(stderr, "Couldn't create new aplwc instance: %s\n", aplwc_errstr_rc(ret));
- return 1;
+ exit_code = 1;
+ goto end;
}
if(input_file){
if(fseek(f, 0, SEEK_END)){
file_size:
fprintf(stderr, "Failed to determine file size\n");
- return 1;
+ exit_code = 1;
+ goto end;
}
tmp = ftell(f);
if(tmp < 0)
@@ -132,11 +152,13 @@ file_size:
input = malloc(input_size);
if(input == NULL){
fprintf(stderr, "Failed to allocate space for file contents\n");
- return 1;
+ exit_code = 1;
+ goto end;
}
if(fread(input, 1, input_size, f) < input_size){
fprintf(stderr, "Failed to read file contents\n");
- return 1;
+ exit_code = 1;
+ goto end;
}
fclose(f);
@@ -156,14 +178,15 @@ file_size:
ret = aplwc_load_module(aplwc, "Main", src, src_size);
if(ret){
fprintf(stderr, "Couldn't load Main module from file %s: %s\n", argv[optind], aplwc_errstr_rc(ret));
- return 1;
+ exit_code = 1;
+ goto end;
}
free(input);
input = NULL;
}
if(xflag)
- goto exit;
+ goto end;
for(;;){
if(input)
@@ -183,10 +206,11 @@ file_size:
aplwc_read(aplwc, input, &line);
if(!aplwc_valid_line(&line)){
line_error:
+ ret = aplwc_last_error(aplwc);
fprintf(stderr, "error on line %d: %s: %s\n", line_number, aplwc_errstr(aplwc), input);
if(input_file){
exit_code = 1;
- goto exit;
+ goto end;
}
continue;
}
@@ -197,14 +221,29 @@ line_error:
}
}
-exit:
+end:
if(input)
free(input);
if(aplwc_valid_line(&line))
aplwc_free_line(&line);
if(aplwc_valid_value(&value))
aplwc_free_value(&value);
+ if(aplwc)
+ aplwc_destroy(aplwc);
+
+ if(memdbg == -1){
+ f = fdopen(3, "w");
+ if(f == NULL){
+ fprintf(stderr, "Failed to open fd 3\n");
+ exit_code = 1;
+ }else{
+ fprintf(f, "%ld\n", alloc_count);
+ fclose(f);
+ }
+ }
+
+ if((exit_code != 0) && (memdbg >= 0) && (ret == APLWC_OUT_OF_MEMORY))
+ exit_code = 0;
- aplwc_destroy(aplwc);
return exit_code;
}
diff --git a/src/bin/util.c b/src/bin/util.c
index b887447..c609e48 100644
--- a/src/bin/util.c
+++ b/src/bin/util.c
@@ -34,3 +34,19 @@ getenv_ulong(const char *name, unsigned long def)
}
return ret;
}
+
+long
+getenv_long(const char *name, long def)
+{
+ long ret, parsed;
+ char *env, *p;
+
+ ret = def;
+ env = getenv(name);
+ if((env != NULL) && (strlen(env) > 0)){
+ parsed = strtol(env, &p, 10);
+ if((*p) == 0)
+ ret = parsed;
+ }
+ return ret;
+}
diff --git a/src/include/aplwc.h b/src/include/aplwc.h
index cb4fe84..f07cd10 100644
--- a/src/include/aplwc.h
+++ b/src/include/aplwc.h
@@ -47,6 +47,7 @@ typedef struct { struct aplwc_ref ref; } AplwcValue;
struct aplwc_fns {
void *(*alloc)(size_t, size_t, size_t *);
void (*dealloc)(void *);
+ int (*hook_alloc)(void);
};
struct aplwc *aplwc_new(struct aplwc_fns, enum aplwc_rc *);
diff --git a/src/lib/main.c b/src/lib/main.c
index d2c353f..1bafa27 100644
--- a/src/lib/main.c
+++ b/src/lib/main.c
@@ -44,8 +44,10 @@ aplwc_new(struct aplwc_fns fns, enum aplwc_rc *rcp)
rc = aplwc_load_module(aplwc, "Boot", (const char *)boot_src, boot_src_len);
end:
- if(rc != APLWC_OK)
+ if(rc != APLWC_OK){
aplwc_destroy(aplwc);
+ aplwc = NULL;
+ }
assert(rcp);
*rcp = rc;
return aplwc;
diff --git a/src/lib/memory.c b/src/lib/memory.c
index b5bb82a..583b2ab 100644
--- a/src/lib/memory.c
+++ b/src/lib/memory.c
@@ -53,7 +53,7 @@ memory_init(struct aplwc *aplwc)
void
memory_destroy(struct aplwc *aplwc)
{
- if(aplwc->fns.dealloc)
+ if(aplwc->fns.dealloc && aplwc->unaligned_data)
aplwc->fns.dealloc(aplwc->unaligned_data);
}
@@ -173,8 +173,7 @@ grow(struct aplwc *aplwc, size_t extra)
if(aplwc->data){
memmove(aligned_data, aplwc->data, aplwc->size);
fixrefs(aplwc, aligned_data, aplwc->data);
- if(aplwc->fns.dealloc)
- aplwc->fns.dealloc(aplwc->unaligned_data);
+ memory_destroy(aplwc);
for(free = head; free; free = next(free))
if(next(free))
assert((free)->tag != CHUNK_TAG_FREE);
@@ -380,7 +379,9 @@ alloc(struct aplwc *aplwc, size_t size, enum chunk_tag tag)
if(pad)
size += ALIGNMENT - pad;
-
+ if(aplwc->fns.hook_alloc && !aplwc->fns.hook_alloc())
+ goto fail;
+
attempt = 0;
retry:
DEBUG(check_mem(aplwc));
@@ -398,6 +399,8 @@ retry:
goto retry;
/* fall-through */
default:
+fail:
+ aplwc->last_error = APLWC_OUT_OF_MEMORY;
return NULL;
}
}