aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2021-02-24 21:07:07 -0500
committerDavid Robillard <d@drobilla.net>2021-03-08 23:23:05 -0500
commit36e2f27502524155e6475a75ffcab4999fce166a (patch)
treec193ccab896fa63a48e0dba5eecfccfc9ec46a2b
parent02507b57fae1e29572a11be8894b7dde9048da5d (diff)
downloadserd-36e2f27502524155e6475a75ffcab4999fce166a.tar.gz
serd-36e2f27502524155e6475a75ffcab4999fce166a.tar.bz2
serd-36e2f27502524155e6475a75ffcab4999fce166a.zip
Align node allocations
-rw-r--r--src/node.c10
-rw-r--r--src/reader.c13
-rw-r--r--src/stack.h8
-rw-r--r--src/system.c16
-rw-r--r--src/system.h5
-rw-r--r--src/writer.c2
-rw-r--r--test/test_overflow.c28
7 files changed, 61 insertions, 21 deletions
diff --git a/src/node.c b/src/node.c
index 0322dd64..0da9d0ed 100644
--- a/src/node.c
+++ b/src/node.c
@@ -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();