Skip to content

Commit ed39ffd

Browse files
committed
toke.c: fix =cut detection
A line starting with `=cut` is only a cut directive if the next character is not a word character. Checking for isALPHA is insufficient because POD directives can contain digits (e.g. `=head1`, `=head2`). Add the same check to the string eval case, where it was missing entirely. Fixes #22759.
1 parent 8c2d9d3 commit ed39ffd

File tree

3 files changed

+134
-3
lines changed

3 files changed

+134
-3
lines changed

pod/perldelta.pod

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,15 @@ manager will later use a regex to expand these into links.
427427

428428
=item *
429429

430+
The perl parser would erroneously parse like C<=cut> some other POD directives
431+
whose names start with I<cut>, prematurely terminating an embedded POD section.
432+
The following cases were affected: I<cut> followed by a digit (e.g.
433+
C<=cut2studio>), I<cut> followed by an underscore (e.g. C<=cut_grass>), and in
434+
string C<eval>, any identifier starting with I<cut> (e.g. C<=cute>).
435+
[GH #22759]
436+
437+
=item *
438+
430439
Builds with C<-msse> and quadmath on 32-bit x86 systems would crash
431440
with a misaligned access early in the build. [GH #22577]
432441

t/base/lex.t

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!./perl
22

3-
print "1..120\n";
3+
print "1..129\n";
44

55
$x = 'x';
66

@@ -586,3 +586,124 @@ $test++;
586586
print "not " unless ref $::{bas} eq 'SCALAR';
587587
print "ok $test - second constant in 'const1 const2' is not upgraded\n";
588588
$test++;
589+
590+
# Test various "not quite =cut" POD directives, which should not terminate a
591+
# POD section.
592+
593+
$foo = "";
594+
595+
=pod
596+
597+
=cute
598+
$foo = "not ";
599+
600+
=pod
601+
602+
=cut
603+
604+
print $foo, "ok $test - =cute does not end POD\n";
605+
$test++;
606+
607+
$foo = "";
608+
609+
=pod
610+
611+
=cut2
612+
$foo = "not ";
613+
614+
=pod
615+
616+
=cut
617+
618+
print $foo, "ok $test - =cut2 does not end POD\n";
619+
$test++;
620+
621+
$foo = "";
622+
623+
=pod
624+
625+
=cut_
626+
$foo = "not ";
627+
628+
=pod
629+
630+
=cut
631+
632+
print $foo, "ok $test - =cut_ does not end POD\n";
633+
$test++;
634+
635+
$foo = "not ";
636+
637+
=pod
638+
639+
=cut$cene
640+
$foo = "";
641+
642+
=pod
643+
644+
=cut
645+
646+
print $foo, "ok $test - =cut\$cene ends POD\n";
647+
$test++;
648+
649+
# Same as above, but in string eval.
650+
651+
eval q{
652+
$foo = "";
653+
654+
=pod
655+
656+
=cute
657+
$foo = "not ";
658+
659+
=pod
660+
661+
=cut
662+
663+
print $foo, "ok $test - =cute does not end POD in string eval\n";
664+
$test++;
665+
666+
$foo = "";
667+
668+
=pod
669+
670+
=cut2
671+
$foo = "not ";
672+
673+
=pod
674+
675+
=cut
676+
677+
print $foo, "ok $test - =cut2 does not end POD in string eval\n";
678+
$test++;
679+
680+
$foo = "";
681+
682+
=pod
683+
684+
=cut_
685+
$foo = "not ";
686+
687+
=pod
688+
689+
=cut
690+
691+
print $foo, "ok $test - =cut_ does not end POD in string eval\n";
692+
$test++;
693+
694+
$foo = "not ";
695+
696+
=pod
697+
698+
=cut$cene
699+
$foo = "";
700+
701+
=pod
702+
703+
=cut
704+
705+
print $foo, "ok $test - =cut\$cene ends POD in string eval\n";
706+
$test++;
707+
};
708+
709+
print $@ eq "" ? "" : "not ", "ok $test - did not throw an error\n# $@\n";

toke.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7349,7 +7349,7 @@ yyl_fake_eof(pTHX_ U32 fake_eof, bool bof, char *s)
73497349
if (PL_parser->in_pod) {
73507350
/* Incest with pod. */
73517351
if ( memBEGINPs(s, (STRLEN) (PL_bufend - s), "=cut")
7352-
&& !isALPHA(s[4]))
7352+
&& !isIDCONT_A(s[4]))
73537353
{
73547354
SvPVCLEAR(PL_linestr);
73557355
PL_oldoldbufptr = PL_oldbufptr = s = PL_linestart = SvPVX(PL_linestr);
@@ -9372,7 +9372,8 @@ yyl_try(pTHX_ char *s)
93729372
while (s < d) {
93739373
if (*s++ == '\n') {
93749374
incline(s, PL_bufend);
9375-
if (memBEGINs(s, (STRLEN) (PL_bufend - s), "=cut"))
9375+
if (memBEGINPs(s, (STRLEN) (PL_bufend - s), "=cut")
9376+
&& !isIDCONT_A(s[4]))
93769377
{
93779378
s = (char *) memchr(s,'\n', d - s);
93789379
if (s)

0 commit comments

Comments
 (0)