Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8269804

Browse files
committed
Avoid using potentially-under-aligned page buffers.
There's a project policy against using plain "char buf[BLCKSZ]" local or static variables as page buffers; preferred style is to palloc or malloc each buffer to ensure it is MAXALIGN'd. However, that policy's been ignored in an increasing number of places. We've apparently got away with it so far, probably because (a) relatively few people use platforms on which misalignment causes core dumps and/or (b) the variables chance to be sufficiently aligned anyway. But this is not something to rely on. Moreover, even if we don't get a core dump, we might be paying a lot of cycles for misaligned accesses. To fix, invent new union types PGAlignedBlock and PGAlignedXLogBlock that the compiler must allocate with sufficient alignment, and use those in place of plain char arrays. I used these types even for variables where there's no risk of a misaligned access, since ensuring proper alignment should make kernel data transfers faster. I also changed some places where we had been palloc'ing short-lived buffers, for coding style uniformity and to save palloc/pfree overhead. Since this seems to be a live portability hazard (despite the lack of field reports), back-patch to all supported versions. Patch by me; thanks to Michael Paquier for review. Discussion: https://postgr.es/m/1535618100.1286.3.camel@credativ.de
1 parent 081e410 commit 8269804

File tree

20 files changed

+116
-139
lines changed

20 files changed

+116
-139
lines changed

contrib/bloom/blinsert.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ typedef struct
3636
int64 indtuples; /* total number of tuples indexed */
3737
MemoryContext tmpCtx; /* temporary memory context reset after each
3838
* tuple */
39-
char data[BLCKSZ]; /* cached page */
39+
PGAlignedBlock data; /* cached page */
4040
int count; /* number of tuples in cached page */
4141
} BloomBuildState;
4242

@@ -52,7 +52,7 @@ flushCachedPage(Relation index, BloomBuildState *buildstate)
5252

5353
state = GenericXLogStart(index);
5454
page = GenericXLogRegisterBuffer(state, buffer, GENERIC_XLOG_FULL_IMAGE);
55-
memcpy(page, buildstate->data, BLCKSZ);
55+
memcpy(page, buildstate->data.data, BLCKSZ);
5656
GenericXLogFinish(state);
5757
UnlockReleaseBuffer(buffer);
5858
}
@@ -63,8 +63,8 @@ flushCachedPage(Relation index, BloomBuildState *buildstate)
6363
static void
6464
initCachedPage(BloomBuildState *buildstate)
6565
{
66-
memset(buildstate->data, 0, BLCKSZ);
67-
BloomInitPage(buildstate->data, 0);
66+
memset(buildstate->data.data, 0, BLCKSZ);
67+
BloomInitPage(buildstate->data.data, 0);
6868
buildstate->count = 0;
6969
}
7070

@@ -84,7 +84,7 @@ bloomBuildCallback(Relation index, HeapTuple htup, Datum *values,
8484
itup = BloomFormTuple(&buildstate->blstate, &htup->t_self, values, isnull);
8585

8686
/* Try to add next item to cached page */
87-
if (BloomPageAddItem(&buildstate->blstate, buildstate->data, itup))
87+
if (BloomPageAddItem(&buildstate->blstate, buildstate->data.data, itup))
8888
{
8989
/* Next item was added successfully */
9090
buildstate->count++;
@@ -98,7 +98,7 @@ bloomBuildCallback(Relation index, HeapTuple htup, Datum *values,
9898

9999
initCachedPage(buildstate);
100100

101-
if (!BloomPageAddItem(&buildstate->blstate, buildstate->data, itup))
101+
if (!BloomPageAddItem(&buildstate->blstate, buildstate->data.data, itup))
102102
{
103103
/* We shouldn't be here since we're inserting to the empty page */
104104
elog(ERROR, "could not add new bloom tuple to empty page");

contrib/pg_prewarm/pg_prewarm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ typedef enum
3737
PREWARM_BUFFER
3838
} PrewarmType;
3939

40-
static char blockbuffer[BLCKSZ];
40+
static PGAlignedBlock blockbuffer;
4141

4242
/*
4343
* pg_prewarm(regclass, mode text, fork text,
@@ -179,7 +179,7 @@ pg_prewarm(PG_FUNCTION_ARGS)
179179
for (block = first_block; block <= last_block; ++block)
180180
{
181181
CHECK_FOR_INTERRUPTS();
182-
smgrread(rel->rd_smgr, forkNumber, block, blockbuffer);
182+
smgrread(rel->rd_smgr, forkNumber, block, blockbuffer.data);
183183
++blocks_done;
184184
}
185185
}

src/backend/access/gin/ginentrypage.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -615,7 +615,7 @@ entrySplitPage(GinBtree btree, Buffer origbuf,
615615
Page lpage = PageGetTempPageCopy(BufferGetPage(origbuf));
616616
Page rpage = PageGetTempPageCopy(BufferGetPage(origbuf));
617617
Size pageSize = PageGetPageSize(lpage);
618-
char tupstore[2 * BLCKSZ];
618+
PGAlignedBlock tupstore[2]; /* could need 2 pages' worth of tuples */
619619

620620
entryPreparePage(btree, lpage, off, insertData, updateblkno);
621621

@@ -624,7 +624,7 @@ entrySplitPage(GinBtree btree, Buffer origbuf,
624624
* one after another in a temporary workspace.
625625
*/
626626
maxoff = PageGetMaxOffsetNumber(lpage);
627-
ptr = tupstore;
627+
ptr = tupstore[0].data;
628628
for (i = FirstOffsetNumber; i <= maxoff; i++)
629629
{
630630
if (i == off)
@@ -657,7 +657,7 @@ entrySplitPage(GinBtree btree, Buffer origbuf,
657657
GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
658658
GinInitPage(lpage, GinPageGetOpaque(rpage)->flags, pageSize);
659659

660-
ptr = tupstore;
660+
ptr = tupstore[0].data;
661661
maxoff++;
662662
lsize = 0;
663663

src/backend/access/gin/ginfast.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,15 @@ writeListPage(Relation index, Buffer buffer,
6161
size = 0;
6262
OffsetNumber l,
6363
off;
64-
char *workspace;
64+
PGAlignedBlock workspace;
6565
char *ptr;
6666

67-
/* workspace could be a local array; we use palloc for alignment */
68-
workspace = palloc(BLCKSZ);
69-
7067
START_CRIT_SECTION();
7168

7269
GinInitBuffer(buffer, GIN_LIST);
7370

7471
off = FirstOffsetNumber;
75-
ptr = workspace;
72+
ptr = workspace.data;
7673

7774
for (i = 0; i < ntuples; i++)
7875
{
@@ -124,7 +121,7 @@ writeListPage(Relation index, Buffer buffer,
124121
XLogRegisterData((char *) &data, sizeof(ginxlogInsertListPage));
125122

126123
XLogRegisterBuffer(0, buffer, REGBUF_WILL_INIT);
127-
XLogRegisterBufData(0, workspace, size);
124+
XLogRegisterBufData(0, workspace.data, size);
128125

129126
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT_LISTPAGE);
130127
PageSetLSN(page, recptr);
@@ -137,8 +134,6 @@ writeListPage(Relation index, Buffer buffer,
137134

138135
END_CRIT_SECTION();
139136

140-
pfree(workspace);
141-
142137
return freesize;
143138
}
144139

src/backend/access/hash/hashpage.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,7 @@ static bool
710710
_hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
711711
{
712712
BlockNumber lastblock;
713-
char zerobuf[BLCKSZ];
713+
PGAlignedBlock zerobuf;
714714

715715
lastblock = firstblock + nblocks - 1;
716716

@@ -721,10 +721,10 @@ _hash_alloc_buckets(Relation rel, BlockNumber firstblock, uint32 nblocks)
721721
if (lastblock < firstblock || lastblock == InvalidBlockNumber)
722722
return false;
723723

724-
MemSet(zerobuf, 0, sizeof(zerobuf));
724+
MemSet(zerobuf.data, 0, sizeof(zerobuf));
725725

726726
RelationOpenSmgr(rel);
727-
smgrextend(rel->rd_smgr, MAIN_FORKNUM, lastblock, zerobuf, false);
727+
smgrextend(rel->rd_smgr, MAIN_FORKNUM, lastblock, zerobuf.data, false);
728728

729729
return true;
730730
}

src/backend/access/heap/heapam.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2637,7 +2637,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
26372637
HeapTuple *heaptuples;
26382638
int i;
26392639
int ndone;
2640-
char *scratch = NULL;
2640+
PGAlignedBlock scratch;
26412641
Page page;
26422642
bool needwal;
26432643
Size saveFreeSpace;
@@ -2654,14 +2654,6 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
26542654
heaptuples[i] = heap_prepare_insert(relation, tuples[i],
26552655
xid, cid, options);
26562656

2657-
/*
2658-
* Allocate some memory to use for constructing the WAL record. Using
2659-
* palloc() within a critical section is not safe, so we allocate this
2660-
* beforehand.
2661-
*/
2662-
if (needwal)
2663-
scratch = palloc(BLCKSZ);
2664-
26652657
/*
26662658
* We're about to do the actual inserts -- but check for conflict first,
26672659
* to minimize the possibility of having to roll back work we've just
@@ -2754,7 +2746,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
27542746
uint8 info = XLOG_HEAP2_MULTI_INSERT;
27552747
char *tupledata;
27562748
int totaldatalen;
2757-
char *scratchptr = scratch;
2749+
char *scratchptr = scratch.data;
27582750
bool init;
27592751
int bufflags = 0;
27602752

@@ -2813,7 +2805,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
28132805
scratchptr += datalen;
28142806
}
28152807
totaldatalen = scratchptr - tupledata;
2816-
Assert((scratchptr - scratch) < BLCKSZ);
2808+
Assert((scratchptr - scratch.data) < BLCKSZ);
28172809

28182810
if (need_tuple_data)
28192811
xlrec->flags |= XLH_INSERT_CONTAINS_NEW_TUPLE;
@@ -2840,7 +2832,7 @@ heap_multi_insert(Relation relation, HeapTuple *tuples, int ntuples,
28402832
bufflags |= REGBUF_KEEP_DATA;
28412833

28422834
XLogBeginInsert();
2843-
XLogRegisterData((char *) xlrec, tupledata - scratch);
2835+
XLogRegisterData((char *) xlrec, tupledata - scratch.data);
28442836
XLogRegisterBuffer(0, buffer, REGBUF_STANDARD | bufflags);
28452837

28462838
XLogRegisterBufData(0, tupledata, totaldatalen);

src/backend/access/heap/visibilitymap.c

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -645,10 +645,9 @@ static void
645645
vm_extend(Relation rel, BlockNumber vm_nblocks)
646646
{
647647
BlockNumber vm_nblocks_now;
648-
Page pg;
648+
PGAlignedBlock pg;
649649

650-
pg = (Page) palloc(BLCKSZ);
651-
PageInit(pg, BLCKSZ, 0);
650+
PageInit((Page) pg.data, BLCKSZ, 0);
652651

653652
/*
654653
* We use the relation extension lock to lock out other backends trying to
@@ -679,10 +678,10 @@ vm_extend(Relation rel, BlockNumber vm_nblocks)
679678
/* Now extend the file */
680679
while (vm_nblocks_now < vm_nblocks)
681680
{
682-
PageSetChecksumInplace(pg, vm_nblocks_now);
681+
PageSetChecksumInplace((Page) pg.data, vm_nblocks_now);
683682

684683
smgrextend(rel->rd_smgr, VISIBILITYMAP_FORKNUM, vm_nblocks_now,
685-
(char *) pg, false);
684+
pg.data, false);
686685
vm_nblocks_now++;
687686
}
688687

@@ -699,6 +698,4 @@ vm_extend(Relation rel, BlockNumber vm_nblocks)
699698
rel->rd_smgr->smgr_vm_nblocks = vm_nblocks_now;
700699

701700
UnlockRelationForExtension(rel, ExclusiveLock);
702-
703-
pfree(pg);
704701
}

src/backend/access/transam/generic_xlog.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,11 @@ typedef struct
6060
/* State of generic xlog record construction */
6161
struct GenericXLogState
6262
{
63-
/*
64-
* page's images. Should be first in this struct to have MAXALIGN'ed
65-
* images addresses, because some code working with pages directly aligns
66-
* addresses, not offsets from beginning of page
67-
*/
68-
char images[MAX_GENERIC_XLOG_PAGES * BLCKSZ];
63+
/* Info about each page, see above */
6964
PageData pages[MAX_GENERIC_XLOG_PAGES];
7065
bool isLogged;
66+
/* Page images (properly aligned) */
67+
PGAlignedBlock images[MAX_GENERIC_XLOG_PAGES];
7168
};
7269

7370
static void writeFragment(PageData *pageData, OffsetNumber offset,
@@ -250,12 +247,12 @@ computeDelta(PageData *pageData, Page curpage, Page targetpage)
250247
#ifdef WAL_DEBUG
251248
if (XLOG_DEBUG)
252249
{
253-
char tmp[BLCKSZ];
250+
PGAlignedBlock tmp;
254251

255-
memcpy(tmp, curpage, BLCKSZ);
256-
applyPageRedo(tmp, pageData->delta, pageData->deltaLen);
257-
if (memcmp(tmp, targetpage, targetLower) != 0 ||
258-
memcmp(tmp + targetUpper, targetpage + targetUpper,
252+
memcpy(tmp.data, curpage, BLCKSZ);
253+
applyPageRedo(tmp.data, pageData->delta, pageData->deltaLen);
254+
if (memcmp(tmp.data, targetpage, targetLower) != 0 ||
255+
memcmp(tmp.data + targetUpper, targetpage + targetUpper,
259256
BLCKSZ - targetUpper) != 0)
260257
elog(ERROR, "result of generic xlog apply does not match");
261258
}
@@ -276,7 +273,7 @@ GenericXLogStart(Relation relation)
276273

277274
for (i = 0; i < MAX_GENERIC_XLOG_PAGES; i++)
278275
{
279-
state->pages[i].image = state->images + BLCKSZ * i;
276+
state->pages[i].image = state->images[i].data;
280277
state->pages[i].buffer = InvalidBuffer;
281278
}
282279

src/backend/access/transam/xlog.c

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3029,8 +3029,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
30293029
{
30303030
char path[MAXPGPATH];
30313031
char tmppath[MAXPGPATH];
3032-
char zbuffer_raw[XLOG_BLCKSZ + MAXIMUM_ALIGNOF];
3033-
char *zbuffer;
3032+
PGAlignedXLogBlock zbuffer;
30343033
XLogSegNo installed_segno;
30353034
XLogSegNo max_segno;
30363035
int fd;
@@ -3084,16 +3083,12 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
30843083
* fsync below) that all the indirect blocks are down on disk. Therefore,
30853084
* fdatasync(2) or O_DSYNC will be sufficient to sync future writes to the
30863085
* log file.
3087-
*
3088-
* Note: ensure the buffer is reasonably well-aligned; this may save a few
3089-
* cycles transferring data to the kernel.
30903086
*/
3091-
zbuffer = (char *) MAXALIGN(zbuffer_raw);
3092-
memset(zbuffer, 0, XLOG_BLCKSZ);
3087+
memset(zbuffer.data, 0, XLOG_BLCKSZ);
30933088
for (nbytes = 0; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
30943089
{
30953090
errno = 0;
3096-
if ((int) write(fd, zbuffer, XLOG_BLCKSZ) != (int) XLOG_BLCKSZ)
3091+
if ((int) write(fd, zbuffer.data, XLOG_BLCKSZ) != (int) XLOG_BLCKSZ)
30973092
{
30983093
int save_errno = errno;
30993094

@@ -3198,7 +3193,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
31983193
{
31993194
char path[MAXPGPATH];
32003195
char tmppath[MAXPGPATH];
3201-
char buffer[XLOG_BLCKSZ];
3196+
PGAlignedXLogBlock buffer;
32023197
int srcfd;
32033198
int fd;
32043199
int nbytes;
@@ -3242,14 +3237,14 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
32423237
* zeros.
32433238
*/
32443239
if (nread < sizeof(buffer))
3245-
memset(buffer, 0, sizeof(buffer));
3240+
memset(buffer.data, 0, sizeof(buffer));
32463241

32473242
if (nread > 0)
32483243
{
32493244
if (nread > sizeof(buffer))
32503245
nread = sizeof(buffer);
32513246
errno = 0;
3252-
if (read(srcfd, buffer, nread) != nread)
3247+
if (read(srcfd, buffer.data, nread) != nread)
32533248
{
32543249
if (errno != 0)
32553250
ereport(ERROR,
@@ -3263,7 +3258,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
32633258
}
32643259
}
32653260
errno = 0;
3266-
if ((int) write(fd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
3261+
if ((int) write(fd, buffer.data, sizeof(buffer)) != (int) sizeof(buffer))
32673262
{
32683263
int save_errno = errno;
32693264

src/backend/access/transam/xloginsert.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -774,12 +774,12 @@ XLogCompressBackupBlock(char *page, uint16 hole_offset, uint16 hole_length,
774774
int32 len;
775775
int32 extra_bytes = 0;
776776
char *source;
777-
char tmp[BLCKSZ];
777+
PGAlignedBlock tmp;
778778

779779
if (hole_length != 0)
780780
{
781781
/* must skip the hole */
782-
source = tmp;
782+
source = tmp.data;
783783
memcpy(source, page, hole_offset);
784784
memcpy(source + hole_offset,
785785
page + (hole_offset + hole_length),
@@ -882,7 +882,7 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
882882
if (lsn <= RedoRecPtr)
883883
{
884884
int flags;
885-
char copied_buffer[BLCKSZ];
885+
PGAlignedBlock copied_buffer;
886886
char *origdata = (char *) BufferGetBlock(buffer);
887887
RelFileNode rnode;
888888
ForkNumber forkno;
@@ -900,11 +900,11 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
900900
uint16 lower = ((PageHeader) page)->pd_lower;
901901
uint16 upper = ((PageHeader) page)->pd_upper;
902902

903-
memcpy(copied_buffer, origdata, lower);
904-
memcpy(copied_buffer + upper, origdata + upper, BLCKSZ - upper);
903+
memcpy(copied_buffer.data, origdata, lower);
904+
memcpy(copied_buffer.data + upper, origdata + upper, BLCKSZ - upper);
905905
}
906906
else
907-
memcpy(copied_buffer, origdata, BLCKSZ);
907+
memcpy(copied_buffer.data, origdata, BLCKSZ);
908908

909909
XLogBeginInsert();
910910

@@ -913,7 +913,7 @@ XLogSaveBufferForHint(Buffer buffer, bool buffer_std)
913913
flags |= REGBUF_STANDARD;
914914

915915
BufferGetTag(buffer, &rnode, &forkno, &blkno);
916-
XLogRegisterBlock(0, &rnode, forkno, blkno, copied_buffer, flags);
916+
XLogRegisterBlock(0, &rnode, forkno, blkno, copied_buffer.data, flags);
917917

918918
recptr = XLogInsert(RM_XLOG_ID, XLOG_FPI_FOR_HINT);
919919
}

0 commit comments

Comments
 (0)