aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2016-05-17 11:58:47 -0400
committerDavid Robillard <d@drobilla.net>2016-05-17 11:58:47 -0400
commite2d1f43bc10172272a74e2bcf2460b0dbc91aeea (patch)
treef16f51f759e9a14e7e9d3f6e0fac425200c1af68 /src
parent4177848a044eead797dfa3262c1781491cc6a56f (diff)
downloadserd-e2d1f43bc10172272a74e2bcf2460b0dbc91aeea.tar.gz
serd-e2d1f43bc10172272a74e2bcf2460b0dbc91aeea.tar.bz2
serd-e2d1f43bc10172272a74e2bcf2460b0dbc91aeea.zip
Fix unaligned memory access (UB which breaks ARM)
With this fix, the test suite runs cleanly with UBSan.
Diffstat (limited to 'src')
-rw-r--r--src/reader.c12
-rw-r--r--src/serd_internal.h34
2 files changed, 39 insertions, 7 deletions
diff --git a/src/reader.c b/src/reader.c
index e49c2a10..e6af0b1c 100644
--- a/src/reader.c
+++ b/src/reader.c
@@ -1,5 +1,5 @@
/*
- Copyright 2011-2015 David Robillard <http://drobilla.net>
+ Copyright 2011-2016 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -173,8 +173,8 @@ static Ref
push_node_padded(SerdReader* reader, size_t maxlen,
SerdType type, const char* str, size_t n_bytes)
{
- uint8_t* mem = serd_stack_push(&reader->stack,
- sizeof(SerdNode) + maxlen + 1);
+ void* mem = serd_stack_push_aligned(
+ &reader->stack, sizeof(SerdNode) + maxlen + 1, sizeof(SerdNode));
SerdNode* const node = (SerdNode*)mem;
node->n_bytes = node->n_chars = n_bytes;
@@ -182,13 +182,13 @@ push_node_padded(SerdReader* reader, size_t maxlen,
node->type = type;
node->buf = NULL;
- uint8_t* buf = mem + sizeof(SerdNode);
+ uint8_t* buf = (uint8_t*)(node + 1);
memcpy(buf, str, n_bytes + 1);
#ifdef SERD_STACK_CHECK
reader->allocs = realloc(
reader->allocs, sizeof(uint8_t*) * (++reader->n_allocs));
- reader->allocs[reader->n_allocs - 1] = (mem - reader->stack.buf);
+ reader->allocs[reader->n_allocs - 1] = ((uint8_t*)mem - reader->stack.buf);
#endif
return (uint8_t*)node - reader->stack.buf;
}
@@ -243,7 +243,7 @@ pop_node(SerdReader* reader, Ref ref)
#endif
SerdNode* const node = deref(reader, ref);
uint8_t* const top = reader->stack.buf + reader->stack.size;
- serd_stack_pop(&reader->stack, top - (uint8_t*)node);
+ serd_stack_pop_aligned(&reader->stack, top - (uint8_t*)node);
}
return 0;
}
diff --git a/src/serd_internal.h b/src/serd_internal.h
index 20700bb8..23fd75b4 100644
--- a/src/serd_internal.h
+++ b/src/serd_internal.h
@@ -1,5 +1,5 @@
/*
- Copyright 2011-2014 David Robillard <http://drobilla.net>
+ Copyright 2011-2016 David Robillard <http://drobilla.net>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -123,6 +123,38 @@ serd_stack_pop(SerdStack* stack, size_t n_bytes)
stack->size -= n_bytes;
}
+static inline void*
+serd_stack_push_aligned(SerdStack* stack, size_t n_bytes, size_t align)
+{
+ // Push one byte to ensure space for a pad count
+ serd_stack_push(stack, 1);
+
+ // Push padding if necessary
+ const uint8_t pad = align - stack->size % align;
+ if (pad > 0) {
+ serd_stack_push(stack, pad);
+ }
+
+ // Set top of stack to pad count so we can properly pop later
+ stack->buf[stack->size - 1] = pad;
+
+ // Push requested space at aligned location
+ return serd_stack_push(stack, n_bytes);
+}
+
+static inline void
+serd_stack_pop_aligned(SerdStack* stack, size_t n_bytes)
+{
+ // Pop requested space down to aligned location
+ serd_stack_pop(stack, n_bytes);
+
+ // Get amount of padding from top of stack
+ const uint8_t pad = stack->buf[stack->size - 1];
+
+ // Pop padding and pad count
+ serd_stack_pop(stack, pad + 1);
+}
+
/* Bulk Sink */
typedef struct SerdBulkSinkImpl {