pkg/59831: patch: fix perl 5.42.0 segfault compiling certain programs

[email protected]
Newsgroups gmane.os.netbsd.devel.pkgsrc.bugs
Message-ID <[email protected]>
>Number:         59831
>Category:       pkg
>Synopsis:       patch: fix perl 5.42.0 segfault compiling certain programs
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    pkg-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Dec 12 04:05:00 +0000 2025
>Originator:     James Cook
>Release:        pkgsrc trunk
>Organization:
>Environment:
NetBSD ucl.h.falsifian.org 10.1 NetBSD 10.1 (GENERIC) #0: Mon Dec 16 13:08:11 UTC 2024  [email protected]:/usr/src/sys/arch/amd64/compile/GENERIC amd64
>Description:
perl 5.42.0 crashes compiling certain programs. I've included a patch, which is simply to apply upstream git commit 96673a4bb36.

See upstream bug report: https://github.com/perl/perl5/issues/23405

I also reported on the pkgsrc-users mailing list; start of thread: https://mail-index.netbsd.org/pkgsrc-users/2025/10/15/msg042082.html

>How-To-Repeat:
Run this command: perl -E 'for my($x,$y)($a->foo){}'
Result: Segmentation fault (core dumped)

After the patch, there is no segfault; instead perl (correctly) complains by outputting:
   Can't call method "foo" on an undefined value at -e line 1.
>Fix:
This patch to pkgsrc fixes it for me. (Applied atop commit ac347f1c6531de16c74bc2743dcf25610cccd465 from the git mirror)

(Sorry, I didn't follow the documented convention of naming the patch after the modified file, because it made more sense to me to keep the patch as one file.)

diff /home/falsifian/co/pkgsrc
path + /home/falsifian/co/pkgsrc
commit - ac347f1c6531de16c74bc2743dcf25610cccd465
blob - d50ed876359c2873fda8cfbad50dd35b46aa6dbb
file + lang/perl5/distinfo
--- lang/perl5/distinfo
+++ lang/perl5/distinfo
@@ -8,6 +8,7 @@ SHA1 (patch-Makefile.SH) = 56203aea57c429a94760f039a97
 SHA1 (patch-cpan_ExtUtils-MakeMaker_lib_ExtUtils_MM__BeOS.pm) = 79e5aeccfa272ca5ec08bffc616d8053ae90ac51
 SHA1 (patch-cpan_ExtUtils-MakeMaker_lib_ExtUtils_MM__Unix.pm) = 996556f221eb0c75c316315462bf6cea6746e030
 SHA1 (patch-cpan_ExtUtils-MakeMaker_t_MM__BeOS.t) = 9b0e7ab85fdab4887b1754599a8879bd7d9f36cc
+SHA1 (patch-fix_2-var_for_crash) = 77ae4219e11a484d78e4253785505a4b6450b287
 SHA1 (patch-hints_cygwin.sh) = 5e2e7179336c9bc085bd2e83d22755a235ea1a4a
 SHA1 (patch-hints_linux.sh) = 4baa8f80695687abb53d4f4e1830cf86db5b2bf7
 SHA1 (patch-hints_netbsd.sh) = cb498170c18f1f429eed9be245cd1df24c7ad628
commit - ac347f1c6531de16c74bc2743dcf25610cccd465
blob - /dev/null
file + lang/perl5/patches/patch-fix_2-var_for_crash (mode 644)
--- /dev/null
+++ lang/perl5/patches/patch-fix_2-var_for_crash
@@ -0,0 +1,78 @@
+$NetBSD$
+
+Fix a segfault when compiling a 2-var for loop over builtin::indexed.
+
+This is upstream git commit 96673a4bb36, with the following commit
+message:
+ 
+ newFOROP: fix crash when optimizing 2-var for over builtin::indexed
+ 
+ OP_ENTERSUB isn't necessarily a LISTOP, apparently, so we can't just
+ grab its op_last. Instead, copy/paste logic from elsewhere in op.c to
+ find the cvop.
+ 
+ Also, avoid crashing on "fake" pad entries that represent lexical subs
+ from outer scopes by climbing up the scope chain until we reach a real
+ pad entry.
+ 
+ Fixes #23405.
+
+diff d83bd2549fce92d161cd621b02e1f3c83162a718 96673a4bb36a973a9a4c5cd0e5727a799789a32c
+commit - d83bd2549fce92d161cd621b02e1f3c83162a718
+commit + 96673a4bb36a973a9a4c5cd0e5727a799789a32c
+blob - d7aaca7fe73c0ae938178e0e2b4425d99a48d613
+blob + 6a5f236cdf86819af838c36eac8b262050aca834
+--- op.c
++++ op.c
+@@ -9671,7 +9671,7 @@ S_op_is_cv_xsub(pTHX_ OP *o, XSUBADDR_t xsub)
+         }
+ 
+         case OP_PADCV:
+-            cv = (CV *)PAD_SVl(o->op_targ);
++            cv = find_lexical_cv(o->op_targ);
+             assert(cv && SvTYPE(cv) == SVt_PVCV);
+             break;
+ 
+@@ -9689,10 +9689,18 @@ S_op_is_cv_xsub(pTHX_ OP *o, XSUBADDR_t xsub)
+ static bool
+ S_op_is_call_to_cv_xsub(pTHX_ OP *o, XSUBADDR_t xsub)
+ {
+-    if(o->op_type != OP_ENTERSUB)
++    if (o->op_type != OP_ENTERSUB)
+         return false;
+ 
+-    OP *cvop = cLISTOPx(cUNOPo->op_first)->op_last;
++    /* entersub may be a UNOP, not a LISTOP, so we can't just use op_last */
++    OP *aop = cUNOPo->op_first;
++    if (!OpHAS_SIBLING(aop)) {
++        aop = cUNOPx(aop)->op_first;
++    }
++    aop = OpSIBLING(aop);
++    OP *cvop;
++    for (cvop = aop; OpHAS_SIBLING(cvop); cvop = OpSIBLING(cvop)) ;
++
+     return op_is_cv_xsub(cvop, xsub);
+ }
+ 
+blob - 2f6790aee7758e16c2c86374648e22a9304ca4fe
+blob + 035d1da07e9196a13b998ed41609d9a299aa9e20
+--- t/op/for-many.t
++++ t/op/for-many.t
+@@ -498,4 +498,17 @@ is($continue, 'xx', 'continue reached twice');
+     is("@have", "Pointy end Up Flamey end Down", 'for my ($one, $two)');
+ }
+ 
++# GH #23405 - segfaults when compiling 2-var for loops
++{
++    my $dummy = sub {};
++    for my ($x, $y) (main->$dummy) {}
++    pass '2-var for does not crash on method calls';
++
++    my sub dummy {}
++    sub {
++        for my ($x, $y) (dummy) {}
++    }->();
++    pass '2-var for does not crash on lexical sub calls';
++}
++
+ done_testing();
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.