From 08a86633fa32a3112ce4c83561a5954ac1ee57f9 Mon Sep 17 00:00:00 2001 From: Hayato Kuroda Date: Wed, 11 Nov 2026 19:07:51 +0900 Subject: [PATCH v2 1/2] injection points: reproducer for the race condition between cleanup and attach() --- .../expected/local_cleanup.out | 59 +++++++++++++++++++ src/test/modules/injection_points/meson.build | 5 +- .../injection_points/specs/local_cleanup.spec | 48 +++++++++++++++ 3 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 src/test/modules/injection_points/expected/local_cleanup.out create mode 100644 src/test/modules/injection_points/specs/local_cleanup.spec diff --git a/src/test/modules/injection_points/expected/local_cleanup.out b/src/test/modules/injection_points/expected/local_cleanup.out new file mode 100644 index 00000000000..6f18c0a24dd --- /dev/null +++ b/src/test/modules/injection_points/expected/local_cleanup.out @@ -0,0 +1,59 @@ +Parsed test spec with 3 sessions + +starting permutation: wait1 replace2 terminate3 noop3 run2 detach2 +injection_points_attach +----------------------- + +(1 row) + +step wait1: + SELECT injection_points_run('injection-points-local-cleanup'); + +step replace2: + SELECT injection_points_detach('injection-points-local-cleanup'); + SELECT injection_points_attach('injection-points-local-cleanup', 'notice'); + +injection_points_detach +----------------------- + +(1 row) + +injection_points_attach +----------------------- + +(1 row) + +step terminate3: + SELECT pg_terminate_backend(pid) FROM pg_stat_activity + WHERE wait_event = 'injection-points-local-cleanup'; + +step wait1: <... completed> +FATAL: terminating connection due to administrator command +server closed the connection unexpectedly + This probably means the server terminated abnormally + before or while processing the request. + +step terminate3: <... completed> +pg_terminate_backend +-------------------- +t +(1 row) + +step noop3: +s2: NOTICE: notice triggered for injection point injection-points-local-cleanup +step run2: + SELECT injection_points_run('injection-points-local-cleanup'); + +injection_points_run +-------------------- + +(1 row) + +step detach2: + SELECT injection_points_detach('injection-points-local-cleanup'); + +injection_points_detach +----------------------- + +(1 row) + diff --git a/src/test/modules/injection_points/meson.build b/src/test/modules/injection_points/meson.build index cf9cb219548..f4c43df8877 100644 --- a/src/test/modules/injection_points/meson.build +++ b/src/test/modules/injection_points/meson.build @@ -51,7 +51,10 @@ injection_points_isolation = [ # on Windows, making the test unstable there. # See https://postgr.es/m/088AB35D-0860-494A-A9CF-8B301543AA51@yandex-team.ru if host_system != 'windows' - injection_points_isolation += 'wait_cleanup' + injection_points_isolation += [ + 'local_cleanup', + 'wait_cleanup', + ] endif tests += { diff --git a/src/test/modules/injection_points/specs/local_cleanup.spec b/src/test/modules/injection_points/specs/local_cleanup.spec new file mode 100644 index 00000000000..696b3a4ff4a --- /dev/null +++ b/src/test/modules/injection_points/specs/local_cleanup.spec @@ -0,0 +1,48 @@ +# Check that cleanup of a local injection point does not detach another point +# that was attached later using the same name. + +setup +{ + CREATE EXTENSION injection_points; +} +teardown +{ + DROP EXTENSION injection_points; +} + +# Attach a local injection point and wait in its callback, keeping this +# backend alive while another backend replaces the point. +session s1 +setup { + SELECT injection_points_set_local(); + SELECT injection_points_attach('injection-points-local-cleanup', 'wait'); +} +step wait1 { + SELECT injection_points_run('injection-points-local-cleanup'); +} + +# Replace the local point, then verify that the replacement survives cleanup +# of the backend that owned the original point. +session s2 +step replace2 { + SELECT injection_points_detach('injection-points-local-cleanup'); + SELECT injection_points_attach('injection-points-local-cleanup', 'notice'); +} +step run2 { + SELECT injection_points_run('injection-points-local-cleanup'); +} +step detach2 { + SELECT injection_points_detach('injection-points-local-cleanup'); +} + +# Terminate s1 to run its before_shmem_exit cleanup. noop3 is needed to ensure +# wait1 has fully completed before starting run2. +session s3 +step terminate3 { + SELECT pg_terminate_backend(pid) FROM pg_stat_activity + WHERE wait_event = 'injection-points-local-cleanup'; +} +step noop3 { } + +# Keep this permutation last because s1 cannot be reused after termination. +permutation wait1 replace2 terminate3(wait1) noop3 run2 detach2 -- 2.52.0