Skip to content

Commit

Permalink
op.c - work around Module::Install::DSL issue
Browse files Browse the repository at this point in the history
This converts INIT {} blocks from the Module::Install::DSL
namespace into BEGIN blocks. This works around the bug reported in
GH Issue Perl#16300. (Hopefully, not fully tested yet.) Which in turn
should allow us to close the bug in Perl#2754.

See also PR: Perl#20168 and Issue: Perl#20161 both of which are blocked by
this.
  • Loading branch information
demerphq authored and scottchiefbaker committed Nov 3, 2022
1 parent 8ec18e1 commit 619c93c
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 2 deletions.
29 changes: 28 additions & 1 deletion op.c
Original file line number Diff line number Diff line change
Expand Up @@ -10711,16 +10711,19 @@ S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
{
const char *const colon = strrchr(fullname,':');
const char *const name = colon ? colon + 1 : fullname;
int is_module_install_hack = 0;

PERL_ARGS_ASSERT_PROCESS_SPECIAL_BLOCKS;

if (*name == 'B') {
if (strEQ(name, "BEGIN")) {
module_install_hack:
if (strEQ(name, "BEGIN") || is_module_install_hack) {
const I32 oldscope = PL_scopestack_ix;
SV *max_nest_sv = NULL;
IV max_nest_iv;
dSP;
(void)CvGV(cv);
is_module_install_hack = 0;
if (floor) LEAVE_SCOPE(floor);
ENTER;

Expand Down Expand Up @@ -10846,6 +10849,30 @@ S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
return FALSE;
} else if (*name == 'I') {
if (strEQ(name, "INIT")) {
#ifdef MI_INIT_WORKAROUND_PACK
{
HV *hv= CvSTASH(cv);
STRLEN len = hv ? HvNAMELEN(hv) : 0;
char *pv= (len == sizeof(MI_INIT_WORKAROUND_PACK)-1)
? HvNAME_get(hv) : NULL;
if ( pv && strEQ(pv,MI_INIT_WORKAROUND_PACK) )
{
/* old versions of Module::Install::DSL contain code
* that creates an INIT in eval, which expect to run
* after an exit(0) in BEGIN. This unfortunately
* breaks a lot of code in the CPAN river. So we magically
* convert INIT blocks from Module::Install::DSL to
* be BEGIN blocks. Which works out, since the INIT
* blocks it creates are eval'ed so are late.
*/
Perl_warn(aTHX_ "Treating %s::INIT block as BEGIN block as workaround",
MI_INIT_WORKAROUND_PACK);
is_module_install_hack = 1;
goto module_install_hack;
}

}
#endif
if (PL_main_start)
/* diag_listed_as: Too late to run %s block */
Perl_ck_warner(aTHX_ packWARN(WARN_VOID),
Expand Down
1 change: 1 addition & 0 deletions op.h
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,7 @@ struct op_argcheck_aux {
char slurpy; /* presence of slurpy: may be '\0', '@' or '%' */
};

#define MI_INIT_WORKAROUND_PACK "Module::Install::DSL"

/*
* ex: set ts=8 sts=4 sw=4 et:
Expand Down
9 changes: 9 additions & 0 deletions pod/perldiag.pod
Original file line number Diff line number Diff line change
Expand Up @@ -6414,6 +6414,15 @@ C<$tr> or C<$y> may cause this error.
(F) The lexer couldn't find the final delimiter of a tr///, tr[][],
y/// or y[][] construct.

=item Treating %s::INIT block as BEGIN block as workaround

(S) A package is using an old version of C<Module::Install::DSL> to
install, which makes unsafe assumptions about when INIT blocks will be
called. Because C<Module::Install::DSL> is used to install other modules
and is difficult to upgrade we have a special workaround in place to
deal with this. Unless you are a maintainer of an affected module you
can ignore this warning. We emit it only as a sanity check.

=item '%s' trapped by operation mask

(F) You tried to use an operator from a Safe compartment in which it's
Expand Down
6 changes: 5 additions & 1 deletion t/op/blocks.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ BEGIN {
set_up_inc('../lib');
}

plan tests => 22;
plan tests => 23;

my @expect = qw(
b1
Expand Down Expand Up @@ -265,3 +265,7 @@ TODO: {

fresh_perl_is('eval "BEGIN {goto end}"; end:', '', {}, 'RT #113934: goto out of BEGIN causes assertion failure');

fresh_perl_is('package Module::Install::DSL; BEGIN { eval "INIT { print q(INIT fired in eval) }" }',
"Treating Module::Install::DSL::INIT block as BEGIN block as workaround at (eval 1) line 1.\n"
."INIT fired in eval", {},
'GH Issue #16300: Module::Install::DSL workaround');

0 comments on commit 619c93c

Please sign in to comment.