Skip to content

Smoke me/fix caller issues #18568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -5639,6 +5639,10 @@ t/lib/feature/nonesuch Tests for enabling/disabling nonexistent feature
t/lib/feature/removed Tests for enabling/disabling removed feature
t/lib/feature/say Tests for enabling/disabling say feature
t/lib/feature/switch Tests for enabling/disabling switch feature
t/lib/GH_15109/Apack.pm test Module for caller.t
t/lib/GH_15109/Bpack.pm test Module for caller.t
t/lib/GH_15109/Cpack.pm test Module for caller.t
t/lib/GH_15109/Foo.pm test Module for caller.t
t/lib/h2ph.h Test header file for h2ph
t/lib/h2ph.pht Generated output from h2ph.h by h2ph, for comparison
t/lib/locale/latin1 Part of locale.t in Latin 1
Expand Down
23 changes: 22 additions & 1 deletion op.c
Original file line number Diff line number Diff line change
Expand Up @@ -11742,10 +11742,31 @@ S_process_special_blocks(pTHX_ I32 floor, const char *const fullname,
(void)CvGV(cv);
if (floor) LEAVE_SCOPE(floor);
ENTER;

SAVEVPTR(PL_curcop);
if (PL_curcop == &PL_compiling) {
/* Avoid pushing the "global" &PL_compiling onto the
* context stack. For example, a stack trace inside
* nested use's would show all calls coming from whoever
* most recently updated PL_compiling.cop_file and
* cop_line. So instead, temporarily set PL_curcop to a
* private copy of &PL_compiling. PL_curcop will soon be
* set to point back to &PL_compiling anyway but only
* after the temp value has been pushed onto the context
* stack as blk_oldcop.
* This is slightly hacky, but necessary. Note also
* that in the brief window before PL_curcop is set back
* to PL_compiling, IN_PERL_COMPILETIME/IN_PERL_RUNTIME
* will give the wrong answer.
*/
PL_curcop = (COP*)newSTATEOP(PL_compiling.op_flags, NULL, NULL);
CopLINE_set(PL_curcop, CopLINE(&PL_compiling));
SAVEFREEOP(PL_curcop);
}

PUSHSTACKi(PERLSI_REQUIRE);
SAVECOPFILE(&PL_compiling);
SAVECOPLINE(&PL_compiling);
SAVEVPTR(PL_curcop);

DEBUG_x( dump_sub(gv) );
Perl_av_create_and_push(aTHX_ &PL_beginav, MUTABLE_SV(cv));
Expand Down
12 changes: 12 additions & 0 deletions pod/perlvar.pod
Original file line number Diff line number Diff line change
Expand Up @@ -1879,6 +1879,10 @@ It has the same scoping as the C<$^H> and C<%^H> variables. The exact
values are considered internal to the L<warnings> pragma and may change
between versions of Perl.

Each time a statement completes being compiled, the current value of
C<${^WARNING_BITS}> is stored with that statement, and can later be
retrieved via C<(caller($level))[9]>.

This variable was added in Perl v5.6.0.

=item $OS_ERROR
Expand Down Expand Up @@ -2175,6 +2179,10 @@ This variable contains compile-time hints for the Perl interpreter. At the
end of compilation of a BLOCK the value of this variable is restored to the
value when the interpreter started to compile the BLOCK.

Each time a statement completes being compiled, the current value of
C<$^H> is stored with that statement, and can later be retrieved via
C<(caller($level))[8]>.

When perl begins to parse any block construct that provides a lexical scope
(e.g., eval body, required file, subroutine body, loop body, or conditional
block), the existing value of C<$^H> is saved, but its value is left unchanged.
Expand Down Expand Up @@ -2223,6 +2231,10 @@ L<perlpragma>. All the entries are stringified when accessed at
runtime, so only simple values can be accommodated. This means no
pointers to objects, for example.

Each time a statement completes being compiled, the current value of
C<%^H> is stored with that statement, and can later be retrieved via
C<(caller($level))[10]>.

When putting items into C<%^H>, in order to avoid conflicting with other
users of the hash there is a convention regarding which keys to use.
A module should use only keys that begin with the module's name (the
Expand Down
4 changes: 4 additions & 0 deletions t/lib/GH_15109/Apack.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# for use by caller.t for GH #15109
package Apack;
use Bpack;
1;
4 changes: 4 additions & 0 deletions t/lib/GH_15109/Bpack.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# for use by caller.t for GH #15109
package Bpack;
use Cpack;
1;
11 changes: 11 additions & 0 deletions t/lib/GH_15109/Cpack.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# for use by caller.t for GH #15109
package Cpack;


my $i = 0;

while (my ($package, $file, $line) = caller($i++)) {
push @Cpack::callers, "$file:$line";
}

1;
9 changes: 9 additions & 0 deletions t/lib/GH_15109/Foo.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# for use by caller.t for GH #15109

package Foo;

sub import {
use warnings; # restore default warnings
() = caller(1); # this used to cause valgrind errors
}
1;
39 changes: 34 additions & 5 deletions t/op/caller.t
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ BEGIN {
chdir 't' if -d 't';
require './test.pl';
set_up_inc('../lib');
plan( tests => 97 ); # some tests are run in a BEGIN block
plan( tests => 111 ); # some tests are run in a BEGIN block
}

my @c;
Expand Down Expand Up @@ -335,16 +335,45 @@ $::testing_caller = 1;

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

# GH #15109
# See that callers within a nested series of 'use's gets the right
# filenames.
{
local @INC = 'lib/GH_15109/';
# Apack use's Bpack which use's Cpack which populates @Cpack::caller
# with the file:N of all the callers
eval 'use Apack; 1';
is($@, "", "GH #15109 - eval");
is (scalar(@Cpack::callers), 10, "GH #15109 - callers count");
like($Cpack::callers[$_], qr{GH_15109/Bpack.pm:3}, "GH #15109 level $_") for 0..2;
like($Cpack::callers[$_], qr{GH_15109/Apack.pm:3}, "GH #15109 level $_") for 3..5;
like($Cpack::callers[$_], qr{\(eval \d+\):1}, "GH #15109 level $_") for 6..8;
like($Cpack::callers[$_], qr{caller\.t}, "GH #15109 level $_") for 9;

# GH #15109 followup - the original fix wasn't saving cop_warnings
# correctly and this code used to crash or fail valgrind

my $w = 0;
local $SIG{__WARN__} = sub { $w++ };
eval q{
use warnings;
no warnings 'numeric'; # ensure custom cop_warnings
use Foo; # this used to mess up warnings flags
BEGIN { my $x = "foo" + 1; } # potential "numeric" warning
};
is ($@, "", "GH #15109 - eval okay");
is ($w, 0, "GH #15109 - warnings restored");
}

{
package RT129239;
BEGIN {
my ($pkg, $file, $line) = caller;
::is $file, 'virtually/op/caller.t', "BEGIN block sees correct caller filename";
::is $line, 12345, "BEGIN block sees correct caller line";
TODO: {
local $::TODO = "BEGIN blocks have wrong caller package [perl #129239]";
::is $pkg, 'RT129239', "BEGIN block sees correct caller package";
}
::is $pkg, 'RT129239', "BEGIN block sees correct caller package";
#line 12345 "virtually/op/caller.t"
}

}