Re: Bus error in pg_logical_slot_get_changes (9.4.7, sparc) - Mailing list pgsql-bugs

From Tom Lane
Subject Re: Bus error in pg_logical_slot_get_changes (9.4.7, sparc)
Date
Msg-id 423.1460653903@sss.pgh.pa.us
Whole thread Raw
In response to Re: Bus error in pg_logical_slot_get_changes (9.4.7, sparc)  (Christoph Berg <myon@debian.org>)
Responses Re: Bus error in pg_logical_slot_get_changes (9.4.7, sparc)
Re: Bus error in pg_logical_slot_get_changes (9.4.7, sparc)
List pgsql-bugs
Christoph Berg <myon@debian.org> writes:
>> ... the patch worked indeed, thanks!

> Duh, the patch does work on sparc, but it breaks amd64:

Well, yeah, because if Size is wider than int32 then that memcpy isn't
enough to initialize it.

But looking around a bit, I think that ReorderBufferRestoreChange is
almost completely broken on alignment-picky machines, if the expectation
is that the input data could be aligned arbitrarily.  Aside from this
particular problem, it contains multiple places where we cast "data"
to something other than char*, and that is sufficient to allow a
spec-compliant compiler to decide that "data" is aligned on more than
a char boundary and hence generate code that depends on such alignment.

I also noticed that the INTERNAL_SNAPSHOT case doesn't bother to advance
"data" past the data read, where all the other switch cases do.  In the
attached, I made it do likewise, but it looks like you could equally
easily just drop the final update of "data" in each switch case,
because nothing is looking at it after the switch.

Proposed patch attached, but I'm still wondering why the alignment-picky
buildfarm members aren't all failing on this.  It seems to strongly
suggest that the regression tests' coverage is lacking here.

            regards, tom lane

diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 52c6986..b6f83f8 100644
*** a/src/backend/replication/logical/reorderbuffer.c
--- b/src/backend/replication/logical/reorderbuffer.c
*************** static void
*** 2449,2463 ****
  ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
                             char *data)
  {
-     ReorderBufferDiskChange *ondisk;
      ReorderBufferChange *change;

-     ondisk = (ReorderBufferDiskChange *) data;
-
      change = ReorderBufferGetChange(rb);

      /* copy static part */
!     memcpy(change, &ondisk->change, sizeof(ReorderBufferChange));

      data += sizeof(ReorderBufferDiskChange);

--- 2449,2461 ----
  ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
                             char *data)
  {
      ReorderBufferChange *change;

      change = ReorderBufferGetChange(rb);

      /* copy static part */
!     memcpy(change, data + offsetof(ReorderBufferDiskChange, change),
!            sizeof(ReorderBufferChange));

      data += sizeof(ReorderBufferDiskChange);

*************** ReorderBufferRestoreChange(ReorderBuffer
*** 2471,2477 ****
          case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
              if (change->data.tp.oldtuple)
              {
!                 Size        tuplelen = ((HeapTuple) data)->t_len;

                  change->data.tp.oldtuple =
                      ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
--- 2469,2479 ----
          case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
              if (change->data.tp.oldtuple)
              {
!                 uint32        tuplelen;
!
!                 /* Must get tuplelen the hard way in case it's misaligned */
!                 memcpy(&tuplelen, data + offsetof(HeapTupleData, t_len),
!                        sizeof(uint32));

                  change->data.tp.oldtuple =
                      ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
*************** ReorderBufferRestoreChange(ReorderBuffer
*** 2492,2498 ****

              if (change->data.tp.newtuple)
              {
!                 Size        tuplelen = ((HeapTuple) data)->t_len;

                  change->data.tp.newtuple =
                      ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
--- 2494,2504 ----

              if (change->data.tp.newtuple)
              {
!                 uint32        tuplelen;
!
!                 /* Must get tuplelen the hard way in case it's misaligned */
!                 memcpy(&tuplelen, data + offsetof(HeapTupleData, t_len),
!                        sizeof(uint32));

                  change->data.tp.newtuple =
                      ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
*************** ReorderBufferRestoreChange(ReorderBuffer
*** 2538,2552 ****
              }
          case REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:
              {
!                 Snapshot    oldsnap;
                  Snapshot    newsnap;
                  Size        size;

!                 oldsnap = (Snapshot) data;

                  size = sizeof(SnapshotData) +
!                     sizeof(TransactionId) * oldsnap->xcnt +
!                     sizeof(TransactionId) * (oldsnap->subxcnt + 0);

                  change->data.snapshot = MemoryContextAllocZero(rb->context, size);

--- 2544,2558 ----
              }
          case REORDER_BUFFER_CHANGE_INTERNAL_SNAPSHOT:
              {
!                 SnapshotData oldsnap;
                  Snapshot    newsnap;
                  Size        size;

!                 memcpy(&oldsnap, data, sizeof(SnapshotData));

                  size = sizeof(SnapshotData) +
!                     sizeof(TransactionId) * oldsnap.xcnt +
!                     sizeof(TransactionId) * oldsnap.subxcnt;

                  change->data.snapshot = MemoryContextAllocZero(rb->context, size);

*************** ReorderBufferRestoreChange(ReorderBuffer
*** 2557,2562 ****
--- 2563,2570 ----
                      (((char *) newsnap) + sizeof(SnapshotData));
                  newsnap->subxip = newsnap->xip + newsnap->xcnt;
                  newsnap->copied = true;
+
+                 data += size;
                  break;
              }
              /* the base struct contains all the data, easy peasy */

pgsql-bugs by date:

Previous
From: "Zombade, Prashant"
Date:
Subject: PostgreSQL on Korean Windows Server 2008 R2 Standard
Next
From: Christoph Berg
Date:
Subject: Re: Bus error in pg_logical_slot_get_changes (9.4.7, sparc)