diff options
author | Jessica Clarke <jrtc27@jrtc27.com> | 2023-01-27 23:45:29 +0000 |
---|---|---|
committer | Jessica Clarke <jrtc27@jrtc27.com> | 2023-01-27 23:45:29 +0000 |
commit | 8f1f38224d1136d920156be08f3548fa3c9ad83b (patch) | |
tree | 83dd80d7a5a6143775cd51b5ec1607948f383153 /gencode.c | |
parent | 75f608b0da534fbd0652bf97e34fb8da31059593 (diff) |
gencode: Unify NetBSD and non-NetBSD alignment, and make more general
Currently the non-NetBSD code assumes that long is the maximum alignment
needed for anything allocated from the chunk allocator. In practice, on
typical 32-bit and 64-bit Unix platforms, this is true, since all the
structures stored in it have only pointers and 32-bit integers. However,
CHERI (on 64-bit architectures) uses 128-bit capabilities to implement C
language pointers, which are a combination of a traditional 64-bit
address, 64 bits of metadata and an additional 129th validity tag bit.
Due to the use of tagged memory to support this tag bit they must be
stored at naturally aligned addresses, i.e. 16 byte aligned, but long is
still only 64-bit, since that is the natural machine word size for
integer arithmetic, and thus if sdup tries to allocate a string of
between 0 and 7 bytes mod 16 a subsequent allocation of any other type
will not be sufficiently aligned for storing a pointer. Technically on
64-bit Windows long is 32-bit and thus insufficient alignment is used
but in practice unaligned accesses work even if they are strictly UB.
Fix this by computing the actual alignment requirement for chunks based
on the set of types that can be stored in a chunk, without making use of
C11's _Alignof. Even if C11 were required, using an explicit list of
types rather than max_align_t allows us to be slightly more efficient in
memory usage, since there are types (like long double) that force it to
be 16 byte aligned that we don't need.
Diffstat (limited to 'gencode.c')
-rw-r--r-- | gencode.c | 29 |
1 files changed, 22 insertions, 7 deletions
@@ -232,6 +232,26 @@ struct chunk { void *m; }; +/* + * A chunk can store any of: + * - a string (guaranteed alignment 1 but present for completeness) + * - a block + * - an slist + * - an arth + * For this simple allocator every allocated chunk gets rounded up to the + * alignment needed for any chunk. + */ +struct chunk_align { + char dummy; + union { + char c; + struct block b; + struct slist s; + struct arth a; + } u; +}; +#define CHUNK_ALIGN (offsetof(struct chunk_align, u)) + /* Code generator state */ struct _compiler_state { @@ -600,13 +620,8 @@ newchunk_nolongjmp(compiler_state_t *cstate, size_t n) int k; size_t size; -#ifndef __NetBSD__ - /* XXX Round up to nearest long. */ - n = (n + sizeof(long) - 1) & ~(sizeof(long) - 1); -#else - /* XXX Round up to structure boundary. */ - n = ALIGN(n); -#endif + /* Round up to chunk alignment. */ + n = (n + CHUNK_ALIGN - 1) & ~(CHUNK_ALIGN - 1); cp = &cstate->chunks[cstate->cur_chunk]; if (n > cp->n_left) { |