record: Support architectures with sizeof(void*) > sizeof(long)

I was seeing SIGBUS errors when running TigerVNC inside the record code
because the offsets into the memory buffer were not sufficiently aligned
to use the RecordSetRec (alignof(void*)). The current code ensures that
all offsets are aligned to sizeof(unsigned long), but that may not be
sufficient to load/store a pointer. Architectures where this is not true
include Arm Morello which has 16-byte pointers and 8-byte longs.
This commit is contained in:
Alex Richardson 2022-05-22 14:57:52 +00:00 committed by Matt Turner
parent f1bd82552b
commit cb8938e3d3

View File

@ -54,6 +54,17 @@ from The Open Group.
#include "misc.h" #include "misc.h"
#include "set.h" #include "set.h"
/*
* Ideally we would always use _Alignof(type) here, but that requires C11, so
* we approximate this using sizeof(void*) for older C standards as that
* should be a valid assumption on all supported architectures.
*/
#if defined(__STDC__) && (__STDC_VERSION__ - 0 >= 201112L)
#define MinSetAlignment(type) max(_Alignof(type), _Alignof(unsigned long))
#else
#define MinSetAlignment(type) max(sizeof(void*), sizeof(unsigned long))
#endif
static int static int
maxMemberInInterval(RecordSetInterval * pIntervals, int nIntervals) maxMemberInInterval(RecordSetInterval * pIntervals, int nIntervals)
{ {
@ -179,7 +190,7 @@ BitVectorSetMemoryRequirements(RecordSetInterval * pIntervals, int nIntervals,
{ {
int nlongs; int nlongs;
*alignment = sizeof(unsigned long); *alignment = MinSetAlignment(BitVectorSet);
nlongs = (maxMember + BITS_PER_LONG) / BITS_PER_LONG; nlongs = (maxMember + BITS_PER_LONG) / BITS_PER_LONG;
return (sizeof(BitVectorSet) + nlongs * sizeof(unsigned long)); return (sizeof(BitVectorSet) + nlongs * sizeof(unsigned long));
} }
@ -289,7 +300,7 @@ static int
IntervalListMemoryRequirements(RecordSetInterval * pIntervals, int nIntervals, IntervalListMemoryRequirements(RecordSetInterval * pIntervals, int nIntervals,
int maxMember, int *alignment) int maxMember, int *alignment)
{ {
*alignment = sizeof(unsigned long); *alignment = MinSetAlignment(IntervalListSet);
return sizeof(IntervalListSet) + nIntervals * sizeof(RecordSetInterval); return sizeof(IntervalListSet) + nIntervals * sizeof(RecordSetInterval);
} }