diff options
author | David Robillard <d@drobilla.net> | 2021-02-24 21:07:07 -0500 |
---|---|---|
committer | David Robillard <d@drobilla.net> | 2021-03-08 23:23:05 -0500 |
commit | 36e2f27502524155e6475a75ffcab4999fce166a (patch) | |
tree | c193ccab896fa63a48e0dba5eecfccfc9ec46a2b | |
parent | 02507b57fae1e29572a11be8894b7dde9048da5d (diff) | |
download | serd-36e2f27502524155e6475a75ffcab4999fce166a.tar.gz serd-36e2f27502524155e6475a75ffcab4999fce166a.tar.bz2 serd-36e2f27502524155e6475a75ffcab4999fce166a.zip |
Align node allocations
-rw-r--r-- | src/node.c | 10 | ||||
-rw-r--r-- | src/reader.c | 13 | ||||
-rw-r--r-- | src/stack.h | 8 | ||||
-rw-r--r-- | src/system.c | 16 | ||||
-rw-r--r-- | src/system.h | 5 | ||||
-rw-r--r-- | src/writer.c | 2 | ||||
-rw-r--r-- | test/test_overflow.c | 28 |
7 files changed, 61 insertions, 21 deletions
@@ -18,6 +18,7 @@ #include "static_nodes.h" #include "string_utils.h" +#include "system.h" #include "exess/exess.h" #include "serd/serd.h" @@ -97,7 +98,7 @@ SerdNode* serd_node_malloc(size_t n_bytes, SerdNodeFlags flags, SerdNodeType type) { const size_t size = sizeof(SerdNode) + serd_node_pad_size(n_bytes); - SerdNode* node = (SerdNode*)calloc(1, size); + SerdNode* node = (SerdNode*)serd_calloc_aligned(sizeof(SerdNode), size); node->n_bytes = 0; node->flags = flags; @@ -112,7 +113,8 @@ serd_node_set(SerdNode** dst, const SerdNode* src) { const size_t size = serd_node_total_size(src); if (serd_node_total_size(*dst) < size) { - (*dst) = (SerdNode*)realloc(*dst, size); + serd_free_aligned(*dst); + *dst = (SerdNode*)serd_calloc_aligned(sizeof(SerdNode), size); } memcpy(*dst, src, size); @@ -345,7 +347,7 @@ serd_node_copy(const SerdNode* node) } const size_t size = serd_node_total_size(node); - SerdNode* copy = (SerdNode*)calloc(1, size + 3); + SerdNode* copy = (SerdNode*)serd_calloc_aligned(sizeof(SerdNode), size); memcpy(copy, node, size); return copy; @@ -749,5 +751,5 @@ serd_node_flags(const SerdNode* node) void serd_node_free(SerdNode* node) { - free(node); + serd_free_aligned(node); } diff --git a/src/reader.c b/src/reader.c index 44b17704..ceef5fb4 100644 --- a/src/reader.c +++ b/src/reader.c @@ -159,15 +159,26 @@ serd_reader_new(SerdWorld* const world, const SerdSink* const sink, const size_t stack_size) { + if (stack_size < 8 * sizeof(SerdNode)) { + return NULL; + } + SerdReader* me = (SerdReader*)calloc(1, sizeof(SerdReader)); me->world = world; me->sink = sink; - me->stack = serd_stack_new(stack_size); + me->stack = serd_stack_new(stack_size, sizeof(SerdNode)); me->syntax = syntax; me->next_id = 1; me->strict = true; + /* Reserve a bit of space at the end of the stack to zero pad nodes. This + particular kind of overflow could be detected (in emit_statement), but + this is simpler and a bit more resilient to mistakes since the reader + generally pushes only a few bytes at a time, making it pretty unlikely + to overshoot the buffer by this much. */ + me->stack.buf_size -= 8 * sizeof(size_t); + me->rdf_first = push_node(me, SERD_URI, NS_RDF "first", 48); me->rdf_rest = push_node(me, SERD_URI, NS_RDF "rest", 47); me->rdf_nil = push_node(me, SERD_URI, NS_RDF "nil", 46); diff --git a/src/stack.h b/src/stack.h index f6d33f51..0eae1b75 100644 --- a/src/stack.h +++ b/src/stack.h @@ -17,6 +17,8 @@ #ifndef SERD_STACK_H #define SERD_STACK_H +#include "system.h" + #include <assert.h> #include <stdbool.h> #include <stddef.h> @@ -37,10 +39,12 @@ typedef struct { #define SERD_STACK_BOTTOM sizeof(void*) static inline SerdStack -serd_stack_new(size_t size) +serd_stack_new(size_t size, size_t align) { + const size_t aligned_size = (size + (align - 1)) / align * align; + SerdStack stack; - stack.buf = (char*)calloc(size, 1); + stack.buf = (char*)serd_calloc_aligned(align, aligned_size); stack.buf_size = size; stack.size = SERD_STACK_BOTTOM; return stack; diff --git a/src/system.c b/src/system.c index 4f6c37c6..323ed62e 100644 --- a/src/system.c +++ b/src/system.c @@ -27,6 +27,7 @@ #include <stdio.h> #include <stdlib.h> +#include <string.h> void* serd_malloc_aligned(const size_t alignment, const size_t size) @@ -44,6 +45,21 @@ serd_malloc_aligned(const size_t alignment, const size_t size) } void* +serd_calloc_aligned(const size_t alignment, const size_t size) +{ +#if defined(_WIN32) || defined(USE_POSIX_MEMALIGN) + void* const ptr = serd_malloc_aligned(alignment, size); + if (ptr) { + memset(ptr, 0, size); + } + return ptr; +#else + (void)alignment; + return calloc(1, size); +#endif +} + +void* serd_allocate_buffer(const size_t size) { return serd_malloc_aligned(SERD_PAGE_SIZE, size); diff --git a/src/system.h b/src/system.h index a5fb7459..f0e6e267 100644 --- a/src/system.h +++ b/src/system.h @@ -27,6 +27,11 @@ SERD_I_MALLOC_FUNC void* serd_malloc_aligned(size_t alignment, size_t size); +/// Allocate a zeroed buffer aligned to `alignment` bytes +SERD_I_MALLOC_FUNC +void* +serd_calloc_aligned(size_t alignment, size_t size); + /// Allocate an aligned buffer for I/O SERD_I_MALLOC_FUNC void* diff --git a/src/writer.c b/src/writer.c index bf869967..7e3033a8 100644 --- a/src/writer.c +++ b/src/writer.c @@ -1108,7 +1108,7 @@ serd_writer_new(SerdWorld* world, writer->env = env; writer->root_node = NULL; writer->root_uri = SERD_URI_NULL; - writer->anon_stack = serd_stack_new(SERD_PAGE_SIZE); + writer->anon_stack = serd_stack_new(SERD_PAGE_SIZE, SERD_PAGE_SIZE); writer->write_func = write_func; writer->stream = stream; writer->context = context; diff --git a/test/test_overflow.c b/test/test_overflow.c index 5889a867..a4d59368 100644 --- a/test/test_overflow.c +++ b/test/test_overflow.c @@ -39,19 +39,21 @@ main(void) size_t stack_size; } Test; - const Test tests[] = {{":s :p :%99 .", 338}, - {":s :p <http://", 336}, - {":s :p eg:foo", 337}, - {":s :p 1234", 307}, - {":s :p 1234", 338}, - {":s :p (1 2 3 4) .", 352}, - {"@prefix eg: <http://example.org> .", 239}, - {":s :p \"literal\"", 336}, - {":s :p \"verb\"", 275}, - {":s :p _:blank .", 307}, - {":s :p true .", 307}, - {":s :p true .", 341}, - {":s :p \"\"@en .", 339}, + const size_t sizes = 3 * sizeof(size_t); + + const Test tests[] = {{":s :p :%99 .", sizes + 280}, + {":s :p <http://", sizes + 276}, + {":s :p eg:foo", sizes + 275}, + {":s :p 1234", sizes + 177}, + {":s :p 1234", sizes + 280}, + {":s :p (1 2 3 4) .", 8 * sizeof(size_t) + 357}, + {"@prefix eg: <http://example.org> .", sizes + 224}, + {":s :p \"literal\"", sizes + 264}, + {":s :p \"verb\"", sizes + 263}, + {":s :p _:blank .", sizes + 276}, + {":s :p true .", sizes + 295}, + {":s :p true .", sizes + 329}, + {":s :p \"\"@en .", sizes + 302}, {NULL, 0}}; SerdWorld* world = serd_world_new(); |