Thread: Fix misaligned access of ItemPointerData on ARM

Fix misaligned access of ItemPointerData on ARM

From
Piotr Stefaniak
Date:
Hello,

Currently there is only one struct that gets packed (via the
__attribute__ keyword that a few compilers support) and it is packed
only on ARM machines -- in order to force it to be exactly 6 bytes long.

But due to how ExecRowMark struct is laid out in memory, the packed
struct ItemPointerData begins at an uneven offset, leading to misaligned
access whenever BlockIdData is set by ItemPointerSetInvalid() (and
likely in some other places, too).

The attached patch is my attempt at fixing that by adding the aligned
attribute (the struct will remain packed).

Attachment

Re: Fix misaligned access of ItemPointerData on ARM

From
Tom Lane
Date:
Piotr Stefaniak <postgres@piotr-stefaniak.me> writes:
> But due to how ExecRowMark struct is laid out in memory, the packed 
> struct ItemPointerData begins at an uneven offset, leading to misaligned 
> access whenever BlockIdData is set by ItemPointerSetInvalid() (and 
> likely in some other places, too).

But BlockIdData is laid out and accessed as two 16-bit fields, so there
should be no problem.  On what platform exactly do you see a failure?
        regards, tom lane



Re: Fix misaligned access of ItemPointerData on ARM

From
Andres Freund
Date:
On 2015-05-21 15:34:00 -0400, Tom Lane wrote:
> Piotr Stefaniak <postgres@piotr-stefaniak.me> writes:
> > But due to how ExecRowMark struct is laid out in memory, the packed 
> > struct ItemPointerData begins at an uneven offset, leading to misaligned 
> > access whenever BlockIdData is set by ItemPointerSetInvalid() (and 
> > likely in some other places, too).
> 
> But BlockIdData is laid out and accessed as two 16-bit fields, so there
> should be no problem.  On what platform exactly do you see a failure?

It's probably aligned on a byte boundary:

typedef struct ExecRowMark
{Relation    relation;        /* opened and suitably locked relation */Index        rti;            /* its range table
index*/Index        prti;            /* parent range table index, if child */Index        rowmarkId;        /* unique
identifierfor resjunk columns */RowMarkType markType;        /* see enum in nodes/plannodes.h */bool        noWait;
      /* NOWAIT option */ItemPointerData curCtid;    /* ctid of currently locked tuple, if any */
 
} ExecRowMark;

due to the packedness curCtid will quite possibly be stored without any
padding after after noWait.



Re: Fix misaligned access of ItemPointerData on ARM

From
Tom Lane
Date:
I wrote:
> But BlockIdData is laid out and accessed as two 16-bit fields, so there
> should be no problem.  On what platform exactly do you see a failure?

Ah, after reading the gcc manual a bit more closely, I get the point.
For some reason I think we assumed that "packed" would not result in
misaligning the struct overall, but it clearly could do so, with possible
efficiency consequences on hardware that doesn't like misaligned accesses.

If the compiler accepts __attribute__((aligned)) then what you've done is
clearly better.  It's not clear to me whether all compilers that accept
"packed" also accept "aligned", but there are enough ARM machines in the
buildfarm that we could hope that we'll find out if this isn't portable.

I wonder whether we should drop the ARM assumption and instead write

#if defined(pg_attribute_packed) && defined(pg_attribute_aligned)
pg_attribute_packed()
pg_attribute_aligned(2)
#endif

so that the annotations are applied on every compiler that accepts them.
        regards, tom lane



Re: Fix misaligned access of ItemPointerData on ARM

From
Andrew Dunstan
Date:
On 05/21/2015 04:08 PM, Tom Lane wrote:
> I wrote:
>> But BlockIdData is laid out and accessed as two 16-bit fields, so there
>> should be no problem.  On what platform exactly do you see a failure?
> Ah, after reading the gcc manual a bit more closely, I get the point.
> For some reason I think we assumed that "packed" would not result in
> misaligning the struct overall, but it clearly could do so, with possible
> efficiency consequences on hardware that doesn't like misaligned accesses.
>
> If the compiler accepts __attribute__((aligned)) then what you've done is
> clearly better.  It's not clear to me whether all compilers that accept
> "packed" also accept "aligned", but there are enough ARM machines in the
> buildfarm that we could hope that we'll find out if this isn't portable.
>
> I wonder whether we should drop the ARM assumption and instead write
>
> #if defined(pg_attribute_packed) && defined(pg_attribute_aligned)
> pg_attribute_packed()
> pg_attribute_aligned(2)
> #endif
>
> so that the annotations are applied on every compiler that accepts them.
>
>             


Sounds reasonable.

cheers

andrew




Re: Fix misaligned access of ItemPointerData on ARM

From
Tom Lane
Date:
Andrew Dunstan <andrew@dunslane.net> writes:
> On 05/21/2015 04:08 PM, Tom Lane wrote:
>> I wonder whether we should drop the ARM assumption and instead write
>> 
>> #if defined(pg_attribute_packed) && defined(pg_attribute_aligned)
>> pg_attribute_packed()
>> pg_attribute_aligned(2)
>> #endif
>> 
>> so that the annotations are applied on every compiler that accepts them.

> Sounds reasonable.

We can try it and see if the buildfarm blows up, at least.

I considered also adding a Static_assert about sizeof(ItemIdData),
but I'm afraid that compilers that don't support these pragmas
probably don't support Static_assert either, so it's not clear
that that would catch anything.
        regards, tom lane



Re: Fix misaligned access of ItemPointerData on ARM

From
Andres Freund
Date:
On 2015-05-21 16:49:27 -0400, Tom Lane wrote:
> I considered also adding a Static_assert about sizeof(ItemIdData),
> but I'm afraid that compilers that don't support these pragmas
> probably don't support Static_assert either, so it's not clear
> that that would catch anything.

I think your fallback for static assert should pretty much always work?
With an ugly message, but work nonetheless?

Andres



Re: Fix misaligned access of ItemPointerData on ARM

From
Piotr Stefaniak
Date:
On 05/21/2015 10:08 PM, Tom Lane wrote:
> It's not clear to me whether all compilers that accept "packed" also
> accept "aligned", but there are enough ARM machines in the buildfarm
> that we could hope that we'll find out if this isn't portable.

I think src/include/c.h:614 onward, in its current state, guarantees that?

/* GCC, Sunpro and XLC support aligned, packed and noreturn */
#if defined(__GNUC__) || defined(__SUNPRO_C) || defined(__IBMC__)
#define pg_attribute_aligned(a) __attribute__((aligned(a)))
#define pg_attribute_noreturn() __attribute__((noreturn))
#define pg_attribute_packed() __attribute__((packed))
#define HAVE_PG_ATTRIBUTE_NORETURN 1
#else



Re: Fix misaligned access of ItemPointerData on ARM

From
Tom Lane
Date:
Piotr Stefaniak <postgres@piotr-stefaniak.me> writes:
> On 05/21/2015 10:08 PM, Tom Lane wrote:
>> It's not clear to me whether all compilers that accept "packed" also
>> accept "aligned", but there are enough ARM machines in the buildfarm
>> that we could hope that we'll find out if this isn't portable.

> I think src/include/c.h:614 onward, in its current state, guarantees that?

Well, c.h *assumes* that.  One of the things I have in mind is that
this should help us find out whether that assumption is valid.
        regards, tom lane



Re: Fix misaligned access of ItemPointerData on ARM

From
Tom Lane
Date:
Andres Freund <andres@anarazel.de> writes:
> On 2015-05-21 16:49:27 -0400, Tom Lane wrote:
>> I considered also adding a Static_assert about sizeof(ItemIdData),
>> but I'm afraid that compilers that don't support these pragmas
>> probably don't support Static_assert either, so it's not clear
>> that that would catch anything.

> I think your fallback for static assert should pretty much always work?
> With an ugly message, but work nonetheless?

Good point.  Committed with a static assertion.  We shall now retire
to a safe distance and watch the buildfarm.
        regards, tom lane