Skip to content
This repository was archived by the owner on Jun 1, 2023. It is now read-only.

Commit 37778ec

Browse files
Father ChrysostomosReini Urban
authored andcommitted
[perl #128597] Crash from gp_free/ckWARN_d
See the explanation in the test added and in the RT ticket. The solution is to make the warn macros check that PL_curcop is non-null.
1 parent 4f76915 commit 37778ec

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

regen/warnings.pl

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,8 +361,10 @@ sub mkOct
361361

362362
print $warn <<'EOM';
363363
364-
#define isLEXWARN_on cBOOL(PL_curcop->cop_warnings != pWARN_STD)
365-
#define isLEXWARN_off cBOOL(PL_curcop->cop_warnings == pWARN_STD)
364+
#define isLEXWARN_on \
365+
cBOOL(PL_curcop && PL_curcop->cop_warnings != pWARN_STD)
366+
#define isLEXWARN_off \
367+
cBOOL(!PL_curcop || PL_curcop->cop_warnings == pWARN_STD)
366368
#define isWARN_ONCE (PL_dowarn & (G_WARN_ON|G_WARN_ONCE))
367369
#define isWARN_on(c,x) (IsSet((U8 *)(c + 1), 2*(x)))
368370
#define isWARNf_on(c,x) (IsSet((U8 *)(c + 1), 2*(x)+1))

t/op/gv.t

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ BEGIN {
1212

1313
use warnings;
1414

15-
plan(tests => 276 );
15+
plan(tests => 277 );
1616

1717
# type coercion on assignment
1818
$foo = 'foo';
@@ -1153,6 +1153,22 @@ pass "No crash due to CvGV pointing to glob copy in the stash";
11531153
is($c_125840, 1, 'RT #125840: $c=$d');
11541154
}
11551155

1156+
# [perl #128597] Crash when gp_free calls ckWARN_d
1157+
# I am not sure this test even belongs in this file, as the crash was the
1158+
# result of various features interacting. But a call to ckWARN_d from
1159+
# gv.c:gp_free triggered the crash, so this seems as good a place as any.
1160+
# ‘die’ (or any abnormal scope exit) can cause the current cop to be freed,
1161+
# if the subroutine containing the ‘die’ gets freed as a result. That
1162+
# causes PL_curcop to be set to NULL. If a writable handle gets freed
1163+
# while PL_curcop is NULL, then gp_free will call ckWARN_d while that con-
1164+
# dition still holds, so ckWARN_d needs to know about PL_curcop possibly
1165+
# being NULL.
1166+
SKIP: {
1167+
skip_if_miniperl("No PerlIO::scalar on miniperl", 1);
1168+
runperl(prog => 'open my $fh, q|>|, \$buf;'
1169+
.'my $sub = eval q|sub {exit 0}|; $sub->()');
1170+
is ($? & 127, 0,"[perl #128597] No crash when gp_free calls ckWARN_d");
1171+
}
11561172

11571173
__END__
11581174
Perl

warnings.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,10 @@
120120
#define WARN_ALLstring "\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125\125"
121121
#define WARN_NONEstring "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
122122

123-
#define isLEXWARN_on cBOOL(PL_curcop->cop_warnings != pWARN_STD)
124-
#define isLEXWARN_off cBOOL(PL_curcop->cop_warnings == pWARN_STD)
123+
#define isLEXWARN_on \
124+
cBOOL(PL_curcop && PL_curcop->cop_warnings != pWARN_STD)
125+
#define isLEXWARN_off \
126+
cBOOL(!PL_curcop || PL_curcop->cop_warnings == pWARN_STD)
125127
#define isWARN_ONCE (PL_dowarn & (G_WARN_ON|G_WARN_ONCE))
126128
#define isWARN_on(c,x) (IsSet((U8 *)(c + 1), 2*(x)))
127129
#define isWARNf_on(c,x) (IsSet((U8 *)(c + 1), 2*(x)+1))

0 commit comments

Comments
 (0)