perl-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Torsten Foertsch <torsten.foert...@gmx.net>
Subject Re: [MP2] possible pnotes bug?
Date Wed, 15 Mar 2006 18:47:15 GMT
On Wednesday 15 March 2006 18:55, Perrin Harkins wrote:
> On Wed, 2006-03-15 at 12:23 -0500, Geoffrey Young wrote:
> > I actually thing that would be somewhat common.  and as I understand
> > things, the fix would require the middle step to be
> >
> >   -- next handler
> >   my $o = $r->pnotes('foo');
> >   $o->set(bar => 1);          # sets $o->{_bar} = 1
> >   $r->pnotes(foo => $o);
> >
> > in order for $o to maintain it's internal state.  is that right?  if so,
> > I don't like that very much.
>
> I agree, cloning is not the answer.  What you want really want here is
> for it to behave like a normal perl variable assignment, i.e. if you
> assign a reference, it stays a reference, and if you assign a value,
> it's just a value, not a double-secret-probation reference.  I don't
> think it's a good idea to change this unless it can be done that way.

The current implementation of

  $r->pnotes(foo=>$x)

is halfway similar to

  $r->pnotes->{foo}=\$x.

Only halfway because fetching the value works as expected: $r->pnotes('foo'). 
In pure Perl the exact behavior cannot be expressed.

Internally pnotes are stored in a HV. $r->pnotes without arguments returns a 
reference to that HV. Hence, $r->pnotes->{foo}=$o works as a normal 
assignment of a hash element:

$ perl -MDevel::Peek -e '$x=1; Dump($x); $h{x}=$x; Dump(\%h);'
SV = IV(0x816e598) at 0x816c6fc
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 1
SV = RV(0x8178d48) at 0x8151d40
  REFCNT = 1
  FLAGS = (TEMP,ROK)
  RV = 0x816c744
  SV = PVHV(0x81699c8) at 0x816c744
...
    Elt "x" HASH = 0x9303a5e5
    SV = IV(0x816e59c) at 0x8151c20
      REFCNT = 1
      FLAGS = (IOK,pIOK)
      IV = 1

Note that the refcounts of both IVs the first after $x=1 and the second in %h 
are 1. Also the IVs themself are different objects one at 0x816e598 the 
second at 0x816e59c.

With $r->pnotes->{x}=$x the output is similar.

But with $r->pnotes(x=>$x) it changes:

SV = IV(0x84c0664) at 0x866099c
  REFCNT = 1
  FLAGS = (PADBUSY,PADMY,IOK,pIOK)
  IV = 1
SV = RV(0x8640b68) at 0x8651a7c
  REFCNT = 2
  FLAGS = (TEMP,ROK)
  RV = 0x86397ec
  SV = PVHV(0x86453a0) at 0x86397ec
...
    Elt "x" HASH = 0x9303a5e5
    SV = IV(0x84c0664) at 0x866099c
      REFCNT = 2
      FLAGS = (PADBUSY,PADMY,IOK,pIOK)
      IV = 1

Now the both IVs are the same (0x84c0664) and the refcount after storing as a 
pnote is 2. And here is the problem. $r->pnotes->{x}=$x and $r->pnotes(x=>$x)

are different operations. The first stores a copy of the IV represented by 
$x. The second stores the IV $x itself. This is somehow similar to *y=\$x:

$ perl -e '$x=1; *y=\$x; $x++; print "$y\n";'
2
$ perl -MDevel::Peek -e '$x=1; Dump($x); *y=\$x; Dump($y);'
SV = IV(0x816e590) at 0x816c6f4
  REFCNT = 1
  FLAGS = (IOK,pIOK)
  IV = 1
SV = IV(0x816e590) at 0x816c6f4
  REFCNT = 2
  FLAGS = (IOK,pIOK)
  IV = 1

I think it is a bug even in MP1.

Here the code that produces the output in error_log:

package pn;

use strict;
use Apache2::RequestRec;
use Apache2::RequestIO;
use Apache2::RequestUtil;
use Apache2::Const -compile=>'OK';
use Devel::Peek;

sub handler {
  my $r=shift;
  my $x=1;
  Dump($x);
  $r->pnotes(x=>$x);
  Dump($r->pnotes);
  $r->print("ok\n");
  return Apache2::Const::OK;
}

1;

Devel::Peek uses buffered output at C-level. Hence, you probably have to 
restart the server to see the actual output.

Torsten

Mime
View raw message