Skip to content

Commit b7b8b09

Browse files
iabynsteve-m-hay
authored andcommitted
avoid identical stack traces
GH #15109 The output of caller() (e.g. as produced by carp::Confess) produces multiple identical outputs when within a nested use/require. This is because at the time of calling the 'BEGIN { require ... }', PL_curcop is set to &PL_compiling, which is a fixed buffer within the interpreter, whose individual file and line fields are saved and restored when doing a new require/eval. This means that within the innermost require, PL_compiling has file:lineno of the innermost source file, and multiple saved PL_curcop values in the context stack frames all point to the same &PL_copmpiling. So all levels of the stack trace appear to come from the innermost file. This commit fixes this (after a fashion) by, at the start of calling a BEGIN, making PL_curcop point to a temporary copy of PL_compiling instead. This is all a bit of a hack. (cherry picked from commit f2f32cd)
1 parent 56969e8 commit b7b8b09

File tree

6 files changed

+63
-2
lines changed

6 files changed

+63
-2
lines changed

MANIFEST

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5476,6 +5476,9 @@ t/lib/feature/nonesuch Tests for enabling/disabling nonexistent feature
54765476
t/lib/feature/removed Tests for enabling/disabling removed feature
54775477
t/lib/feature/say Tests for enabling/disabling say feature
54785478
t/lib/feature/switch Tests for enabling/disabling switch feature
5479+
t/lib/GH_15109/Apack.pm test Module for caller.t
5480+
t/lib/GH_15109/Bpack.pm test Module for caller.t
5481+
t/lib/GH_15109/Cpack.pm test Module for caller.t
54795482
t/lib/h2ph.h Test header file for h2ph
54805483
t/lib/h2ph.pht Generated output from h2ph.h by h2ph, for comparison
54815484
t/lib/locale/latin1 Part of locale.t in Latin 1

op.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10460,10 +10460,32 @@ S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
1046010460
(void)CvGV(cv);
1046110461
if (floor) LEAVE_SCOPE(floor);
1046210462
ENTER;
10463+
10464+
SAVEVPTR(PL_curcop);
10465+
if (PL_curcop == &PL_compiling) {
10466+
/* Avoid pushing the "global" &PL_compiling onto the
10467+
* context stack. For example, a stack trace inside
10468+
* nested use's would show all calls coming from whoever
10469+
* most recently updated PL_compiling.cop_file and
10470+
* cop_line. So instead, temporarily set PL_curcop to a
10471+
* private copy of &PL_compiling. PL_curcop will soon be
10472+
* set to point back to &PL_compiling anyway but only
10473+
* after the temp value has been pushed onto the context
10474+
* stack as blk_oldcop.
10475+
* This is slightly hacky, but necessary. Note also
10476+
* that in the brief window before PL_curcop is set back
10477+
* to PL_compiling, IN_PERL_COMPILETIME/IN_PERL_RUNTIME
10478+
* will give the wrong answer.
10479+
*/
10480+
Newx(PL_curcop, 1, COP);
10481+
StructCopy(&PL_compiling, PL_curcop, COP);
10482+
PL_curcop->op_slabbed = 0;
10483+
SAVEFREEPV(PL_curcop);
10484+
}
10485+
1046310486
PUSHSTACKi(PERLSI_REQUIRE);
1046410487
SAVECOPFILE(&PL_compiling);
1046510488
SAVECOPLINE(&PL_compiling);
10466-
SAVEVPTR(PL_curcop);
1046710489

1046810490
DEBUG_x( dump_sub(gv) );
1046910491
Perl_av_create_and_push(aTHX_ &PL_beginav, MUTABLE_SV(cv));

t/lib/GH_15109/Apack.pm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# for use by caller.t for GH #15109
2+
package Apack;
3+
use Bpack;
4+
1;

t/lib/GH_15109/Bpack.pm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# for use by caller.t for GH #15109
2+
package Bpack;
3+
use Cpack;
4+
1;

t/lib/GH_15109/Cpack.pm

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# for use by caller.t for GH #15109
2+
package Cpack;
3+
4+
5+
my $i = 0;
6+
7+
while (my ($package, $file, $line) = caller($i++)) {
8+
push @Cpack::callers, "$file:$line";
9+
}
10+
11+
1;

t/op/caller.t

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ BEGIN {
55
chdir 't' if -d 't';
66
require './test.pl';
77
set_up_inc('../lib');
8-
plan( tests => 97 ); # some tests are run in a BEGIN block
8+
plan( tests => 109 ); # some tests are run in a BEGIN block
99
}
1010

1111
my @c;
@@ -335,6 +335,22 @@ $::testing_caller = 1;
335335

336336
do './op/caller.pl' or die $@;
337337

338+
# GH #15109
339+
# See that callers within a nested series of 'use's gets the right
340+
# filenames.
341+
{
342+
local @INC = 'lib/GH_15109/';
343+
# Apack use's Bpack which use's Cpack which populates @Cpack::caller
344+
# with the file:N of all the callers
345+
eval 'use Apack; 1';
346+
is($@, "", "GH #15109 - eval");
347+
is (scalar(@Cpack::callers), 10, "GH #15109 - callers count");
348+
like($Cpack::callers[$_], qr{GH_15109/Bpack.pm:3}, "GH #15109 level $_") for 0..2;
349+
like($Cpack::callers[$_], qr{GH_15109/Apack.pm:3}, "GH #15109 level $_") for 3..5;
350+
like($Cpack::callers[$_], qr{\(eval \d+\):1}, "GH #15109 level $_") for 6..8;
351+
like($Cpack::callers[$_], qr{caller\.t}, "GH #15109 level $_") for 9;
352+
}
353+
338354
{
339355
package RT129239;
340356
BEGIN {
@@ -348,3 +364,4 @@ do './op/caller.pl' or die $@;
348364
#line 12345 "virtually/op/caller.t"
349365
}
350366
}
367+

0 commit comments

Comments
 (0)