Re: Prevent crash when calling pgstat functions with unregistered stats kind

Ewan Young <kdbase.hack@gmail.com>

From: Ewan Young <kdbase.hack@gmail.com>
To: Bertrand Drouvot <bertranddrouvot.pg@gmail.com>
Cc: pgsql-hackers@lists.postgresql.org, Michael Paquier <michael@paquier.xyz>
Date: 2026-07-01T08:20:39Z
Lists: pgsql-hackers
Hi Bertrand,

On Wed, Jul 1, 2026 at 3:20 PM Bertrand Drouvot
<bertranddrouvot.pg@gmail.com> wrote:
>
> Hi hackers,
>
> While reviewing [1], I got segfault(s) because I created a custom statistics
> extension that I forgot to add to shared_preload_libraries. Then using one of
> its function produced:
>
> "
> Core was generated by `postgres: postgres postgres [local] SELECT                                    '.
> Program terminated with signal SIGSEGV, Segmentation fault.
> #0  pgstat_init_entry (kind=kind@entry=24, shhashent=shhashent@entry=0x73f6c341a740) at pgstat_shmem.c:335
> 335             chunk = dsa_allocate_extended(pgStatLocal.dsa,
> "
>
> Indeed, if a custom statistics extension is loaded via CREATE EXTENSION without
> being listed in shared_preload_libraries, its _PG_init() skips the call to
> pgstat_register_kind(). The SQL functions are still created, and calling them
> invokes pgstat functions with a kind that was never registered.
>
> pgstat_get_kind_info() returns NULL in this case. The existing code only
> checked this via Assert() in some paths, so non-assert builds would dereference
> NULL and segfault.
>
> The attached patch adds runtime checks in all public-facing pgstat functions that
> accept a PgStat_Kind and dereference the returned kind info:
>
> - pgstat_prep_pending_entry()
> - pgstat_fetch_entry()
> - pgstat_reset()
> - pgstat_reset_of_kind()
> - pgstat_have_entry()
> - pgstat_snapshot_fixed()
> - pgstat_init_entry()
> - pgstat_reset_entry()
>
> Each now raises ERROR with ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE when
> the kind is not known or registered.

Thanks for the patch — nice catch, and the diagnosis looks right.

One small thing: in pgstat_snapshot_fixed(), the existing
Assert(pgstat_is_kind_valid(kind)); becomes redundant after the new NULL
check. A non-NULL kind_info already implies the kind is valid (that's the
only way pgstat_get_kind_info() returns non-NULL), so the assert can never
fire. Might as well drop it and keep just the fixed_amount one.

>
> [1]: https://postgr.es/m/akSi2txzLZWQL31Q%40bdtpg
>
> Regards,
>
> --
> Bertrand Drouvot
> PostgreSQL Contributors Team
> RDS Open Source Databases
> Amazon Web Services: https://aws.amazon.com

-- 
Regards,
Ewan Young



Commits

  1. test_custom_stats: Fail if loading module outside shared_preload_libraries