This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #81290] assertion failure with lock &lvsub
authorFather Chrysostomos <sprout@cpan.org>
Thu, 21 Jul 2011 06:52:57 +0000 (23:52 -0700)
committerFather Chrysostomos <sprout@cpan.org>
Thu, 21 Jul 2011 06:53:23 +0000 (23:53 -0700)
With this commit, locking an lvalue subroutine no longer tries to lock
the subroutine itself (triggering an assertion in pp_lock).  Instead,
the &foo syntax is treated as a scalar lvalue expression, as with tie,
so the return value gets locked.  Non-lvalue sub calls still produce a
‘Can't modify’ error, as they are not modifiable.

This also stops lock from trying to return a sub as though it were a
scalar, thereby breaking this JAPH I’ve just written:-)

sub _:lvalue{$x}for(lock&_){$_
="Just another Perl hacker,\n"}
print+prototype"_"

MANIFEST
op.c
pod/perldelta.pod
t/op/lock.t [new file with mode: 0644]

index 95f9d61..8635bf6 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -4970,6 +4970,7 @@ t/op/lfs.t                        See if large files work for perlio
 t/op/list.t                    See if array lists work
 t/op/localref.t                        See if local ${deref} works
 t/op/local.t                   See if local works
+t/op/lock.t                    Tests for lock args & retval (no threads)
 t/op/loopctl.t                 See if next/last/redo work
 t/op/lop.t                     See if logical operators work
 t/op/magic-27839.t             Test for #27839, skipped for minitest
diff --git a/op.c b/op.c
index ab65490..1ff086b 100644 (file)
--- a/op.c
+++ b/op.c
@@ -1878,7 +1878,7 @@ Perl_doref(pTHX_ OP *o, I32 type, bool set_op_ref)
 
     switch (o->op_type) {
     case OP_ENTERSUB:
-       if ((type == OP_EXISTS || type == OP_DEFINED || type == OP_LOCK) &&
+       if ((type == OP_EXISTS || type == OP_DEFINED) &&
            !(o->op_flags & OPf_STACKED)) {
            o->op_type = OP_RV2CV;             /* entersub => rv2cv */
            o->op_ppaddr = PL_ppaddr[OP_RV2CV];
index 8bbdbd6..a3d92cd 100644 (file)
@@ -333,7 +333,10 @@ L</Modules and Pragmata>.
 
 =item *
 
-XXX
+Locking an lvalue subroutine (via C<lock &lvsub>) now locks the return
+value, instead of trying to lock the sub (which has no effect).  It also no
+longer tries to return the sub as a scalar, resulting in strange side
+effects like C<ref \$_> returning "CODE" in some instances.
 
 =back
 
diff --git a/t/op/lock.t b/t/op/lock.t
new file mode 100644 (file)
index 0000000..2fd6782
--- /dev/null
@@ -0,0 +1,18 @@
+#!./perl
+
+BEGIN {
+    chdir 't' if -d 't';
+    @INC = qw(. ../lib);
+    require './test.pl';
+}
+plan tests => 5;
+
+is \lock $foo, \$foo, 'lock returns a scalar argument';
+is  lock @foo, \@foo, 'lock returns a ref to its array argument';
+is  lock %foo, \%foo, 'lock returns a ref to its hash argument';
+eval { lock &foo }; my $file = __FILE__; my $line = __LINE__;
+is $@, "Can't modify non-lvalue subroutine call at $file line $line.\n",
+     'Error when locking non-lvalue sub';
+
+sub eulavl : lvalue { $x }
+is \lock &eulavl, \$x, 'locking lvalue sub acts on retval, just like tie';