[PATCH] Catch croak during PL/Perl result conversion - Mailing list pgsql-hackers

From Andrey Rachitskiy
Subject [PATCH] Catch croak during PL/Perl result conversion
Date
Msg-id CAB8bMit1h4PqwXsCRa4qeAzsxidgMV0wzGuL97Q78jQ=bQ6HDA@mail.gmail.com
Whole thread
List 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 \@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

pgsql-hackers by date:

Previous
From: Robert Haas
Date:
Subject: Re: PGQ catalog representation and pg_dump support
Next
From: Dmitry Dolgov
Date:
Subject: Re: Routed ON CONFLICT inserts broken by partition-local deferrable unique constraints in 19 and master