Skip Menu |

This queue is for tickets about the Lexical-Util CPAN distribution.

Report information
The Basics
Id: 23485
Status: new
Priority: 0/
Queue: Lexical-Util

People
Owner: Nobody in particular
Requestors: ofun [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 0.8
Fixed in: (no value)



Subject: CVREF does not specify a stack frame
If a function is called recursively, the same CVREF will be assigned to each call, even though those calls have different stack frames. Therefore, the functions ref_to_lexical, lexalias, and lexical_alias cannot be correctly implemented with the given prototypes. My quick guess (without thoroughly understanding the code) is that the '0' hardcoded in Util.c:204: ref_to_var = av_fetch(padv, i, 0); always references the topmost scratchpad. This level should be variable instead. For single-threaded execution, probably you could count the number of times the same CVREF is obtained before level $i the caller stack, and return it as $j in ($cvref, $j) = frame_to_cvref($i); so that the '0' above can be replaced with $j provided in a call: $ref = ref_to_lexical('$lexical', $cvref, $j); (order of arguments changed as a suggestion, for composability and so that $j can default to zero). In a multi-threaded environment, you're in deeper trouble. See PadWalker for a solution, I hope. Tests (working with PadWalker, failing with Lexical::Util) attached. Thanks for factoring this functionality out, by the way; I hope you can fix it so it's usable! ------- This is perl, v5.8.6 built for darwin-thread-multi-2level OS X 10.4.8
Subject: padwalker-recursion.t
use Test::More tests => 7; use PadWalker qw/peek_my/; foo(0); sub foo { my $depth = $_[0]; my $y = $depth; if($depth > 0) { my $href = peek_my(1); my $yref = $$href{'$y'}; $$yref = -1 * $$yref; } is($y, $depth, "Depth $depth: Before foo(), I have not been negated"); if($depth < 3) { foo($depth + 1); is($y, -1 * $depth, "Depth $depth: after foo(), I have been negated"); } }
Subject: recursion-bug.t
use Test::More tests => 7; use Lexical::Util qw/frame_to_cvref ref_to_lexical/; foo(0); sub foo { my $depth = $_[0]; my $y = $depth; if($depth > 0) { my $yref = ref_to_lexical(frame_to_cvref(1), '$y'); $$yref = -1 * $$yref; } is($y, $depth, "Depth $depth: Before foo(), I have not been negated"); if($depth < 3) { foo($depth + 1); is($y, -1 * $depth, "Depth $depth: after foo(), I have been negated"); } }