1
0
mirror of https://github.com/postgres/postgres.git synced 2026-01-27 21:43:08 +03:00
Files
postgres/src/include/utils/memdebug.h
Tom Lane bb049a79d3 Improve our support for Valgrind's leak tracking.
When determining whether an allocated chunk is still reachable,
Valgrind will consider only pointers within what it believes to be
allocated chunks.  Normally, all of a block obtained from malloc()
would be considered "allocated" --- but it turns out that if we use
VALGRIND_MEMPOOL_ALLOC to designate sub-section(s) of a malloc'ed
block as allocated, all the rest of that malloc'ed block is ignored.
This leads to lots of false positives of course.  In particular,
in any multi-malloc-block context, all but the primary block were
reported as leaked.  We also had a problem with context "ident"
strings, which were reported as leaked unless there was some other
pointer to them besides the one in the context header.

To fix, we need to use VALGRIND_MEMPOOL_ALLOC to designate
a context's management structs (the context struct itself and
any per-block headers) as allocated chunks.  That forces moving
the VALGRIND_CREATE_MEMPOOL/VALGRIND_DESTROY_MEMPOOL calls into
the per-context-type code, so that the pool identifier can be
made as soon as we've allocated the initial block, but otherwise
it's fairly straightforward.  Note that in Valgrind's eyes there
is no distinction between these allocations and the allocations
that the mmgr modules hand out to user code.  That's fine for
now, but perhaps someday we'll want to do better yet.

When reading this patch, it's helpful to start with the comments
added at the head of mcxt.c.

Author: Andres Freund <andres@anarazel.de>
Co-authored-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/285483.1746756246@sss.pgh.pa.us
Discussion: https://postgr.es/m/20210317181531.7oggpqevzz6bka3g@alap3.anarazel.de
2025-08-02 21:59:46 -04:00

84 lines
2.2 KiB
C

/*-------------------------------------------------------------------------
*
* memdebug.h
* Memory debugging support.
*
* Currently, this file either wraps <valgrind/memcheck.h> or substitutes
* empty definitions for Valgrind client request macros we use.
*
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/utils/memdebug.h
*
*-------------------------------------------------------------------------
*/
#ifndef MEMDEBUG_H
#define MEMDEBUG_H
#ifdef USE_VALGRIND
#include <valgrind/memcheck.h>
#else
#define VALGRIND_CHECK_MEM_IS_DEFINED(addr, size) do {} while (0)
#define VALGRIND_CREATE_MEMPOOL(context, redzones, zeroed) do {} while (0)
#define VALGRIND_DESTROY_MEMPOOL(context) do {} while (0)
#define VALGRIND_MAKE_MEM_DEFINED(addr, size) do {} while (0)
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size) do {} while (0)
#define VALGRIND_MAKE_MEM_UNDEFINED(addr, size) do {} while (0)
#define VALGRIND_MEMPOOL_ALLOC(context, addr, size) do {} while (0)
#define VALGRIND_MEMPOOL_FREE(context, addr) do {} while (0)
#define VALGRIND_MEMPOOL_CHANGE(context, optr, nptr, size) do {} while (0)
#define VALGRIND_MEMPOOL_TRIM(context, addr, size) do {} while (0)
#endif
#ifdef CLOBBER_FREED_MEMORY
/* Wipe freed memory for debugging purposes */
static inline void
wipe_mem(void *ptr, size_t size)
{
VALGRIND_MAKE_MEM_UNDEFINED(ptr, size);
memset(ptr, 0x7F, size);
VALGRIND_MAKE_MEM_NOACCESS(ptr, size);
}
#endif /* CLOBBER_FREED_MEMORY */
#ifdef MEMORY_CONTEXT_CHECKING
static inline void
set_sentinel(void *base, Size offset)
{
char *ptr = (char *) base + offset;
VALGRIND_MAKE_MEM_UNDEFINED(ptr, 1);
*ptr = 0x7E;
VALGRIND_MAKE_MEM_NOACCESS(ptr, 1);
}
static inline bool
sentinel_ok(const void *base, Size offset)
{
const char *ptr = (const char *) base + offset;
bool ret;
VALGRIND_MAKE_MEM_DEFINED(ptr, 1);
ret = *ptr == 0x7E;
VALGRIND_MAKE_MEM_NOACCESS(ptr, 1);
return ret;
}
#endif /* MEMORY_CONTEXT_CHECKING */
#ifdef RANDOMIZE_ALLOCATED_MEMORY
void randomize_mem(char *ptr, size_t size);
#endif /* RANDOMIZE_ALLOCATED_MEMORY */
#endif /* MEMDEBUG_H */