From 39483260f4b68b593438fc389c123c2d2f6a7e48 Mon Sep 17 00:00:00 2001 From: Florian Walpen Date: Fri, 4 Jan 2019 16:22:01 +0100 Subject: [PATCH] Force 16-byte buffer alignment for SIMD With build option USE_DYNSIMD, SSE SIMD instructions are enabled that require 16-byte aligned buffer data. Multiple buffers are allocated in one contiguous block of memory, the buffer size is determined by the number of 4-byte float samples (nframes) per buffer. If this number is not set to a multiple of 4, the offset of subsequent buffers will be misaligned and jackd crashes with SIGBUS. An example of this actually happening would be using 24 bit sample size in the OSS backend, where the page sized system buffers may result in an odd number of samples per buffer. See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=234574 for a detailed bug report. This change effectively adds some padding by rounding up the allocated buffer size to a multiple of 16 bytes, given that both: a) SIMD instructions are enabled in the build. b) The requested buffer size is not already a multiple of 16 bytes. All other cases should be unaffected. The existing buffer handling, copy and mix code seems to be well prepared for padded buffers, with the number of samples (nframes) and buffer offsets kept separately. --- libjack/port.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libjack/port.c b/libjack/port.c index 53ff6d20..a3deebee 100644 --- a/libjack/port.c +++ b/libjack/port.c @@ -630,13 +630,22 @@ jack_port_get_buffer (jack_port_t *port, jack_nframes_t nframes) size_t jack_port_type_buffer_size (jack_port_type_info_t* port_type_info, jack_nframes_t nframes) { + size_t size; + if ( port_type_info->buffer_scale_factor < 0 ) { return port_type_info->buffer_size; } - return port_type_info->buffer_scale_factor + size = port_type_info->buffer_scale_factor * sizeof(jack_default_audio_sample_t) * nframes; + +#ifdef USE_DYNSIMD + /* Round up to the next multiple of 16 bytes, align buffers for SIMD. */ + size = (size + 15) & (~ (size_t)0x0f); +#endif /* USE_DYNSIMD */ + + return size; } int