[PATCH] Catch croak during PL/Perl result conversion

From: Andrey Rachitskiy <pl0h0yp1(at)gmail(dot)com>
To: pgsql-hackers mailing list <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Subject: [PATCH] Catch croak during PL/Perl result conversion
Date: 2026-09-16 20:54:31
Message-ID: CAB8bMit1h4PqwXsCRa4qeAzsxidgMV0wzGuL97Q78jQ=bQ6HDA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

plperl_call_perl_func() invokes the user's sub with call_sv(G_EVAL).
A die inside the sub becomes ERRSV and we report it as ERROR.

After the sub returns we convert the result in C. That path can
dispatch Perl magic: SvGETMAGIC(), av_fetch(), hv_iternext(), and
transform functions such as plperl_to_hstore(). A croak from FETCH
then finds no CXt_EVAL on Perl's cx stack. die_where() treats it as
uncaught, writes the message to stderr, and my_exit_jump() does
JMPENV_JUMP(2). The backend exits with status 2. The postmaster
runs crash recovery.

A tied scalar that RETURNS text already becomes ERROR, because
return $s runs FETCH inside pp_leavesub while G_EVAL is still
active. return \(at)tied or \%tied only returns a reference. The
element FETCHes happen later, after call_sv has returned.

The hole is any Perl croak from that C conversion, not only tie.
A trigger that returns an overloaded object dies in sv2cstr().

JMPENV_PUSH around the handler is not an eval context. It would
catch JMPENV_JUMP(2) after Perl has already unwound its stacks.
The interpreter is then in exit state, so the honest mapping is
FATAL, not ERROR.

The conversion needs a live Perl eval context. Register
PostgreSQL::InServer::_eval with newXS, next to
SPI::bootstrap. After SPI_finish, plperl_func_handler and
plperl_trigger_handler call that XSUB with call_sv(G_VOID | G_EVAL).
The XSUB runs the existing conversion. Postgres errors are turned
into croak_cstr(), the same pattern as plperl_spi_exec(). After
call_sv returns we restore PG_exception_stack and
error_context_stack, because a croak from FETCH longjmps to call_sv
and skips PG_TRY inside the XSUB. Nested conversion from
return_next() is already under the user's eval, so the trampoline
just calls the C function.

A croak from FETCH is then JMPENV_JUMP(3). call_sv returns with
ERRSV set. We report ERROR. The interpreter stays usable. The
same session can run another PL/Perl function.

A regress case is included. It covers die in FETCH, a missing
FETCH method, and die in FIRSTKEY. A plperlu case covers croak
from overload stringify on a trigger return.

--
Regards,
Rachitskiy Andrey

Attachment Content-Type Size
0001-Catch-croak-during-PL-Perl-result-conversion.patch text/x-patch 20.5 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Dmitry Dolgov 2026-09-16 20:56:35 Re: Routed ON CONFLICT inserts broken by partition-local deferrable unique constraints in 19 and master
Previous Message Robert Haas 2026-09-16 20:47:31 Re: PGQ catalog representation and pg_dump support