Alignment of stack variables

Recently I’ve been trying to use Win32 Raw Input. This API requires to allocate some buffer to write input data to:

var raw_input_buffer: [0xFF] u8 = undefined;

Then, after the buffer is filled, I need to cast it to proper type:

const input: *win32.RAWINPUT = @alignCast(@ptrCast(&raw_input_buffer[0]));

Here I’ve found that if raw_input_buffer allocated on stack it is not aligned correctly, making program crash on @alignCast.

I would like to understand if it is expected behaviour. u8 is aligned to 1, but I was expecting that stack space for array still will be aligned to architecture word size.

Zig Version: 0.17.0-dev.314+eae06cf5c

As workaround I’ve put raw_input_buffer to global variable and it resolved the problem. I’m actually wondering, maybe this is more appropriate place for such buffers. Still, would like to know the situation with the stack.

You can override the alignment of variables with var foo: T align(n) = ...

you can do the same with fields too foo: T align(n), and even functions fn foo() align(n) void {}

The only guarantee zig provides is data will be at the appropriate alignment that is either the types default or an overridden alignment.

As explained above, it working as a global is chance.

It is not appropriate as the buffer is quite small, and you may not want its data to persist between calls. Avoid globals unless necessary.

Thank you! Now it’s working on the stack.

Previously I was trying to do it like this:

var raw_input_buffer: [0xFF] align(8) u8  = undefined;

And missed the part that I should align variable and not array element.

The only time alignment will be in the type is with pointers/slices e.g []align(8) u8. That will ofc align the data pointed to and not the place the pointer is stored.

Heh, FWIW sokol_app.h stumbled over the same problem (see changelog entry here: sokol/CHANGELOG.md at master · floooh/sokol · GitHub).

The funny thing is that this alignment problem never caused problems, but was found via Zig because that compiles C code with ASAN in debug mode.

I think the ‘correct’ solution is to allocate the input buffer on the heap, e.g. first call GetRawInputData with a NULL buffer pointer to query the required size, then use that size to allocate a heap buffer, then call GetRawInputData() again with the allocated buffer pointer to get the actual data (in Zig you might want to allocate with the required alignment, in C MSVC malloc guarantees 16-byte alignment, which is good enough).

This is the approach that GLFW is using, and which since then I also use in sokol_app.h.

PS: the problem with this fixed-size buffer raw_input_buffer: [0xFF] u8 is also that theoretically GetRawInputData() may want to return more data than 255 bytes (in reality it doesn’t, but some weird input devices might theoretically).