Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite7a4561

Browse files
committed
Fix core dump in ReorderBufferRestoreChange on alignment-picky platforms.
When re-reading an update involving both an old tuple and a new tuple fromdisk, reorderbuffer.c was careless about whether the new tuple is suitablyaligned for direct access --- in general, it isn't. We'd missed seeingthis in the buildfarm because the contrib/test_decoding tests exercise thiscode path only a few times, and by chance all of those cases have oldtuples with length a multiple of 4, which is usually enough to make theaccess to the new tuple's t_len safe. For some still-not-entirely-clearreason, however, Debian's sparc build gets a bus error, as reported byChristoph Berg; perhaps it's assuming 8-byte alignment of the pointer?The lack of previous field reports is probably because you need all ofthese conditions to trigger a crash: an alignment-picky platform (notIntel), a transaction large enough to spill to disk, an update withinthat 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_lendirectly, 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>
1 parentce47112 commite7a4561

File tree

3 files changed

+28
-9
lines changed

3 files changed

+28
-9
lines changed

‎contrib/test_decoding/expected/ddl.out

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,23 +227,28 @@ CREATE TABLE tr_etoomuch (id serial primary key, data int);
227227
INSERT INTO tr_etoomuch(data) SELECT g.i FROM generate_series(1, 10234) g(i);
228228
DELETE FROM tr_etoomuch WHERE id < 5000;
229229
UPDATE tr_etoomuch SET data = - data WHERE id > 5000;
230+
CREATE TABLE tr_oddlength (id text primary key, data text);
231+
INSERT INTO tr_oddlength VALUES('ab', 'foo');
230232
COMMIT;
231233
/* display results, but hide most of the output */
232234
SELECT count(*), min(data), max(data)
233235
FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')
234236
GROUP BY substring(data, 1, 24)
235237
ORDER BY 1,2;
236-
count | min | max
237-
-------+-------------------------------------------------+------------------------------------------------------------------------
238-
1 | BEGIN | BEGIN
239-
1 | COMMIT | COMMIT
240-
20467 | table public.tr_etoomuch: DELETE: id[integer]:1 | table public.tr_etoomuch: UPDATE: id[integer]:9999 data[integer]:-9999
241-
(3 rows)
238+
count | min | max
239+
-------+-------------------------------------------------------------------+------------------------------------------------------------------------
240+
1 | BEGIN | BEGIN
241+
1 | COMMIT | COMMIT
242+
1 | table public.tr_oddlength: INSERT: id[text]:'ab' data[text]:'foo' | table public.tr_oddlength: INSERT: id[text]:'ab' data[text]:'foo'
243+
20467 | table public.tr_etoomuch: DELETE: id[integer]:1 | table public.tr_etoomuch: UPDATE: id[integer]:9999 data[integer]:-9999
244+
(4 rows)
242245

243246
-- check updates of primary keys work correctly
244247
BEGIN;
245248
CREATE TABLE spoolme AS SELECT g.i FROM generate_series(1, 5000) g(i);
246249
UPDATE tr_etoomuch SET id = -id WHERE id = 5000;
250+
UPDATE tr_oddlength SET id = 'x', data = 'quux';
251+
UPDATE tr_oddlength SET id = 'yy', data = 'a';
247252
DELETE FROM spoolme;
248253
DROP TABLE spoolme;
249254
COMMIT;
@@ -253,7 +258,9 @@ WHERE data ~ 'UPDATE';
253258
data
254259
-------------------------------------------------------------------------------------------------------------
255260
table public.tr_etoomuch: UPDATE: old-key: id[integer]:5000 new-tuple: id[integer]:-5000 data[integer]:5000
256-
(1 row)
261+
table public.tr_oddlength: UPDATE: old-key: id[text]:'ab' new-tuple: id[text]:'x' data[text]:'quux'
262+
table public.tr_oddlength: UPDATE: old-key: id[text]:'x' new-tuple: id[text]:'yy' data[text]:'a'
263+
(3 rows)
257264

258265
-- check that a large, spooled, upsert works
259266
INSERT INTO tr_etoomuch (id, data)

‎contrib/test_decoding/sql/ddl.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ CREATE TABLE tr_etoomuch (id serial primary key, data int);
115115
INSERT INTO tr_etoomuch(data)SELECTg.iFROM generate_series(1,10234) g(i);
116116
DELETEFROM tr_etoomuchWHERE id<5000;
117117
UPDATE tr_etoomuchSET data=- dataWHERE id>5000;
118+
CREATETABLEtr_oddlength (idtextprimary key, datatext);
119+
INSERT INTO tr_oddlengthVALUES('ab','foo');
118120
COMMIT;
119121

120122
/* display results, but hide most of the output*/
@@ -127,6 +129,8 @@ ORDER BY 1,2;
127129
BEGIN;
128130
CREATETABLEspoolmeASSELECTg.iFROM generate_series(1,5000) g(i);
129131
UPDATE tr_etoomuchSET id=-idWHERE id=5000;
132+
UPDATE tr_oddlengthSET id='x', data='quux';
133+
UPDATE tr_oddlengthSET id='yy', data='a';
130134
DELETEFROM spoolme;
131135
DROPTABLE spoolme;
132136
COMMIT;

‎src/backend/replication/logical/reorderbuffer.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,6 +2347,10 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
23472347
/*
23482348
* Convert change from its on-disk format to in-memory format and queue it onto
23492349
* the TXN's ->changes list.
2350+
*
2351+
* Note: although "data" is declared char*, at entry it points to a
2352+
* maxalign'd buffer, making it safe in most of this function to assume
2353+
* that the pointed-to data is suitably aligned for direct access.
23502354
*/
23512355
staticvoid
23522356
ReorderBufferRestoreChange(ReorderBuffer*rb,ReorderBufferTXN*txn,
@@ -2374,7 +2378,7 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
23742378
caseREORDER_BUFFER_CHANGE_INTERNAL_SPEC_INSERT:
23752379
if (change->data.tp.oldtuple)
23762380
{
2377-
Sizetuplelen= ((HeapTuple)data)->t_len;
2381+
uint32tuplelen= ((HeapTuple)data)->t_len;
23782382

23792383
change->data.tp.oldtuple=
23802384
ReorderBufferGetTupleBuf(rb,tuplelen-SizeofHeapTupleHeader);
@@ -2395,7 +2399,11 @@ ReorderBufferRestoreChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
23952399

23962400
if (change->data.tp.newtuple)
23972401
{
2398-
Sizetuplelen= ((HeapTuple)data)->t_len;
2402+
/* here, data might not be suitably aligned! */
2403+
uint32tuplelen;
2404+
2405+
memcpy(&tuplelen,data+ offsetof(HeapTupleData,t_len),
2406+
sizeof(uint32));
23992407

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

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp