On Tue, 3 Jan 2023 at 10:25, Tom Lane <t...@sss.pgh.pa.us> wrote:
> The thing that I find really distressing here is that it's been
> like this for years and none of our automated testing caught it.
> You'd have expected valgrind testing to do so ... but it does not,
> because we've never marked that word NOACCESS.  Maybe we should
> rethink that?  It'd require making mcxt.c do some valgrind flag
> manipulations so it could access the hdrmask when appropriate.

Yeah, that probably could have been improved during the recent change.
Here's a patch for it.

I'm just doing a final Valgrind run on it now to check for errors.

David
diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c
index ef10bb1690..30151d57d6 100644
--- a/src/backend/utils/mmgr/aset.c
+++ b/src/backend/utils/mmgr/aset.c
@@ -188,14 +188,6 @@ typedef struct AllocBlockData
        char       *endptr;                     /* end of space in this block */
 }                      AllocBlockData;
 
-/*
- * Only the "hdrmask" field should be accessed outside this module.
- * We keep the rest of an allocated chunk's header marked NOACCESS when using
- * valgrind.  But note that chunk headers that are in a freelist are kept
- * accessible, for simplicity.
- */
-#define ALLOCCHUNK_PRIVATE_LEN offsetof(MemoryChunk, hdrmask)
-
 /*
  * AllocPointerIsValid
  *             True iff pointer is valid allocation pointer.
@@ -777,8 +769,8 @@ AllocSetAlloc(MemoryContext context, Size size)
                VALGRIND_MAKE_MEM_NOACCESS((char *) 
MemoryChunkGetPointer(chunk) + size,
                                                                   chunk_size - 
size);
 
-               /* Disallow external access to private part of chunk header. */
-               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
+               /* Disallow access to the chunk header. */
+               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
 
                return MemoryChunkGetPointer(chunk);
        }
@@ -823,8 +815,8 @@ AllocSetAlloc(MemoryContext context, Size size)
                VALGRIND_MAKE_MEM_NOACCESS((char *) 
MemoryChunkGetPointer(chunk) + size,
                                                                   
GetChunkSizeFromFreeListIdx(fidx) - size);
 
-               /* Disallow external access to private part of chunk header. */
-               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
+               /* Disallow access to the chunk header. */
+               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
 
                return MemoryChunkGetPointer(chunk);
        }
@@ -989,8 +981,8 @@ AllocSetAlloc(MemoryContext context, Size size)
        VALGRIND_MAKE_MEM_NOACCESS((char *) MemoryChunkGetPointer(chunk) + size,
                                                           chunk_size - size);
 
-       /* Disallow external access to private part of chunk header. */
-       VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
+       /* Disallow access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
 
        return MemoryChunkGetPointer(chunk);
 }
@@ -1005,8 +997,8 @@ AllocSetFree(void *pointer)
        AllocSet        set;
        MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
 
-       /* Allow access to private part of chunk header. */
-       VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOCCHUNK_PRIVATE_LEN);
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
 
        if (MemoryChunkIsExternal(chunk))
        {
@@ -1117,8 +1109,8 @@ AllocSetRealloc(void *pointer, Size size)
        Size            oldsize;
        int                     fidx;
 
-       /* Allow access to private part of chunk header. */
-       VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOCCHUNK_PRIVATE_LEN);
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
 
        if (MemoryChunkIsExternal(chunk))
        {
@@ -1166,8 +1158,8 @@ AllocSetRealloc(void *pointer, Size size)
                block = (AllocBlock) realloc(block, blksize);
                if (block == NULL)
                {
-                       /* Disallow external access to private part of chunk 
header. */
-                       VALGRIND_MAKE_MEM_NOACCESS(chunk, 
ALLOCCHUNK_PRIVATE_LEN);
+                       /* Disallow access to the chunk header. */
+                       VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
                        return NULL;
                }
 
@@ -1223,8 +1215,8 @@ AllocSetRealloc(void *pointer, Size size)
                /* Ensure any padding bytes are marked NOACCESS. */
                VALGRIND_MAKE_MEM_NOACCESS((char *) pointer + size, chksize - 
size);
 
-               /* Disallow external access to private part of chunk header. */
-               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
+               /* Disallow access to the chunk header . */
+               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
 
                return pointer;
        }
@@ -1296,8 +1288,8 @@ AllocSetRealloc(void *pointer, Size size)
                VALGRIND_MAKE_MEM_DEFINED(pointer, size);
 #endif
 
-               /* Disallow external access to private part of chunk header. */
-               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOCCHUNK_PRIVATE_LEN);
+               /* Disallow access to the chunk header. */
+               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
 
                return pointer;
        }
@@ -1322,8 +1314,8 @@ AllocSetRealloc(void *pointer, Size size)
                /* leave immediately if request was not completed */
                if (newPointer == NULL)
                {
-                       /* Disallow external access to private part of chunk 
header. */
-                       VALGRIND_MAKE_MEM_NOACCESS(chunk, 
ALLOCCHUNK_PRIVATE_LEN);
+                       /* Disallow access to the chunk header. */
+                       VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
                        return NULL;
                }
 
@@ -1363,11 +1355,17 @@ AllocSetGetChunkContext(void *pointer)
        AllocBlock      block;
        AllocSet        set;
 
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
+
        if (MemoryChunkIsExternal(chunk))
                block = ExternalChunkGetBlock(chunk);
        else
                block = (AllocBlock) MemoryChunkGetBlock(chunk);
 
+       /* Disallow access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
+
        Assert(AllocBlockIsValid(block));
        set = block->aset;
 
@@ -1385,16 +1383,27 @@ AllocSetGetChunkSpace(void *pointer)
        MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
        int                     fidx;
 
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
+
        if (MemoryChunkIsExternal(chunk))
        {
                AllocBlock      block = ExternalChunkGetBlock(chunk);
 
+               /* Disallow access to the chunk header. */
+               VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
+
                Assert(AllocBlockIsValid(block));
+
                return block->endptr - (char *) chunk;
        }
 
        fidx = MemoryChunkGetValue(chunk);
        Assert(FreeListIdxIsValid(fidx));
+
+       /* Disallow external access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, ALLOC_CHUNKHDRSZ);
+
        return GetChunkSizeFromFreeListIdx(fidx) + ALLOC_CHUNKHDRSZ;
 }
 
@@ -1555,8 +1564,8 @@ AllocSetCheck(MemoryContext context)
                        Size            chsize,
                                                dsize;
 
-                       /* Allow access to private part of chunk header. */
-                       VALGRIND_MAKE_MEM_DEFINED(chunk, 
ALLOCCHUNK_PRIVATE_LEN);
+                       /* Allow access to the chunk header. */
+                       VALGRIND_MAKE_MEM_DEFINED(chunk, ALLOC_CHUNKHDRSZ);
 
                        if (MemoryChunkIsExternal(chunk))
                        {
@@ -1606,12 +1615,9 @@ AllocSetCheck(MemoryContext context)
                                elog(WARNING, "problem in alloc set %s: 
detected write past chunk end in block %p, chunk %p",
                                         name, block, chunk);
 
-                       /*
-                        * If chunk is allocated, disallow external access to 
private part
-                        * of chunk header.
-                        */
+                       /* if chunk is allocated, disallow access to the chunk 
header */
                        if (dsize != InvalidAllocSize)
-                               VALGRIND_MAKE_MEM_NOACCESS(chunk, 
ALLOCCHUNK_PRIVATE_LEN);
+                               VALGRIND_MAKE_MEM_NOACCESS(chunk, 
ALLOC_CHUNKHDRSZ);
 
                        blk_data += chsize;
                        nchunks++;
diff --git a/src/backend/utils/mmgr/generation.c 
b/src/backend/utils/mmgr/generation.c
index 93825265a1..3cc5e481c0 100644
--- a/src/backend/utils/mmgr/generation.c
+++ b/src/backend/utils/mmgr/generation.c
@@ -98,14 +98,6 @@ struct GenerationBlock
        char       *endptr;                     /* end of space in this block */
 };
 
-/*
- * Only the "hdrmask" field should be accessed outside this module.
- * We keep the rest of an allocated chunk's header marked NOACCESS when using
- * valgrind.  But note that freed chunk headers are kept accessible, for
- * simplicity.
- */
-#define GENERATIONCHUNK_PRIVATE_LEN    offsetof(MemoryChunk, hdrmask)
-
 /*
  * GenerationIsValid
  *             True iff set is valid generation set.
@@ -407,8 +399,8 @@ GenerationAlloc(MemoryContext context, Size size)
                VALGRIND_MAKE_MEM_NOACCESS((char *) 
MemoryChunkGetPointer(chunk) + size,
                                                                   chunk_size - 
size);
 
-               /* Disallow external access to private part of chunk header. */
-               VALGRIND_MAKE_MEM_NOACCESS(chunk, GENERATIONCHUNK_PRIVATE_LEN);
+               /* Disallow access to the chunk header. */
+               VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
 
                return MemoryChunkGetPointer(chunk);
        }
@@ -522,8 +514,8 @@ GenerationAlloc(MemoryContext context, Size size)
        VALGRIND_MAKE_MEM_NOACCESS((char *) MemoryChunkGetPointer(chunk) + size,
                                                           chunk_size - size);
 
-       /* Disallow external access to private part of chunk header. */
-       VALGRIND_MAKE_MEM_NOACCESS(chunk, GENERATIONCHUNK_PRIVATE_LEN);
+       /* Disallow access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
 
        return MemoryChunkGetPointer(chunk);
 }
@@ -664,8 +656,8 @@ GenerationFree(void *pointer)
 #endif
        }
 
-       /* Allow access to private part of chunk header. */
-       VALGRIND_MAKE_MEM_DEFINED(chunk, GENERATIONCHUNK_PRIVATE_LEN);
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
 
 #ifdef MEMORY_CONTEXT_CHECKING
        /* Test for someone scribbling on unused space in chunk */
@@ -744,8 +736,8 @@ GenerationRealloc(void *pointer, Size size)
        GenerationPointer newPointer;
        Size            oldsize;
 
-       /* Allow access to private part of chunk header. */
-       VALGRIND_MAKE_MEM_DEFINED(chunk, GENERATIONCHUNK_PRIVATE_LEN);
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
 
        if (MemoryChunkIsExternal(chunk))
        {
@@ -832,8 +824,8 @@ GenerationRealloc(void *pointer, Size size)
                VALGRIND_MAKE_MEM_DEFINED(pointer, size);
 #endif
 
-               /* Disallow external access to private part of chunk header. */
-               VALGRIND_MAKE_MEM_NOACCESS(chunk, GENERATIONCHUNK_PRIVATE_LEN);
+               /* Disallow access to the chunk header. */
+               VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
 
                return pointer;
        }
@@ -844,8 +836,8 @@ GenerationRealloc(void *pointer, Size size)
        /* leave immediately if request was not completed */
        if (newPointer == NULL)
        {
-               /* Disallow external access to private part of chunk header. */
-               VALGRIND_MAKE_MEM_NOACCESS(chunk, GENERATIONCHUNK_PRIVATE_LEN);
+               /* Disallow access to the chunk header. */
+               VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
                return NULL;
        }
 
@@ -883,11 +875,17 @@ GenerationGetChunkContext(void *pointer)
        MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
        GenerationBlock *block;
 
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
+
        if (MemoryChunkIsExternal(chunk))
                block = ExternalChunkGetBlock(chunk);
        else
                block = (GenerationBlock *) MemoryChunkGetBlock(chunk);
 
+       /* Disallow access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
+
        Assert(GenerationBlockIsValid(block));
        return &block->context->header;
 }
@@ -903,6 +901,9 @@ GenerationGetChunkSpace(void *pointer)
        MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
        Size            chunksize;
 
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
+
        if (MemoryChunkIsExternal(chunk))
        {
                GenerationBlock *block = ExternalChunkGetBlock(chunk);
@@ -913,6 +914,9 @@ GenerationGetChunkSpace(void *pointer)
        else
                chunksize = MemoryChunkGetValue(chunk);
 
+       /* Disallow access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, Generation_CHUNKHDRSZ);
+
        return Generation_CHUNKHDRSZ + chunksize;
 }
 
@@ -1054,8 +1058,8 @@ GenerationCheck(MemoryContext context)
                        GenerationBlock *chunkblock;
                        Size            chunksize;
 
-                       /* Allow access to private part of chunk header. */
-                       VALGRIND_MAKE_MEM_DEFINED(chunk, 
GENERATIONCHUNK_PRIVATE_LEN);
+                       /* Allow access to the chunk header. */
+                       VALGRIND_MAKE_MEM_DEFINED(chunk, Generation_CHUNKHDRSZ);
 
                        if (MemoryChunkIsExternal(chunk))
                        {
@@ -1098,12 +1102,9 @@ GenerationCheck(MemoryContext context)
                        else
                                nfree += 1;
 
-                       /*
-                        * If chunk is allocated, disallow external access to 
private part
-                        * of chunk header.
-                        */
+                       /* if chunk is allocated, disallow access to the chunk 
header */
                        if (chunk->requested_size != InvalidAllocSize)
-                               VALGRIND_MAKE_MEM_NOACCESS(chunk, 
GENERATIONCHUNK_PRIVATE_LEN);
+                               VALGRIND_MAKE_MEM_NOACCESS(chunk, 
Generation_CHUNKHDRSZ);
                }
 
                /*
diff --git a/src/backend/utils/mmgr/mcxt.c b/src/backend/utils/mmgr/mcxt.c
index 8b6591abfb..8038a2fea4 100644
--- a/src/backend/utils/mmgr/mcxt.c
+++ b/src/backend/utils/mmgr/mcxt.c
@@ -190,8 +190,14 @@ GetMemoryChunkMethodID(const void *pointer)
         */
        Assert(pointer == (const void *) MAXALIGN(pointer));
 
+       /* Allow access to the uint64 header */
+       VALGRIND_MAKE_MEM_DEFINED((char *) pointer - sizeof(uint64), 
sizeof(uint64));
+
        header = *((const uint64 *) ((const char *) pointer - sizeof(uint64)));
 
+       /* Disallow access to the uint64 header */
+       VALGRIND_MAKE_MEM_NOACCESS((char *) pointer - sizeof(uint64), 
sizeof(uint64));
+
        return (MemoryContextMethodID) (header & MEMORY_CONTEXT_METHODID_MASK);
 }
 
@@ -204,7 +210,17 @@ GetMemoryChunkMethodID(const void *pointer)
 static inline uint64
 GetMemoryChunkHeader(const void *pointer)
 {
-       return *((const uint64 *) ((const char *) pointer - sizeof(uint64)));
+       uint64          header;
+
+       /* Allow access to the uint64 header */
+       VALGRIND_MAKE_MEM_DEFINED((char *) pointer - sizeof(uint64), 
sizeof(uint64));
+
+       header = *((const uint64 *) ((const char *) pointer - sizeof(uint64)));
+
+       /* Disallow access to the uint64 header */
+       VALGRIND_MAKE_MEM_NOACCESS((char *) pointer - sizeof(uint64), 
sizeof(uint64));
+
+       return header;
 }
 
 /*
diff --git a/src/backend/utils/mmgr/slab.c b/src/backend/utils/mmgr/slab.c
index 33dca0f37c..9fd00a98d0 100644
--- a/src/backend/utils/mmgr/slab.c
+++ b/src/backend/utils/mmgr/slab.c
@@ -630,6 +630,9 @@ SlabAlloc(MemoryContext context, Size size)
        randomize_mem((char *) MemoryChunkGetPointer(chunk), size);
 #endif
 
+       /* Disallow access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, Slab_CHUNKHDRSZ);
+
        return MemoryChunkGetPointer(chunk);
 }
 
@@ -646,6 +649,9 @@ SlabFree(void *pointer)
        int                     curBlocklistIdx;
        int                     newBlocklistIdx;
 
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
+
        /*
         * For speed reasons we just Assert that the referenced block is good.
         * Future field experience may show that this Assert had better become a
@@ -761,9 +767,14 @@ void *
 SlabRealloc(void *pointer, Size size)
 {
        MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
-       SlabBlock  *block = MemoryChunkGetBlock(chunk);
+       SlabBlock  *block;
        SlabContext *slab;
 
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
+
+       block = MemoryChunkGetBlock(chunk);
+
        /*
         * Try to verify that we have a sane block pointer: the block header
         * should reference a slab context.  (We use a test-and-elog, not just
@@ -790,9 +801,18 @@ MemoryContext
 SlabGetChunkContext(void *pointer)
 {
        MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
-       SlabBlock  *block = MemoryChunkGetBlock(chunk);
+       SlabBlock  *block;
+
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
+
+       block = MemoryChunkGetBlock(chunk);
+
+       /* Disallow access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, Slab_CHUNKHDRSZ);
 
        Assert(SlabBlockIsValid(block));
+
        return &block->slab->header;
 }
 
@@ -805,9 +825,17 @@ Size
 SlabGetChunkSpace(void *pointer)
 {
        MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
-       SlabBlock  *block = MemoryChunkGetBlock(chunk);
+       SlabBlock  *block;
        SlabContext *slab;
 
+       /* Allow access to the chunk header. */
+       VALGRIND_MAKE_MEM_DEFINED(chunk, Slab_CHUNKHDRSZ);
+
+       block = MemoryChunkGetBlock(chunk);
+
+       /* Disallow access to the chunk header. */
+       VALGRIND_MAKE_MEM_NOACCESS(chunk, Slab_CHUNKHDRSZ);
+
        Assert(SlabBlockIsValid(block));
        slab = block->slab;
 
@@ -1017,7 +1045,15 @@ SlabCheck(MemoryContext context)
                                if (!slab->isChunkFree[j])
                                {
                                        MemoryChunk *chunk = 
SlabBlockGetChunk(slab, block, j);
-                                       SlabBlock  *chunkblock = (SlabBlock *) 
MemoryChunkGetBlock(chunk);
+                                       SlabBlock  *chunkblock;
+
+                                       /* Allow access to the chunk header. */
+                                       VALGRIND_MAKE_MEM_DEFINED(chunk, 
Slab_CHUNKHDRSZ);
+
+                                       chunkblock = (SlabBlock *) 
MemoryChunkGetBlock(chunk);
+
+                                       /* Disallow access to the chunk header. 
*/
+                                       VALGRIND_MAKE_MEM_NOACCESS(chunk, 
Slab_CHUNKHDRSZ);
 
                                        /*
                                         * check the chunk's blockoffset 
correctly points back to

Reply via email to