Unaligned memory access

118 views
Skip to first unread message

Andre Leiradella

unread,
Feb 14, 2026, 8:41:26 AM (6 days ago) Feb 14
to lu...@googlegroups.com
Hi list,

I usually embed C structures and C++ classes directly into Lua userdata blocks, instead of creating them in the heap and embedding the pointer in the userdata. This avoids a pointer indirection, and having to remember to delete the object when the userdata is collected. Not big deals I know, but this is how I like to do it.

However, I have alignment issues in the userdata from time to time. It happens when the userdata contains something that requires a 16 byte alignment. Since this is not enforced by lua_newuserdata, the program will crash with things like this:

   0x00007ff6fe911135 <+85>:    xorps  %xmm6,%xmm6
=> 0x00007ff6fe911138 <+88>:    movaps %xmm6,0x50(%rdi)

where %rdi is not 16-bytes aligned.

The workaround is easy enough: allocate the object in the heap with new, and embed the pointer in the userdata. Compiler flags that will generate movups for the case above are also an option.

This is not a request to change anything or add new APIs, it's just to let the Lua maintainers know that this happens in the wild in code that uses Lua. Maybe they will find it useful to fix it somehow.

Cheers,

Andre

Sainan

unread,
Feb 14, 2026, 9:00:40 AM (6 days ago) Feb 14
to lu...@googlegroups.com
lua_newuserdata does not provide alignment guarantees, but practically, you will see that it is only 8-byte aligned (on 64-bit). Of course, your workaround of using 'new' works, but you can also simply allocate 15 more bytes so you can safely offset the pointer:

char *data = reinterpret_cast<char*>(lua_newuserdata(L, data_len + 15));
if (reinterpret_cast<uintptr_t>(data) % 16) { /* data is not 16-byte aligned? */
data = reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(data) + (16 - (reinterpret_cast<uintptr_t>(data) % 16))); /* align data to 16-byte boundary */
}

-- Sainan

Roberto Ierusalimschy

unread,
Feb 14, 2026, 12:39:37 PM (6 days ago) Feb 14
to lu...@googlegroups.com
> However, I have alignment issues in the userdata from time to time. It
> happens when the userdata contains something that requires a 16 byte
> alignment. Since this is not enforced by lua_newuserdata, the program will
> crash with things like this:
>
> 0x00007ff6fe911135 <+85>: xorps %xmm6,%xmm6
> => 0x00007ff6fe911138 <+88>: movaps %xmm6,0x50(%rdi)
>
> where %rdi is not 16-bytes aligned.

Lua ensures that the memory in a userdata is aligned with values
in ISO C. If you have other objects that require other alignments
(such as 16-bit values), you can redefine the macro LUAI_MAXALIGN, in
luaconf.h. Its standard definition is like this:

#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l

Just toss these other objects in this list.

-- Roberto

Andre Leiradella

unread,
Feb 14, 2026, 1:29:45 PM (6 days ago) Feb 14
to lua-l
Em sábado, 14 de fevereiro de 2026 às 17:39:37 UTC, Roberto Ierusalimschy escreveu:
Lua ensures that the memory in a userdata is aligned with values
in ISO C. If you have other objects that require other alignments
(such as 16-bit values), you can redefine the macro LUAI_MAXALIGN, in
luaconf.h. Its standard definition is like this:

#define LUAI_MAXALIGN lua_Number n; double u; void *s; lua_Integer i; long l

Just toss these other objects in this list.

-- Roberto

Thanks, I wasn't aware of that macro.

Andre 

Andre Leiradella

unread,
Feb 14, 2026, 1:31:38 PM (6 days ago) Feb 14
to lua-l
Good idea, I ended up using it instead of the additional pointer indirection:

ud = (ud + 15) & ~(uintptr_t)15;

Andre

Spar

unread,
Feb 14, 2026, 2:34:10 PM (6 days ago) Feb 14
to lua-l
You can also look at std::align or how sol2 manages this: https://github.com/ThePhD/sol2/blob/develop/include/sol/stack_core.hpp#L129
--
You received this message because you are subscribed to the Google Groups "lua-l" group.
To unsubscribe from this group and stop receiving emails from it, send an email to lua-l+un...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/lua-l/7d247e5e-5c1d-4ab6-91bf-52c305546e02n%40googlegroups.com.

Gé Weijers

unread,
Feb 14, 2026, 4:44:26 PM (6 days ago) Feb 14
to lu...@googlegroups.com
On Sat, Feb 14, 2026 at 9:39 AM Roberto Ierusalimschy <rob...@inf.puc-rio.br> wrote:

Lua ensures that the memory in a userdata is aligned with values
in ISO C. If you have other objects that require other alignments
(such as 16-bit values), you can redefine the macro LUAI_MAXALIGN, in
luaconf.h. Its standard definition is like this:

  #define LUAI_MAXALIGN  lua_Number n; double u; void *s; lua_Integer i; long l

Just toss these other objects in this list.

This assumes that 'realloc' returns memory aligned on 16-byte boundaries. I don't think that's guaranteed by the standard, at least I could not find it in the C23 one.

I would replace the standard Lua allocator with one that when it creates a uservalue uses the (post-C89) 'aligned_alloc' function or whatever the system provides
to create a properly aligned object. And of course you'd still have to add one of those Intel-specific types to LUAI_MAXALIGN.


--

Roberto Ierusalimschy

unread,
Feb 14, 2026, 5:35:51 PM (6 days ago) Feb 14
to lu...@googlegroups.com
> This assumes that 'realloc' returns memory aligned on 16-byte boundaries. I
> don't think that's guaranteed by the standard, at least I could not find it
> in the C23 one.

The standard says this: "The pointer returned if the allocation succeeds
is suitably aligned so that it may be assigned to a pointer to any
type of object and then used to access such an object or an array of
such objects in the space allocated".

So, if your system has objects that need 16-bit alignment, malloc must
respect that.

-- Roberto

Andre Leiradella

unread,
Feb 15, 2026, 7:08:49 AM (5 days ago) Feb 15
to lua-l
Em sábado, 14 de fevereiro de 2026 às 19:34:10 UTC, Spar escreveu:
You can also look at std::align or how sol2 manages this: https://github.com/ThePhD/sol2/blob/develop/include/sol/stack_core.hpp#L129

Thanks, I'll keep it simple for now.

Andre 

Andre Leiradella

unread,
Feb 15, 2026, 7:11:13 AM (5 days ago) Feb 15
to lua-l
Em sábado, 14 de fevereiro de 2026 às 21:44:26 UTC, Gé Weijers escreveu:
I would replace the standard Lua allocator with one that when it creates a uservalue uses the (post-C89) 'aligned_alloc' function or whatever the system provides
to create a properly aligned object. And of course you'd still have to add one of those Intel-specific types to LUAI_MAXALIGN.

Good idea, but I don't want to build Lua myself.

Andre 

bil til

unread,
Feb 16, 2026, 2:40:17 AM (4 days ago) Feb 16
to lu...@googlegroups.com
... it depends on your security ambitions... .

Keeping memory allocation in close view is typically a good idea for
every medium sized software project.

(building Lua by yourself would be a super-HUGE software project :) ).

Sewbacca

unread,
Feb 16, 2026, 3:28:01 AM (4 days ago) Feb 16
to lu...@googlegroups.com
I think what they meant is you can pass a custom allocator function in lua_newstate() instead of the default one provided by luaL_newstate()

If Lua does some arena magic behind the scenes this statement is rendered invalid though.

Cheers
~ Sewbacca

15.02.2026 13:11:18 Andre Leiradella <an...@leiradella.com>:

Sainan

unread,
Feb 16, 2026, 3:34:48 AM (4 days ago) Feb 16
to lu...@googlegroups.com
> If Lua does some arena magic behind the scenes

It doesn't.

-- Sainan

Andre Leiradella

unread,
Feb 16, 2026, 6:28:54 AM (4 days ago) Feb 16
to lua-l
Em segunda-feira, 16 de fevereiro de 2026 às 08:28:01 UTC, Sewbacca escreveu:
I think what they meant is you can pass a custom allocator function in lua_newstate() instead of the default one provided by luaL_newstate()
I don't think that will guarantee 16-bit alignment for the userdata, since the userdata has a header that might cause the actual space for the userdata to fall into an 8-bytes boundary. 

Roberto Ierusalimschy

unread,
Feb 17, 2026, 12:54:21 PM (3 days ago) Feb 17
to lu...@googlegroups.com
>
> I think what they meant is you can pass a custom allocator function in
> lua_newstate() instead of the default one provided by luaL_newstate()
>
> I don't think that will guarantee 16-bit alignment for the userdata, since
> the userdata has a header that might cause the actual space for the
> userdata to fall into an 8-bytes boundary.

That is the whole point of LUAI_MAXALIGN: Lua ensures that all types in
that macro are properly aligned inside a userdata, after the header.
Lua uses the macro to ensure the header behaves correctly.

-- Roberto
Reply all
Reply to author
Forward
0 new messages