Skip to content

Quickstart

  • PostgreSQL 15 or later (server headers required)
  • pg_config in your PATH
  • A C compiler (gcc or clang)
  1. Clone the repository

    Terminal window
    git clone https://github.com/samsiva-dev/pg_ext_memcheck.git
    cd pg_ext_memcheck
  2. Build and install

    Terminal window
    make
    sudo make install

    This uses PGXS to build against your installed PostgreSQL headers and places the extension files in the correct $libdir.

  3. Configure postgresql.conf

    Add the extension to the preloaded libraries so the background worker and hooks are registered at startup:

    # postgresql.conf
    shared_preload_libraries = 'pg_ext_memcheck'

    Restart PostgreSQL after making this change.

  4. Create the extension

    CREATE EXTENSION pg_ext_memcheck;

Test a simple function or query from/on any extension you are developing:

-- Set the monitoring mode (controls which execution phases are instrumented)
SET pg_ext_memcheck.memcheck_mode = 'executor';
-- Start a check window targeted at your extension's memory contexts.
-- The pattern uses SQL LIKE syntax; '%' is a wildcard.
-- Pass an empty string to monitor all contexts.
SELECT ext_memcheck.begin('MyExtCtx%');
-- Call the function you want to inspect
SELECT your_extension.some_function('input');
-- End the window; returns violations for contexts matching 'MyExtCtx%'
SELECT * FROM ext_memcheck.end();
-- Also flush any remaining ring-buffer entries to the log table
SELECT ext_memcheck.flush_violations();
-- Query the violation log for details
SELECT * FROM ext_memcheck.violation_log ORDER BY ts DESC;

If flush_violations() returns zero rows, no leaks or wrong-context allocations were detected for that invocation.

To suppress false positives from contexts your extension intentionally uses long-term, pass an allowed_contexts allowlist:

SET pg_ext_memcheck.memcheck_mode = 'all';
SELECT ext_memcheck.begin(
'MyExtCtx%',
'{"allowed_contexts": ["TopMemoryContext", "CacheMemoryContext"]}'
);
SELECT your_extension.some_function('input');
SELECT * FROM ext_memcheck.end();

A violation row looks like this:

ColumnExample
ts2026-05-10 14:32:01 UTC
backend_pid12345
detail"Context present in post-query snapshot but not pre-query"
severityWARNING, INFO, ERROR
check_typecontext_leak, wrong_ctx_alloc, shmem_overrun, etc.
source_libyour_extension.dylib
-- Run the growth benchmark scenario (measures context growth over repeated calls)
SELECT ext_memcheck.run_scenario('growth_benchmark', 100, 'SELECT your_extension.some_function(''input'');');
SELECT ext_memcheck.flush_violations();
-- Run the tx_abort_loop scenario (tests memory cleanup on transaction abort)
SELECT ext_memcheck.run_scenario('tx_abort_loop', 50, 'SELECT your_extension.some_function(''input'');');
SELECT ext_memcheck.flush_violations();
ParameterTypeDefaultDescription
pg_ext_memcheck.memcheck_modeenumnoneall / executor / none — controls which execution phases are hooked. See API reference.
pg_ext_memcheck.min_leak_bytesint8192Context growth smaller than this (in bytes) is silently ignored by the leak detector.
pg_ext_memcheck.bloat_min_bytesint8192Minimum cumulative growth (in bytes) for a context to be reported as bloating by growth_benchmark.

memcheck_mode controls which phases are hooked; the ext_context_pattern argument to begin() controls which contexts are reported. Set the GUC once for the session:

-- Executor-only mode (less noise, skips planning-phase allocations)
SET pg_ext_memcheck.memcheck_mode = 'executor';
-- Full coverage: planner + executor
SET pg_ext_memcheck.memcheck_mode = 'all';

The pg_ext_memcheck extension includes a test suite that can be run using pg_regress (comes with PostgreSQL source). To run the tests:

From the extension directory, run:

Terminal window
PG_CONFIG=pg_config ./test/run_tests.sh