1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-25 01:02:05 +03:00

Fix core dump in ReorderBufferRestoreChange on alignment-picky platforms.

When re-reading an update involving both an old tuple and a new tuple from
disk, reorderbuffer.c was careless about whether the new tuple is suitably
aligned for direct access --- in general, it isn't.  We'd missed seeing
this in the buildfarm because the contrib/test_decoding tests exercise this
code path only a few times, and by chance all of those cases have old
tuples with length a multiple of 4, which is usually enough to make the
access to the new tuple's t_len safe.  For some still-not-entirely-clear
reason, however, Debian's sparc build gets a bus error, as reported by
Christoph Berg; perhaps it's assuming 8-byte alignment of the pointer?

The lack of previous field reports is probably because you need all of
these conditions to trigger a crash: an alignment-picky platform (not
Intel), a transaction large enough to spill to disk, an update within
that xact that changes a primary-key field and has an odd-length old tuple,
and of course logical decoding tracing the transaction.

Avoid the alignment assumption by using memcpy instead of fetching t_len
directly, and add a test case that exposes the crash on picky platforms.
Back-patch to 9.4 where the bug was introduced.

Discussion: <20160413094117.GC21485@msg.credativ.de>
This commit is contained in:
Tom Lane
2016-04-14 19:42:21 -04:00
parent c2dc194bdb
commit 6a3d3965d6
3 changed files with 23 additions and 4 deletions

View File

@ -2444,6 +2444,10 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
/*
* Convert change from its on-disk format to in-memory format and queue it onto
* the TXN's ->changes list.
*
* Note: although "data" is declared char*, at entry it points to a
* maxalign'd buffer, making it safe in most of this function to assume
* that the pointed-to data is suitably aligned for direct access.
*/
static void
ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
@ -2471,7 +2475,7 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
case REORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
if (change->data.tp.oldtuple)
{
Size tuplelen = ((HeapTuple) data)->t_len;
uint32 tuplelen = ((HeapTuple) data)->t_len;
change->data.tp.oldtuple =
ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);
@ -2492,7 +2496,11 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
if (change->data.tp.newtuple)
{
Size tuplelen = ((HeapTuple) data)->t_len;
/* here, data might not be suitably aligned! */
uint32 tuplelen;
memcpy(&tuplelen, data + offsetof(HeapTupleData, t_len),
sizeof(uint32));
change->data.tp.newtuple =
ReorderBufferGetTupleBuf(rb, tuplelen - SizeofHeapTupleHeader);