]> granicus.if.org Git - postgresql/commitdiff
Fix shm_toc.c to always return buffer-aligned memory.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 16 Aug 2017 18:52:38 +0000 (21:52 +0300)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 16 Aug 2017 18:52:38 +0000 (21:52 +0300)
Previously, if you passed a non-aligned size to shm_toc_create(), the
memory returned by shm_toc_allocate() would be similarly non-aligned.
This was exposed by commit 3cda10f41b, which allocated structs containing
a pg_atomic_uint64 field with shm_toc_allocate(). On systems with
MAXIMUM_ALIGNOF = 4, such structs still need to be 8-bytes aligned, but
the memory returned by shm_toc_allocate() was only 4-bytes aligned.

It's quite bogus that we abuse BUFFERALIGN to align the structs for
pg_atomic_uint64. It doesn't really have anything to do with buffers. But
that's a separate issue.

This ought to fix the buildfarm failures on 32-bit x86 systems.

Discussion: https://www.postgresql.org/message-id/7e0a73a5-0df9-1859-b8ae-9acf122dc38d@iki.fi

src/backend/storage/ipc/shm_toc.c
src/include/c.h

index 9f259441f01a2f0b9b7688fe2775936bfefb20e7..958397884de6db009a812db3fd1c85cffaa07ca1 100644 (file)
@@ -44,7 +44,12 @@ shm_toc_create(uint64 magic, void *address, Size nbytes)
        Assert(nbytes > offsetof(shm_toc, toc_entry));
        toc->toc_magic = magic;
        SpinLockInit(&toc->toc_mutex);
-       toc->toc_total_bytes = nbytes;
+
+       /*
+        * The alignment code in shm_toc_allocate() assumes that the starting
+        * value is buffer-aligned.
+        */
+       toc->toc_total_bytes = BUFFERALIGN_DOWN(nbytes);
        toc->toc_allocated_bytes = 0;
        toc->toc_nentry = 0;
 
@@ -88,7 +93,12 @@ shm_toc_allocate(shm_toc *toc, Size nbytes)
        Size            nentry;
        Size            toc_bytes;
 
-       /* Make sure request is well-aligned. */
+       /*
+        * Make sure request is well-aligned.  XXX: MAXALIGN is not enough,
+        * because atomic ops might need a wider alignment.  We don't have a
+        * proper definition for the minimum to make atomic ops safe, but
+        * BUFFERALIGN ought to be enough.
+        */
        nbytes = BUFFERALIGN(nbytes);
 
        SpinLockAcquire(&toc->toc_mutex);
@@ -252,7 +262,11 @@ shm_toc_lookup(shm_toc *toc, uint64 key, bool noError)
 Size
 shm_toc_estimate(shm_toc_estimator *e)
 {
-       return add_size(offsetof(shm_toc, toc_entry),
-                                       add_size(mul_size(e->number_of_keys, sizeof(shm_toc_entry)),
-                                                        e->space_for_chunks));
+       Size            sz;
+
+       sz = offsetof(shm_toc, toc_entry);
+       sz += add_size(sz, mul_size(e->number_of_keys, sizeof(shm_toc_entry)));
+       sz += add_size(sz, e->space_for_chunks);
+
+       return BUFFERALIGN(sz);
 }
index 9066e3c57835f97f8a0ee6cf1cf4bd8102979fcb..af799dc1dfb3f849f18aa7c43c7120d12fc73001 100644 (file)
@@ -598,6 +598,7 @@ typedef NameData *Name;
 #define LONGALIGN_DOWN(LEN)            TYPEALIGN_DOWN(ALIGNOF_LONG, (LEN))
 #define DOUBLEALIGN_DOWN(LEN)  TYPEALIGN_DOWN(ALIGNOF_DOUBLE, (LEN))
 #define MAXALIGN_DOWN(LEN)             TYPEALIGN_DOWN(MAXIMUM_ALIGNOF, (LEN))
+#define BUFFERALIGN_DOWN(LEN)  TYPEALIGN_DOWN(ALIGNOF_BUFFER, (LEN))
 
 /*
  * The above macros will not work with types wider than uintptr_t, like with