lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

Kay Roepke wrote:
> After several lengthy gdb sessions and barking up entirely wrong trees, it 
> became apparent that 'gkey(mp)' in
>    gkey(mp)->value = key->value; gkey(mp)->tt = key->tt;
> was actually referring to dummynode (static const Node dummynode_ in 
> ltable.c:75) which was improperly aligned.

I think your analysis is incomplete. Please check the control
flow in newkey(). You should never get to the assignment you
quoted, if mp is equal to dummynode!

Which in turn means the equality test for dummynode is failing.
This is the usual symptom, if you've linked two copies of the Lua
core into your application (causing two instances of dummynode to

A common error is to link C extension modules (shared libraries)
with the static library. The linker command line for extension
modules must not ever contain -llua or anything similar!

The Lua core symbols (lua_insert() and so on) are only to be
exported from the executable which contains the Lua core itself.
All C extension modules loaded afterwards can then access these
symbols. Under ELF systems this is what -Wl,-E is for on the
linker line. MACH-O systems don't need this since all non-static
symbols are exported.

I.e. check your build process. If you are unsure where the two
copies of the Lua core come from, grep the binaries for some
characteristic error message, like "table index is nil".

> (Aside: Can someone comment on the issue that mp actually is dummynode at 
> this point? Would that be correct at all? Just so I know next time when I'm 
> in there...)

It's a minimal (and read-only!) node structure which is used in
case a table does not contain any entries in the hash part (yet).
It only contains a single nil key/value pair and no free slots.
So there's always a hash part for every table. This saves some
conditional jumps in several important code paths.

> The "fix" we did was to change the definition of dummynode_ to
>    static volatile dummynode_ = {
> which made the SIGBUS disappear.

This is not the right approach. You are only masking the
symptoms. The static dummynode should never, ever be written to
by the code quoted above!

> Discussing this on #lua, we agreed that this smells like a compiler bug in 
> Apple's gcc and I will report it as a bug with them.

This is a different issue and you may have a point. I'm assuming
the two assignments are translated to an SSE2 instruction which
causes the alignment error (check the generated assembler code of
newkey for a movq or something similar).

This would be incorrect since the maximum alignment of the Node
struct is that of a double. Which is 4 (and not 8!) in both the
SYSV x86 ABI (used by Linux, BSD* and so on) and the (slightly
different) Mac OS X x86 ABI.

This means it's perfectly ok for dummynode to be only 4-byte
aligned. Check the assembler output for the section it's emitted
to and its alignment.

[That is unless you're using -malign-double inconsistently, which
is a really bad idea.]

So the compiler is wrong to assume that Node is always 8-byte
aligned. Maybe there's some overly optimistic optimization which
takes a guess that Node * always points to heap-allocated objects
(which are always 16-byte aligned on OSX).

[Another theory to check: maybe the compiler does assume 8-byte
alignment, but either GCC or the MACH-O linker is moving
dummynode to the BSS (because it's all zero) and erroneously
drops the alignment.]