Skip to content
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

Referencing a PADTMP twice produces two copies #10690

Closed
p5pRT opened this issue Oct 3, 2010 · 37 comments
Closed

Referencing a PADTMP twice produces two copies #10690

p5pRT opened this issue Oct 3, 2010 · 37 comments

Comments

@p5pRT
Copy link

p5pRT commented Oct 3, 2010

Migrated from rt.perl.org#78194 (status was 'resolved')

Searchable as RT78194$

@p5pRT
Copy link
Author

p5pRT commented Oct 3, 2010

From @cpansprout

$ perl -le' for( "$y" ){print \$_.\$_}'
SCALAR(0x8039f0)SCALAR(0x8038d0)

(The same address should be printed twice.)

It looks as though the TARG ought to be stolen by S_refto, and then replaced via pad_swipe or something similar.


Flags​:
  category=core
  severity=low


Site configuration information for perl 5.13.5​:

Configured by sprout at Mon Sep 27 23​:15​:22 PDT 2010.

Summary of my perl5 (revision 5 version 13 subversion 5) configuration​:
  Commit id​: 3eab78e
  Platform​:
  osname=darwin, osvers=10.4.0, archname=darwin-thread-multi-2level
  uname='darwin pint.local 10.4.0 darwin kernel version 10.4.0​: fri apr 23 18​:28​:53 pdt 2010; root​:xnu-1504.7.4~1release_i386 i386 '
  config_args='-de -Dusedevel -Duseithreads -DDEBUGGING'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=define, usemultiplicity=define
  useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
  use64bitint=undef, use64bitall=undef, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-fno-common -DPERL_DARWIN -no-cpp-precomp -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include',
  optimize='-O3 -g',
  cppflags='-no-cpp-precomp -fno-common -DPERL_DARWIN -no-cpp-precomp -DDEBUGGING -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.2.1 (Apple Inc. build 5664)', gccosandvers=''
  intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
  ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib
  libs=-ldbm -ldl -lm -lutil -lc
  perllibs=-ldl -lm -lutil -lc
  libc=/usr/lib/libc.dylib, so=dylib, useshrplib=false, libperl=libperl.a
  gnulibc_version=''
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
  cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup -L/usr/local/lib -fstack-protector'

Locally applied patches​:
 


@​INC for perl 5.13.5​:
  /usr/local/lib/perl5/site_perl/5.13.5/darwin-thread-multi-2level
  /usr/local/lib/perl5/site_perl/5.13.5
  /usr/local/lib/perl5/5.13.5/darwin-thread-multi-2level
  /usr/local/lib/perl5/5.13.5
  /usr/local/lib/perl5/site_perl
  .


Environment for perl 5.13.5​:
  DYLD_LIBRARY_PATH (unset)
  HOME=/Users/sprout
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/X11/bin​:/usr/local/bin
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jun 5, 2011

From @cpansprout

On Sun Oct 03 14​:08​:37 2010, sprout wrote​:

$ perl -le' for( "$y" ){print \$_.\$_}'
SCALAR(0x8039f0)SCALAR(0x8038d0)

(The same address should be printed twice.)

It looks as though the TARG ought to be stolen by S_refto, and then
replaced via pad_swipe or something similar.

It might be cleaner for not only S_refto, but also any op that aliases a
PADTMP to copy it. That would include for, map, grep, arguments to
subroutines, and the lhs of (...)x...

@p5pRT
Copy link
Author

p5pRT commented Jun 5, 2011

From [Unknown Contact. See original ticket]

On Sun Oct 03 14​:08​:37 2010, sprout wrote​:

$ perl -le' for( "$y" ){print \$_.\$_}'
SCALAR(0x8039f0)SCALAR(0x8038d0)

(The same address should be printed twice.)

It looks as though the TARG ought to be stolen by S_refto, and then
replaced via pad_swipe or something similar.

It might be cleaner for not only S_refto, but also any op that aliases a
PADTMP to copy it. That would include for, map, grep, arguments to
subroutines, and the lhs of (...)x...

@p5pRT
Copy link
Author

p5pRT commented Jun 5, 2011

@cpansprout - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jan 8, 2012

From @cpansprout

On Sun Jun 05 16​:04​:53 2011, sprout wrote​:

On Sun Oct 03 14​:08​:37 2010, sprout wrote​:

$ perl -le' for( "$y" ){print \$_.\$_}'
SCALAR(0x8039f0)SCALAR(0x8038d0)

(The same address should be printed twice.)

It looks as though the TARG ought to be stolen by S_refto, and then
replaced via pad_swipe or something similar.

It might be cleaner for not only S_refto, but also any op that aliases a
PADTMP to copy it. That would include for, map, grep, arguments to
subroutines, and the lhs of (...)x...

Here is a difficult case​:

$ ./perl -Ilib -e 'use Devel​::Peek; "$_" =~ /(?{ Dump $_ })/;'
SV = PVMG(0x824b78) at 0x826ba0
  REFCNT = 1
  FLAGS = (PADTMP,SMG,POK,pPOK)
...

Fixing the operators I mentioned above is easy. Fixing patterns without
a speed hit (since regexps are used so often) is not so easy.

Are regular expressions with code blocks in them flagged somehow, so we
can avoid making a copy for every PADTMP =~ // ?

In case it’s not obvious, this is the bug I’m trying to fix​:

$ ./perl -Ilib -le '"$_" =~ /(?{ print \$_; print \$_ })/;'
SCALAR(0x803a10)
SCALAR(0x803b50)

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 8, 2012

From [Unknown Contact. See original ticket]

On Sun Jun 05 16​:04​:53 2011, sprout wrote​:

On Sun Oct 03 14​:08​:37 2010, sprout wrote​:

$ perl -le' for( "$y" ){print \$_.\$_}'
SCALAR(0x8039f0)SCALAR(0x8038d0)

(The same address should be printed twice.)

It looks as though the TARG ought to be stolen by S_refto, and then
replaced via pad_swipe or something similar.

It might be cleaner for not only S_refto, but also any op that aliases a
PADTMP to copy it. That would include for, map, grep, arguments to
subroutines, and the lhs of (...)x...

Here is a difficult case​:

$ ./perl -Ilib -e 'use Devel​::Peek; "$_" =~ /(?{ Dump $_ })/;'
SV = PVMG(0x824b78) at 0x826ba0
  REFCNT = 1
  FLAGS = (PADTMP,SMG,POK,pPOK)
...

Fixing the operators I mentioned above is easy. Fixing patterns without
a speed hit (since regexps are used so often) is not so easy.

Are regular expressions with code blocks in them flagged somehow, so we
can avoid making a copy for every PADTMP =~ // ?

In case it’s not obvious, this is the bug I’m trying to fix​:

$ ./perl -Ilib -le '"$_" =~ /(?{ print \$_; print \$_ })/;'
SCALAR(0x803a10)
SCALAR(0x803b50)

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jan 13, 2012

From @iabyn

On Sun, Jan 08, 2012 at 02​:21​:34PM -0800, Father Chrysostomos via RT wrote​:

On Sun Jun 05 16​:04​:53 2011, sprout wrote​:

On Sun Oct 03 14​:08​:37 2010, sprout wrote​:

$ perl -le' for( "$y" ){print \$_.\$_}'
SCALAR(0x8039f0)SCALAR(0x8038d0)

(The same address should be printed twice.)

It looks as though the TARG ought to be stolen by S_refto, and then
replaced via pad_swipe or something similar.

It might be cleaner for not only S_refto, but also any op that aliases a
PADTMP to copy it. That would include for, map, grep, arguments to
subroutines, and the lhs of (...)x...

Here is a difficult case​:

$ ./perl -Ilib -e 'use Devel​::Peek; "$_" =~ /(?{ Dump $_ })/;'
SV = PVMG(0x824b78) at 0x826ba0
REFCNT = 1
FLAGS = (PADTMP,SMG,POK,pPOK)
...

Fixing the operators I mentioned above is easy. Fixing patterns without
a speed hit (since regexps are used so often) is not so easy.

Are regular expressions with code blocks in them flagged somehow, so we
can avoid making a copy for every PADTMP =~ // ?

yes, RXf_EVAL_SEEN. It's used at the start of S_regtry to decide whether
to alias $_ (and PL_reg_eval_set is then set, to avoid doing it multiple
times).

In case it’s not obvious, this is the bug I’m trying to fix​:

$ ./perl -Ilib -le '"$_" =~ /(?{ print \$_; print \$_ })/;'
SCALAR(0x803a10)
SCALAR(0x803b50)

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

Confused the hell out me! :-) I didn't realise until I looked at it just
now, that $_ is aliased within code blocks.

--
Gravity is just a theory; teach Intelligent Falling in our schools!
  http​://www.theonion.com/content/node/39512

@p5pRT
Copy link
Author

p5pRT commented Jan 13, 2012

From patcat88@snet.net

On Sun Jan 08 14​:21​:34 2012, sprout wrote​:
................................

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

I'll add my PerlMonks discussion to this
http​://www.perlmonks.org/?node_id=941973 . PADTMPs should always be
copied (or sv body stolen ??), not referenced. srefgen/S_refto and newRV
do different things but they should be the same. PADTMPs are supposed to
be allocated and dealloced on block enterance/leaving, but under the
hood are effectively closures or C function level static. Its a mess.

@p5pRT
Copy link
Author

p5pRT commented Jan 13, 2012

From [Unknown Contact. See original ticket]

On Sun Jan 08 14​:21​:34 2012, sprout wrote​:
................................

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

I'll add my PerlMonks discussion to this
http​://www.perlmonks.org/?node_id=941973 . PADTMPs should always be
copied (or sv body stolen ??), not referenced. srefgen/S_refto and newRV
do different things but they should be the same. PADTMPs are supposed to
be allocated and dealloced on block enterance/leaving, but under the
hood are effectively closures or C function level static. Its a mess.

@p5pRT
Copy link
Author

p5pRT commented Jun 15, 2013

From @cpansprout

This is related to #7505, which is one instance of this bug.

@p5pRT
Copy link
Author

p5pRT commented Jun 15, 2013

From [Unknown Contact. See original ticket]

This is related to #7505, which is one instance of this bug.

@p5pRT
Copy link
Author

p5pRT commented Jun 16, 2013

From @cpansprout

On Sat Jun 15 13​:49​:57 2013, sprout wrote​:

This is related to #7505, which is one instance of this bug.

Um, nope, it’s not. Ignore that.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jun 16, 2013

From [Unknown Contact. See original ticket]

On Sat Jun 15 13​:49​:57 2013, sprout wrote​:

This is related to #7505, which is one instance of this bug.

Um, nope, it’s not. Ignore that.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 26, 2013

From @cpansprout

Fixed in​:

a0ed822
b479c9f
8e079c2
706a6eb
da9e430
2b66f6d
82c2360

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 26, 2013

From [Unknown Contact. See original ticket]

Fixed in​:

a0ed822
b479c9f
8e079c2
706a6eb
da9e430
2b66f6d
82c2360

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 26, 2013

@cpansprout - Status changed from 'open' to 'resolved'

@p5pRT
Copy link
Author

p5pRT commented Jul 27, 2013

From @cpansprout

On Fri Jan 13 13​:16​:42 2012, patcat88 wrote​:

On Sun Jan 08 14​:21​:34 2012, sprout wrote​:
................................

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

I'll add my PerlMonks discussion to this
http​://www.perlmonks.org/?node_id=941973 . PADTMPs should always be
copied (or sv body stolen ??), not referenced. srefgen/S_refto and newRV
do different things but they should be the same. PADTMPs are supposed to
be allocated and dealloced on block enterance/leaving, but under the
hood are effectively closures or C function level static. Its a mess.

This part is not resolved. I’m reopening it.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 27, 2013

From [Unknown Contact. See original ticket]

On Fri Jan 13 13​:16​:42 2012, patcat88 wrote​:

On Sun Jan 08 14​:21​:34 2012, sprout wrote​:
................................

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

I'll add my PerlMonks discussion to this
http​://www.perlmonks.org/?node_id=941973 . PADTMPs should always be
copied (or sv body stolen ??), not referenced. srefgen/S_refto and newRV
do different things but they should be the same. PADTMPs are supposed to
be allocated and dealloced on block enterance/leaving, but under the
hood are effectively closures or C function level static. Its a mess.

This part is not resolved. I’m reopening it.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 27, 2013

@cpansprout - Status changed from 'resolved' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jul 27, 2013

From @cpansprout

On Fri Jul 26 23​:12​:23 2013, sprout wrote​:

On Fri Jan 13 13​:16​:42 2012, patcat88 wrote​:

On Sun Jan 08 14​:21​:34 2012, sprout wrote​:
................................

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

I'll add my PerlMonks discussion to this
http​://www.perlmonks.org/?node_id=941973 . PADTMPs should always be
copied (or sv body stolen ??), not referenced. srefgen/S_refto and newRV
do different things but they should be the same. PADTMPs are supposed to
be allocated and dealloced on block enterance/leaving, but under the
hood are effectively closures or C function level static. Its a mess.

This part is not resolved. I’m reopening it.

I did not fix this bug for calls to XSUBs, because it will make
Devel​::Peek less useful. Calling Dump("$x") and being able to see what
pp_stringify is return is a useful feature.

(Here I’m referring to the original bug reported, not the newRV issue.
Calling foo("$x") allowed the foo sub to see a TARG in $_[0], such that
print \$_[0], \$_[0] would show two different addresses.)

Currently foo("$x") will make a COW copy of the TARG if it is a Perl
sub, but pass the TARG itself if it is an XSUB. So for XS code to call
newRV on that is wrong (or what newRV does is wrong).

I think the real solution here is to apply the fix to XSUBs (copy TARG
arguments) but modify Devel​::Peek to inline itself, so that it remains
exempt.

That way the only XS code having access to TARGs will be that which
rummages through pads. For most XS code this will just dwim.

In fact, having Devel​::Peek inline itself would be useful for seeing the
return value of substr and vec in rvalue context, something currently
not possible.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Jul 27, 2013

From [Unknown Contact. See original ticket]

On Fri Jul 26 23​:12​:23 2013, sprout wrote​:

On Fri Jan 13 13​:16​:42 2012, patcat88 wrote​:

On Sun Jan 08 14​:21​:34 2012, sprout wrote​:
................................

Taking a reference to $_ twice should not create references to two
different variables. The implementation details are leaking through.

I'll add my PerlMonks discussion to this
http​://www.perlmonks.org/?node_id=941973 . PADTMPs should always be
copied (or sv body stolen ??), not referenced. srefgen/S_refto and newRV
do different things but they should be the same. PADTMPs are supposed to
be allocated and dealloced on block enterance/leaving, but under the
hood are effectively closures or C function level static. Its a mess.

This part is not resolved. I’m reopening it.

I did not fix this bug for calls to XSUBs, because it will make
Devel​::Peek less useful. Calling Dump("$x") and being able to see what
pp_stringify is return is a useful feature.

(Here I’m referring to the original bug reported, not the newRV issue.
Calling foo("$x") allowed the foo sub to see a TARG in $_[0], such that
print \$_[0], \$_[0] would show two different addresses.)

Currently foo("$x") will make a COW copy of the TARG if it is a Perl
sub, but pass the TARG itself if it is an XSUB. So for XS code to call
newRV on that is wrong (or what newRV does is wrong).

I think the real solution here is to apply the fix to XSUBs (copy TARG
arguments) but modify Devel​::Peek to inline itself, so that it remains
exempt.

That way the only XS code having access to TARGs will be that which
rummages through pads. For most XS code this will just dwim.

In fact, having Devel​::Peek inline itself would be useful for seeing the
return value of substr and vec in rvalue context, something currently
not possible.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 12, 2013

From @cpansprout

On Sat Jul 27 11​:27​:57 2013, sprout wrote​:

I did not fix this bug for calls to XSUBs, because it will make
Devel​::Peek less useful. Calling Dump("$x") and being able to see what
pp_stringify is return[ing] is a useful feature.

(Here I’m referring to the original bug reported, not the newRV issue.
Calling foo("$x") allowed the foo sub to see a TARG in $_[0], such that
print \$_[0], \$_[0] would show two different addresses.)

Currently foo("$x") will make a COW copy of the TARG if it is a Perl
sub, but pass the TARG itself if it is an XSUB. So for XS code to call
newRV on that is wrong (or what newRV does is wrong).

I think the real solution here is to apply the fix to XSUBs (copy TARG
arguments) but modify Devel​::Peek to inline itself, so that it remains
exempt.

That way the only XS code having access to TARGs will be that which
rummages through pads. For most XS code this will just dwim.

In fact, having Devel​::Peek inline itself would be useful for seeing the
return value of substr and vec in rvalue context, something currently
not possible.

Attached is a patch to get Devel​::Peek to inline itself. It also allows
Dump %hash and Dump @​array.

It breaks compatibility in that ‘@​args = ($thing, 5); Dump @​args’ no
longer works; scalar context is applied to both arguments now, and the
number of arguments is checked at compile time, rather than run time.

I still think it is worth it.

The patch can also be found on the sprout/peek branch.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 12, 2013

From @cpansprout

From b71bcee5cdd1e9dc06692914a330bb543cacc16b Mon Sep 17 00​:00​:00 2001
From​: Father Chrysostomos <sprout@​cpan.org>
Date​: Sun, 11 Aug 2013 21​:54​:11 -0700
Subject​: [PATCH] Inline Devel​::Peek​::Dump; allow Dump %hash etc.
MIME-Version​: 1.0
Content-Type​: text/plain; charset=UTF-8
Content-Transfer-Encoding​: 8bit

This commit makes Devel​::Peek​::Dump modify the op tree to allow it to
dump arrays and hashes directly via Dump @​array and Dump %hash. It
also puts other operators in rvalue context, allowing the return value
of rvalue substr for instance to be dumped, making Devel​::Peek more
useful as a debugging tool.

Since a future commit (to fix the rest of #78194) is likely to make
pp_entersub copy PADTMPs (operator return values) for XSUBs (it
already happens for Perl subs as of b479c9f), to the detriment of
Devel​::Peek’s usefulness, I also made it inline Dump as a custom op.

This does introduce a backward-incompatible change, in that both argu-
ments to Dump are now in scalar context, and the number of arguments
is checked at compile time instead of run time (still run time for
&Dump(...)), but I think it is worth it.

Inline Patch
diff --git a/ext/Devel-Peek/Peek.xs b/ext/Devel-Peek/Peek.xs
index 4c5f974..edcb02f 100644
--- a/ext/Devel-Peek/Peek.xs
+++ b/ext/Devel-Peek/Peek.xs
@@ -323,6 +323,94 @@ mstats2hash(SV *sv, SV *rv, int level)
 	(SvROK(cv) && (SvTYPE(SvRV(cv))==SVt_PVCV)	\
 	 ? SvREFCNT_inc(CvGV((CV*)SvRV(cv))) : &PL_sv_undef)
 
+static void
+S_do_dump(pTHX_ SV *const sv, I32 lim)
+{
+    dVAR;
+    SV *pv_lim_sv = perl_get_sv("Devel::Peek::pv_limit", 0);
+    const STRLEN pv_lim = pv_lim_sv ? SvIV(pv_lim_sv) : 0;
+    SV *dumpop = perl_get_sv("Devel::Peek::dump_ops", 0);
+    const U16 save_dumpindent = PL_dumpindent;
+    PL_dumpindent = 2;
+    do_sv_dump(0, Perl_debug_log, sv, 0, lim,
+	       (bool)(dumpop && SvTRUE(dumpop)), pv_lim);
+    PL_dumpindent = save_dumpindent;
+}
+
+static OP *
+S_pp_dump(pTHX)
+{
+    dSP;
+    const I32 lim = PL_op->op_private == 2 ? (I32)POPi : 4;
+    dPOPss;
+    S_do_dump(aTHX_ sv, lim);
+    RETPUSHUNDEF;
+}
+
+static OP *
+S_ck_dump(pTHX_ OP *entersubop, GV *namegv, SV *cv)
+{
+    OP *aop, *prev, *first, *second = NULL;
+    BINOP *newop;
+    size_t arg = 0;
+
+    ck_entersub_args_proto(entersubop, namegv,
+			   newSVpvn_flags("$;$", 3, SVs_TEMP));
+
+    aop = cUNOPx(entersubop)->op_first;
+    if (!aop->op_sibling)
+	aop = cUNOPx(aop)->op_first;
+    prev = aop;
+    aop = aop->op_sibling;
+    while (PL_madskills && aop->op_type == OP_STUB) {
+	prev = aop;
+	aop = aop->op_sibling;
+    }
+    if (PL_madskills && aop->op_type == OP_NULL) {
+	first = ((UNOP*)aop)->op_first;
+	((UNOP*)aop)->op_first = NULL;
+	prev = aop;
+    }
+    else {
+	first = aop;
+	prev->op_sibling = first->op_sibling;
+    }
+    if (first->op_type == OP_RV2AV ||
+	first->op_type == OP_PADAV ||
+	first->op_type == OP_RV2HV ||
+	first->op_type == OP_PADHV
+    )
+	first->op_flags |= OPf_REF;
+    else
+	first->op_flags &= ~OPf_MOD;
+    aop = aop->op_sibling;
+    while (PL_madskills && aop->op_type == OP_STUB) {
+	prev = aop;
+	aop = aop->op_sibling;
+    }
+    /* aop now points to the second arg if there is one, the cvop otherwise
+     */
+    if ((prev->op_sibling = aop->op_sibling)) {
+	second = aop;
+	second->op_sibling = NULL;
+    }
+    first->op_sibling = second;
+
+    op_free(entersubop);
+
+    NewOp(1234, newop, 1, BINOP);
+    newop->op_type   = OP_CUSTOM;
+    newop->op_ppaddr = S_pp_dump;
+    newop->op_first  = first;
+    newop->op_last   = second;
+    newop->op_private= second ? 2 : 1;
+    newop->op_flags  = OPf_KIDS|OPf_WANT_SCALAR;
+
+    return (OP *)newop;
+}
+
+static XOP my_xop;
+
 MODULE = Devel::Peek		PACKAGE = Devel::Peek
 
 void
@@ -346,14 +434,18 @@ SV *	sv
 I32	lim
 PPCODE:
 {
-    SV *pv_lim_sv = perl_get_sv("Devel::Peek::pv_limit", 0);
-    const STRLEN pv_lim = pv_lim_sv ? SvIV(pv_lim_sv) : 0;
-    SV *dumpop = perl_get_sv("Devel::Peek::dump_ops", 0);
-    const U16 save_dumpindent = PL_dumpindent;
-    PL_dumpindent = 2;
-    do_sv_dump(0, Perl_debug_log, sv, 0, lim,
-	       (bool)(dumpop && SvTRUE(dumpop)), pv_lim);
-    PL_dumpindent = save_dumpindent;
+    S_do_dump(aTHX_ sv, lim);
+}
+
+BOOT:
+{
+    CV * const cv = get_cvn_flags("Devel::Peek::Dump", 17, 0);
+    cv_set_call_checker(cv, S_ck_dump, (SV *)cv);
+
+    XopENTRY_set(&my_xop, xop_name, "Dump");
+    XopENTRY_set(&my_xop, xop_desc, "Dump");
+    XopENTRY_set(&my_xop, xop_class, OA_BINOP);
+    Perl_custom_op_register(aTHX_ S_pp_dump, &my_xop);
 }
 
 void
diff --git a/ext/Devel-Peek/t/Peek.t b/ext/Devel-Peek/t/Peek.t
index 088f505..1f344df 100644
--- a/ext/Devel-Peek/t/Peek.t
+++ b/ext/Devel-Peek/t/Peek.t
@@ -31,11 +31,24 @@ sub do_test {
     my $todo = $_[3];
     my $repeat_todo = $_[4];
     my $pattern = $_[2];
+    my $do_eval = $_[5];
     if (open(OUT,">peek$$")) {
 	open(STDERR, ">&OUT") or die "Can't dup OUT: $!";
-	Dump($_[1]);
-        print STDERR "*****\n";
-        Dump($_[1]); # second dump to compare with the first to make sure nothing changed.
+        if ($do_eval) {
+            my $sub = eval "sub { Dump $_[1] }";
+            $sub->();
+            print STDERR "*****\n";
+            # second dump to compare with the first to make sure nothing
+            # changed.
+            $sub->();
+        }
+        else {
+            Dump($_[1]);
+            print STDERR "*****\n";
+            # second dump to compare with the first to make sure nothing
+            # changed.
+            Dump($_[1]);
+        }
 	open(STDERR, ">&SAVERR") or die "Can't restore STDERR: $!";
 	close(OUT);
 	if (open(IN, "peek$$")) {
@@ -196,8 +209,8 @@ do_test('integer constant',
 do_test('undef',
         undef,
 'SV = NULL\\(0x0\\) at $ADDR
-  REFCNT = 1
-  FLAGS = \\(\\)');
+  REFCNT = \d+
+  FLAGS = \\(READONLY\\)');
 
 do_test('reference to scalar',
         \$a,
@@ -335,6 +348,8 @@ do_test('reference to named subroutine without prototype',
        \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$todo"
        \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$repeat_todo"
        \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$pattern"
+       \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$do_eval"
+      \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$sub"
       \\d+\\. $ADDR<\\d+> FAKE "\\$DEBUG"			# $] < 5.009
       \\d+\\. $ADDR<\\d+> FAKE "\\$DEBUG" flags=0x0 index=0	# $] >= 5.009
       \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$dump"
@@ -968,6 +983,59 @@ do_test('large hash',
     Elt .*
 ');
 
+# Dump with arrays, hashes, and operator return values
+@array = 1..3;
+do_test('Dump @array', '@array', <<'ARRAY', '', '', 1);
+SV = PVAV\($ADDR\) at $ADDR
+  REFCNT = 1
+  FLAGS = \(\)
+  ARRAY = $ADDR
+  FILL = 2
+  MAX = 3
+  ARYLEN = 0x0
+  FLAGS = \(REAL\)
+  Elt No. 0
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 1
+  Elt No. 1
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 2
+  Elt No. 2
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 3
+ARRAY
+%hash = 1..2;
+do_test('Dump %hash', '%hash', <<'HASH', '', '', 1);
+SV = PVHV\($ADDR\) at $ADDR
+  REFCNT = 1
+  FLAGS = \(SHAREKEYS\)
+  ARRAY = $ADDR  \(0:7, 1:1\)
+  hash quality = 100.0%
+  KEYS = 1
+  FILL = 1
+  MAX = 7
+  Elt "1" HASH = $ADDR
+  SV = IV\($ADDR\) at $ADDR
+    REFCNT = 1
+    FLAGS = \(IOK,pIOK\)
+    IV = 2
+HASH
+$_ = "hello";
+do_test('rvalue substr', 'substr $_, 1, 2', <<'SUBSTR', '', '', 1);
+SV = PV\($ADDR\) at $ADDR
+  REFCNT = 1
+  FLAGS = \(PADTMP,POK,pPOK\)
+  PV = $ADDR "el"\\0
+  CUR = 2
+  LEN = 20
+SUBSTR
+
 SKIP: {
     skip "Not built with usemymalloc", 2
       unless $Config{usemymalloc} eq 'y';

@p5pRT
Copy link
Author

p5pRT commented Aug 12, 2013

From [Unknown Contact. See original ticket]

On Sat Jul 27 11​:27​:57 2013, sprout wrote​:

I did not fix this bug for calls to XSUBs, because it will make
Devel​::Peek less useful. Calling Dump("$x") and being able to see what
pp_stringify is return[ing] is a useful feature.

(Here I’m referring to the original bug reported, not the newRV issue.
Calling foo("$x") allowed the foo sub to see a TARG in $_[0], such that
print \$_[0], \$_[0] would show two different addresses.)

Currently foo("$x") will make a COW copy of the TARG if it is a Perl
sub, but pass the TARG itself if it is an XSUB. So for XS code to call
newRV on that is wrong (or what newRV does is wrong).

I think the real solution here is to apply the fix to XSUBs (copy TARG
arguments) but modify Devel​::Peek to inline itself, so that it remains
exempt.

That way the only XS code having access to TARGs will be that which
rummages through pads. For most XS code this will just dwim.

In fact, having Devel​::Peek inline itself would be useful for seeing the
return value of substr and vec in rvalue context, something currently
not possible.

Attached is a patch to get Devel​::Peek to inline itself. It also allows
Dump %hash and Dump @​array.

It breaks compatibility in that ‘@​args = ($thing, 5); Dump @​args’ no
longer works; scalar context is applied to both arguments now, and the
number of arguments is checked at compile time, rather than run time.

I still think it is worth it.

The patch can also be found on the sprout/peek branch.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 12, 2013

From @Hugmeir

On Mon, Aug 12, 2013 at 6​:00 AM, Father Chrysostomos via RT <
perlbug-comment@​perl.org> wrote​:

On Sat Jul 27 11​:27​:57 2013, sprout wrote​:

I did not fix this bug for calls to XSUBs, because it will make
Devel​::Peek less useful. Calling Dump("$x") and being able to see what
pp_stringify is return[ing] is a useful feature.

(Here I’m referring to the original bug reported, not the newRV issue.
Calling foo("$x") allowed the foo sub to see a TARG in $_[0], such that
print \$_[0], \$_[0] would show two different addresses.)

Currently foo("$x") will make a COW copy of the TARG if it is a Perl
sub, but pass the TARG itself if it is an XSUB. So for XS code to call
newRV on that is wrong (or what newRV does is wrong).

I think the real solution here is to apply the fix to XSUBs (copy TARG
arguments) but modify Devel​::Peek to inline itself, so that it remains
exempt.

That way the only XS code having access to TARGs will be that which
rummages through pads. For most XS code this will just dwim.

In fact, having Devel​::Peek inline itself would be useful for seeing the
return value of substr and vec in rvalue context, something currently
not possible.

Attached is a patch to get Devel​::Peek to inline itself. It also allows
Dump %hash and Dump @​array.

It breaks compatibility in that ‘@​args = ($thing, 5); Dump @​args’ no
longer works; scalar context is applied to both arguments now, and the
number of arguments is checked at compile time, rather than run time.

I still think it is worth it.

The patch can also be found on the sprout/peek branch.

This is unrelated to the thread, but I just wanted to say that looking over
your attached patch made me go "Oh, so THAT'S how you create a custom op!"
Thanks, Father C! This was educational.

About the patch itself, I have never written Dump(@​foo) and not meant
Dump(\@​foo), or Dump %hash and not meant Dump(\%hash), so the incompatible
change seems good to me.

--

Father Chrysostomos

From b71bcee5cdd1e9dc06692914a330bb543cacc16b Mon Sep 17 00​:00​:00 2001
From​: Father Chrysostomos <sprout@​cpan.org>
Date​: Sun, 11 Aug 2013 21​:54​:11 -0700
Subject​: [PATCH] Inline Devel​::Peek​::Dump; allow Dump %hash etc.
MIME-Version​: 1.0
Content-Type​: text/plain; charset=UTF-8
Content-Transfer-Encoding​: 8bit

This commit makes Devel​::Peek​::Dump modify the op tree to allow it to
dump arrays and hashes directly via Dump @​array and Dump %hash. It
also puts other operators in rvalue context, allowing the return value
of rvalue substr for instance to be dumped, making Devel​::Peek more
useful as a debugging tool.

Since a future commit (to fix the rest of #78194) is likely to make
pp_entersub copy PADTMPs (operator return values) for XSUBs (it
already happens for Perl subs as of b479c9f), to the detriment of
Devel​::Peek’s usefulness, I also made it inline Dump as a custom op.

This does introduce a backward-incompatible change, in that both argu-
ments to Dump are now in scalar context, and the number of arguments
is checked at compile time instead of run time (still run time for
&Dump(...)), but I think it is worth it.

diff --git a/ext/Devel-Peek/Peek.xs b/ext/Devel-Peek/Peek.xs
index 4c5f974..edcb02f 100644
--- a/ext/Devel-Peek/Peek.xs
+++ b/ext/Devel-Peek/Peek.xs
@​@​ -323,6 +323,94 @​@​ mstats2hash(SV *sv, SV *rv, int level)
(SvROK(cv) && (SvTYPE(SvRV(cv))==SVt_PVCV) \
? SvREFCNT_inc(CvGV((CV*)SvRV(cv))) : &PL_sv_undef)

+static void
+S_do_dump(pTHX_ SV *const sv, I32 lim)
+{
+ dVAR;
+ SV *pv_lim_sv = perl_get_sv("Devel​::Peek​::pv_limit", 0);
+ const STRLEN pv_lim = pv_lim_sv ? SvIV(pv_lim_sv) : 0;
+ SV *dumpop = perl_get_sv("Devel​::Peek​::dump_ops", 0);
+ const U16 save_dumpindent = PL_dumpindent;
+ PL_dumpindent = 2;
+ do_sv_dump(0, Perl_debug_log, sv, 0, lim,
+ (bool)(dumpop && SvTRUE(dumpop)), pv_lim);
+ PL_dumpindent = save_dumpindent;
+}
+
+static OP *
+S_pp_dump(pTHX)
+{
+ dSP;
+ const I32 lim = PL_op->op_private == 2 ? (I32)POPi : 4;
+ dPOPss;
+ S_do_dump(aTHX_ sv, lim);
+ RETPUSHUNDEF;
+}
+
+static OP *
+S_ck_dump(pTHX_ OP *entersubop, GV *namegv, SV *cv)
+{
+ OP *aop, *prev, *first, *second = NULL;
+ BINOP *newop;
+ size_t arg = 0;
+
+ ck_entersub_args_proto(entersubop, namegv,
+ newSVpvn_flags("$;$", 3, SVs_TEMP));
+
+ aop = cUNOPx(entersubop)->op_first;
+ if (!aop->op_sibling)
+ aop = cUNOPx(aop)->op_first;
+ prev = aop;
+ aop = aop->op_sibling;
+ while (PL_madskills && aop->op_type == OP_STUB) {
+ prev = aop;
+ aop = aop->op_sibling;
+ }
+ if (PL_madskills && aop->op_type == OP_NULL) {
+ first = ((UNOP*)aop)->op_first;
+ ((UNOP*)aop)->op_first = NULL;
+ prev = aop;
+ }
+ else {
+ first = aop;
+ prev->op_sibling = first->op_sibling;
+ }
+ if (first->op_type == OP_RV2AV ||
+ first->op_type == OP_PADAV ||
+ first->op_type == OP_RV2HV ||
+ first->op_type == OP_PADHV
+ )
+ first->op_flags |= OPf_REF;
+ else
+ first->op_flags &= ~OPf_MOD;
+ aop = aop->op_sibling;
+ while (PL_madskills && aop->op_type == OP_STUB) {
+ prev = aop;
+ aop = aop->op_sibling;
+ }
+ /* aop now points to the second arg if there is one, the cvop
otherwise
+ */
+ if ((prev->op_sibling = aop->op_sibling)) {
+ second = aop;
+ second->op_sibling = NULL;
+ }
+ first->op_sibling = second;
+
+ op_free(entersubop);
+
+ NewOp(1234, newop, 1, BINOP);
+ newop->op_type = OP_CUSTOM;
+ newop->op_ppaddr = S_pp_dump;
+ newop->op_first = first;
+ newop->op_last = second;
+ newop->op_private= second ? 2 : 1;
+ newop->op_flags = OPf_KIDS|OPf_WANT_SCALAR;
+
+ return (OP *)newop;
+}
+
+static XOP my_xop;
+
MODULE = Devel​::Peek PACKAGE = Devel​::Peek

void
@​@​ -346,14 +434,18 @​@​ SV * sv
I32 lim
PPCODE​:
{
- SV *pv_lim_sv = perl_get_sv("Devel​::Peek​::pv_limit", 0);
- const STRLEN pv_lim = pv_lim_sv ? SvIV(pv_lim_sv) : 0;
- SV *dumpop = perl_get_sv("Devel​::Peek​::dump_ops", 0);
- const U16 save_dumpindent = PL_dumpindent;
- PL_dumpindent = 2;
- do_sv_dump(0, Perl_debug_log, sv, 0, lim,
- (bool)(dumpop && SvTRUE(dumpop)), pv_lim);
- PL_dumpindent = save_dumpindent;
+ S_do_dump(aTHX_ sv, lim);
+}
+
+BOOT​:
+{
+ CV * const cv = get_cvn_flags("Devel​::Peek​::Dump", 17, 0);
+ cv_set_call_checker(cv, S_ck_dump, (SV *)cv);
+
+ XopENTRY_set(&my_xop, xop_name, "Dump");
+ XopENTRY_set(&my_xop, xop_desc, "Dump");
+ XopENTRY_set(&my_xop, xop_class, OA_BINOP);
+ Perl_custom_op_register(aTHX_ S_pp_dump, &my_xop);
}

void
diff --git a/ext/Devel-Peek/t/Peek.t b/ext/Devel-Peek/t/Peek.t
index 088f505..1f344df 100644
--- a/ext/Devel-Peek/t/Peek.t
+++ b/ext/Devel-Peek/t/Peek.t
@​@​ -31,11 +31,24 @​@​ sub do_test {
my $todo = $_[3];
my $repeat_todo = $_[4];
my $pattern = $_[2];
+ my $do_eval = $_[5];
if (open(OUT,">peek$$")) {
open(STDERR, ">&OUT") or die "Can't dup OUT​: $!";
- Dump($_[1]);
- print STDERR "*****\n";
- Dump($_[1]); # second dump to compare with the first to make sure
nothing changed.
+ if ($do_eval) {
+ my $sub = eval "sub { Dump $_[1] }";
+ $sub->();
+ print STDERR "*****\n";
+ # second dump to compare with the first to make sure nothing
+ # changed.
+ $sub->();
+ }
+ else {
+ Dump($_[1]);
+ print STDERR "*****\n";
+ # second dump to compare with the first to make sure nothing
+ # changed.
+ Dump($_[1]);
+ }
open(STDERR, ">&SAVERR") or die "Can't restore STDERR​: $!";
close(OUT);
if (open(IN, "peek$$")) {
@​@​ -196,8 +209,8 @​@​ do_test('integer constant',
do_test('undef',
undef,
'SV = NULL\\(0x0\\) at $ADDR
- REFCNT = 1
- FLAGS = \\(\\)');
+ REFCNT = \d+
+ FLAGS = \\(READONLY\\)');

do_test('reference to scalar',
\$a,
@​@​ -335,6 +348,8 @​@​ do_test('reference to named subroutine without
prototype',
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$todo"
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$repeat_todo"
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$pattern"
+ \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$do_eval"
+ \\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$sub"
\\d+\\. $ADDR&lt;\\d+&gt; FAKE "\\$DEBUG" # $] <
5.009
\\d+\\. $ADDR&lt;\\d+&gt; FAKE "\\$DEBUG" flags=0x0 index=0 # $] >=
5.009
\\d+\\. $ADDR<\\d+> \\(\\d+,\\d+\\) "\\$dump"
@​@​ -968,6 +983,59 @​@​ do_test('large hash',
Elt .*
');

+# Dump with arrays, hashes, and operator return values
+@​array = 1..3;
+do_test('Dump @​array', '@​array', <<'ARRAY', '', '', 1);
+SV = PVAV\($ADDR\) at $ADDR
+ REFCNT = 1
+ FLAGS = \(\)
+ ARRAY = $ADDR
+ FILL = 2
+ MAX = 3
+ ARYLEN = 0x0
+ FLAGS = \(REAL\)
+ Elt No. 0
+ SV = IV\($ADDR\) at $ADDR
+ REFCNT = 1
+ FLAGS = \(IOK,pIOK\)
+ IV = 1
+ Elt No. 1
+ SV = IV\($ADDR\) at $ADDR
+ REFCNT = 1
+ FLAGS = \(IOK,pIOK\)
+ IV = 2
+ Elt No. 2
+ SV = IV\($ADDR\) at $ADDR
+ REFCNT = 1
+ FLAGS = \(IOK,pIOK\)
+ IV = 3
+ARRAY
+%hash = 1..2;
+do_test('Dump %hash', '%hash', <<'HASH', '', '', 1);
+SV = PVHV\($ADDR\) at $ADDR
+ REFCNT = 1
+ FLAGS = \(SHAREKEYS\)
+ ARRAY = $ADDR \(0​:7, 1​:1\)
+ hash quality = 100.0%
+ KEYS = 1
+ FILL = 1
+ MAX = 7
+ Elt "1" HASH = $ADDR
+ SV = IV\($ADDR\) at $ADDR
+ REFCNT = 1
+ FLAGS = \(IOK,pIOK\)
+ IV = 2
+HASH
+$_ = "hello";
+do_test('rvalue substr', 'substr $_, 1, 2', <<'SUBSTR', '', '', 1);
+SV = PV\($ADDR\) at $ADDR
+ REFCNT = 1
+ FLAGS = \(PADTMP,POK,pPOK\)
+ PV = $ADDR "el"\\0
+ CUR = 2
+ LEN = 20
+SUBSTR
+
SKIP​: {
skip "Not built with usemymalloc", 2
unless $Config{usemymalloc} eq 'y';

@p5pRT
Copy link
Author

p5pRT commented Aug 12, 2013

From @cpansprout

On Mon Aug 12 12​:24​:53 2013, Hugmeir wrote​:

This is unrelated to the thread, but I just wanted to say that looking
over
your attached patch made me go "Oh, so THAT'S how you create a custom op!"
Thanks, Father C! This was educational.

I just copied bits of XS​::APItest and ck_entersub_args_proto. :-)

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 12, 2013

From [Unknown Contact. See original ticket]

On Mon Aug 12 12​:24​:53 2013, Hugmeir wrote​:

This is unrelated to the thread, but I just wanted to say that looking
over
your attached patch made me go "Oh, so THAT'S how you create a custom op!"
Thanks, Father C! This was educational.

I just copied bits of XS​::APItest and ck_entersub_args_proto. :-)

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 12, 2013

From @ikegami

On Mon, Aug 12, 2013 at 3​:24 PM, Brian Fraser <fraserbn@​gmail.com> wrote​:

This is unrelated to the thread, but I just wanted to say that looking
over your attached patch made me go "Oh, so THAT'S how you create a custom
op!"
Thanks, Father C! This was educational.

See also​: Syntax​::Feature​::Loop
http​://search.cpan.org/perldoc?Syntax​::Feature​::Loop

@p5pRT
Copy link
Author

p5pRT commented Aug 12, 2013

From @ikegami

oops, nevermind. That demonstrates custom keywords, custom parsing,
inlining of subs and lexical scoping of subs, but not custom ops.

On Mon, Aug 12, 2013 at 3​:49 PM, Eric Brine <ikegami@​adaelis.com> wrote​:

On Mon, Aug 12, 2013 at 3​:24 PM, Brian Fraser <fraserbn@​gmail.com> wrote​:

This is unrelated to the thread, but I just wanted to say that looking
over your attached patch made me go "Oh, so THAT'S how you create a custom
op!"
Thanks, Father C! This was educational.

See also​: Syntax​::Feature​::Loop
http​://search.cpan.org/perldoc?Syntax​::Feature​::Loop

@p5pRT
Copy link
Author

p5pRT commented Aug 13, 2013

From @cpansprout

On Mon Aug 12 02​:00​:18 2013, sprout wrote​:

On Sat Jul 27 11​:27​:57 2013, sprout wrote​:

I did not fix this bug for calls to XSUBs, because it will make
Devel​::Peek less useful. Calling Dump("$x") and being able to see what
pp_stringify is return[ing] is a useful feature.

(Here I’m referring to the original bug reported, not the newRV issue.
Calling foo("$x") allowed the foo sub to see a TARG in $_[0], such that
print \$_[0], \$_[0] would show two different addresses.)

Currently foo("$x") will make a COW copy of the TARG if it is a Perl
sub, but pass the TARG itself if it is an XSUB. So for XS code to call
newRV on that is wrong (or what newRV does is wrong).

I think the real solution here is to apply the fix to XSUBs (copy TARG
arguments) but modify Devel​::Peek to inline itself, so that it remains
exempt.

That way the only XS code having access to TARGs will be that which
rummages through pads. For most XS code this will just dwim.

I have made that change in commit 3455055.

In fact, having Devel​::Peek inline itself would be useful for seeing the
return value of substr and vec in rvalue context, something currently
not possible.

Attached is a patch to get Devel​::Peek to inline itself. It also allows
Dump %hash and Dump @​array.

And I applied that patch, with a slight tweak (with one arg it was
leaking ops), as 34b94bc.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 13, 2013

From [Unknown Contact. See original ticket]

On Mon Aug 12 02​:00​:18 2013, sprout wrote​:

On Sat Jul 27 11​:27​:57 2013, sprout wrote​:

I did not fix this bug for calls to XSUBs, because it will make
Devel​::Peek less useful. Calling Dump("$x") and being able to see what
pp_stringify is return[ing] is a useful feature.

(Here I’m referring to the original bug reported, not the newRV issue.
Calling foo("$x") allowed the foo sub to see a TARG in $_[0], such that
print \$_[0], \$_[0] would show two different addresses.)

Currently foo("$x") will make a COW copy of the TARG if it is a Perl
sub, but pass the TARG itself if it is an XSUB. So for XS code to call
newRV on that is wrong (or what newRV does is wrong).

I think the real solution here is to apply the fix to XSUBs (copy TARG
arguments) but modify Devel​::Peek to inline itself, so that it remains
exempt.

That way the only XS code having access to TARGs will be that which
rummages through pads. For most XS code this will just dwim.

I have made that change in commit 3455055.

In fact, having Devel​::Peek inline itself would be useful for seeing the
return value of substr and vec in rvalue context, something currently
not possible.

Attached is a patch to get Devel​::Peek to inline itself. It also allows
Dump %hash and Dump @​array.

And I applied that patch, with a slight tweak (with one arg it was
leaking ops), as 34b94bc.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 13, 2013

@cpansprout - Status changed from 'open' to 'resolved'

@p5pRT p5pRT closed this as completed Aug 13, 2013
@p5pRT
Copy link
Author

p5pRT commented Aug 14, 2013

From @bulk88

On Tue Aug 13 13​:46​:33 2013, sprout wrote​:

And I applied that patch, with a slight tweak (with one arg it was
leaking ops), as 34b94bc.

The patch looks inefficient. Every XSUB call now has a larger overhead.

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Aug 14, 2013

From @ikegami

On Wed, Aug 14, 2013 at 11​:24 AM, bulk88 via RT
<perlbug-followup@​perl.org>wrote​:

On Tue Aug 13 13​:46​:33 2013, sprout wrote​:

And I applied that patch, with a slight tweak (with one arg it was
leaking ops), as 34b94bc.

The patch looks inefficient. Every XSUB call now has a larger overhead.

Why do you think so? Do you think S_ck_dump gets called for every XSUB
call? Isn't it only called for calls Devel​::Peek​::Dump (and imports
thereof)?

+ CV * const cv = get_cvn_flags("Devel​::Peek​::Dump", 17, 0);
+ cv_set_call_checker(cv, S_ck_dump, (SV *)cv);

@p5pRT
Copy link
Author

p5pRT commented Aug 14, 2013

From @bulk88

On Wed Aug 14 09​:11​:42 2013, ikegami@​adaelis.com wrote​:

On Wed, Aug 14, 2013 at 11​:24 AM, bulk88 via RT
<perlbug-followup@​perl.org>wrote​:

On Tue Aug 13 13​:46​:33 2013, sprout wrote​:

And I applied that patch, with a slight tweak (with one arg it was
leaking ops), as 34b94bc.

The patch looks inefficient. Every XSUB call now has a larger overhead.

Why do you think so? Do you think S_ck_dump gets called for every XSUB
call? Isn't it only called for calls Devel​::Peek​::Dump (and imports
thereof)?

+ CV * const cv = get_cvn_flags("Devel​::Peek​::Dump", 17, 0);
+ cv_set_call_checker(cv, S_ck_dump, (SV *)cv);

Whoops, I meant the patch in
http​://perl5.git.perl.org/perl.git/commit/3455055faace06645b99a6ed63fce90144ab47e1
which claims to be part of this ticket. I didn't compare the SHA1s.

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Aug 18, 2013

From @cpansprout

On Wed Aug 14 09​:27​:13 2013, bulk88 wrote​:

On Wed Aug 14 09​:11​:42 2013, ikegami@​adaelis.com wrote​:

On Wed, Aug 14, 2013 at 11​:24 AM, bulk88 via RT
<perlbug-followup@​perl.org>wrote​:

On Tue Aug 13 13​:46​:33 2013, sprout wrote​:

And I applied that patch, with a slight tweak (with one arg it
was
leaking ops), as 34b94bc.

The patch

(He means 3455055; see below.)

looks inefficient. Every XSUB call now has a larger
overhead.

True, but the overhead is minuscule, just a quick scan and flag check in
most cases. This is less than the argument-processing overhead of most
XSUBs.

An alternative would be to fix this bug by having newRV copy anything
marked PADTMP, but then newRV_noinc would have to SvREFCNT_dec its
argument, leaving the caller with a pointer to a freed SV. That would
result in subtle bugs hard to diagnose.

Another way would be to modify ops that return PADTMPs not to return
them in lvalue context to begin with, but that would shift the
complexity elsewhere into many pp_ functions, including pp_const which
is hotter than pp_entersub.

Why do you think so? Do you think S_ck_dump gets called for every
XSUB
call? Isn't it only called for calls Devel​::Peek​::Dump (and imports
thereof)?

+ CV * const cv = get_cvn_flags("Devel​::Peek​::Dump", 17, 0);
+ cv_set_call_checker(cv, S_ck_dump, (SV *)cv);

Whoops, I meant the patch in

http​://perl5.git.perl.org/perl.git/commit/3455055faace06645b99a6ed63fce90144ab47e1

which claims to be part of this ticket. I didn't compare the SHA1s.

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 18, 2013

From [Unknown Contact. See original ticket]

On Wed Aug 14 09​:27​:13 2013, bulk88 wrote​:

On Wed Aug 14 09​:11​:42 2013, ikegami@​adaelis.com wrote​:

On Wed, Aug 14, 2013 at 11​:24 AM, bulk88 via RT
<perlbug-followup@​perl.org>wrote​:

On Tue Aug 13 13​:46​:33 2013, sprout wrote​:

And I applied that patch, with a slight tweak (with one arg it
was
leaking ops), as 34b94bc.

The patch

(He means 3455055; see below.)

looks inefficient. Every XSUB call now has a larger
overhead.

True, but the overhead is minuscule, just a quick scan and flag check in
most cases. This is less than the argument-processing overhead of most
XSUBs.

An alternative would be to fix this bug by having newRV copy anything
marked PADTMP, but then newRV_noinc would have to SvREFCNT_dec its
argument, leaving the caller with a pointer to a freed SV. That would
result in subtle bugs hard to diagnose.

Another way would be to modify ops that return PADTMPs not to return
them in lvalue context to begin with, but that would shift the
complexity elsewhere into many pp_ functions, including pp_const which
is hotter than pp_entersub.

Why do you think so? Do you think S_ck_dump gets called for every
XSUB
call? Isn't it only called for calls Devel​::Peek​::Dump (and imports
thereof)?

+ CV * const cv = get_cvn_flags("Devel​::Peek​::Dump", 17, 0);
+ cv_set_call_checker(cv, S_ck_dump, (SV *)cv);

Whoops, I meant the patch in

http​://perl5.git.perl.org/perl.git/commit/3455055faace06645b99a6ed63fce90144ab47e1

which claims to be part of this ticket. I didn't compare the SHA1s.

--

Father Chrysostomos

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant