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

[PATCH blead] Re: Overload Segfaulting #9378

Closed
p5pRT opened this issue Jun 14, 2008 · 5 comments
Closed

[PATCH blead] Re: Overload Segfaulting #9378

p5pRT opened this issue Jun 14, 2008 · 5 comments

Comments

@p5pRT
Copy link

p5pRT commented Jun 14, 2008

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

Searchable as RT55786$

@p5pRT
Copy link
Author

p5pRT commented Jun 14, 2008

From rick@bort.ca

On Jun 12 2008, Craig A. Berry wrote​:

On Thu, Jun 12, 2008 at 10​:26 AM, Nicholas Clark <nick@​ccl4.org> wrote​:

On Thu, Jun 12, 2008 at 11​:17​:39AM -0400, Jerry D. Hedden wrote​:

Ovid wrote​:

The following segfaults on Solaris, Ubuntu 7.10 and Windows (all of
whom are running 5.8.8). Seems like a fairly universal failure.

use strict;
use warnings;

{
package Some​::Package;

 use overload
     '\+\+'     => sub \{ print "object is $\_\[0\]\\n" \}\,
     fallback => 1;

 sub new \{ bless \{\} => shift \}

}

my $object = Some​::Package->new;
print $object++;

Segfaults with blead under Cygwin, too.

and blead on VMS​:

$ perl bar.t
%SYSTEM-F-ACCVIO, access violation, reason mask=00, virtual
address=0000000000000008, PC=00000000001F0E18, PS=0000001B
%TRACE-F-TRACEBACK, symbolic stack dump follows
image module routine line rel PC abs PC
DBGPERLSHR PP_HOT Perl_pp_concat 70185 0000000000001468 00000000001F0E18
DBGPERLSHR DUMP Perl_runops_debug 80908 0000000000008744 00000000001BC9A4
DBGPERLSHR GV Perl_amagic_call 72280 00000000000087B8 00000000000F6408
DBGPERLSHR SV Perl_sv_inc 78861 0000000000016118 000000000010D338
DBGPERLSHR PP Perl_pp_postinc 71120 00000000000053B8 000000000021D718
DBGPERLSHR DUMP Perl_runops_debug 80908 0000000000008744 00000000001BC9A4
DBGPERLSHR PERL S_run_body 72488 0000000000004C04 00000000000BC9E4
DBGPERLSHR PERL perl_run 72408 000000000000480C 00000000000BC5EC
NDBGPERL PERLMAIN main 70074 0000000000000204 0000000000020204
NDBGPERL PERLMAIN __main 70023 00000000000000A0 00000000000200A0
PTHREAD$RTL 0 0000000000057618 FFFFFFFF80E77618
PTHREAD$RTL 0 0000000000030444 FFFFFFFF80E50444
0 FFFFFFFF8037BCE4 FFFFFFFF8037BCE4
%TRACE-I-END, end of TRACE stack dump

Seems to be something to do with the perl stack being made of NULL​:

Somewhat more specifically, it's trying to get at something 8 bytes
offset from a null pointer (the access violation happens at an address
of 8, which is not a valid address).

(gdb) r
Starting program​: /home/nick/p4perl/perl/perl -Ilib ../maint-5.10/perl/Ovid

Program received signal SIGSEGV, Segmentation fault.
0x00000000004d4fc5 in Perl_pp_concat () at pp_hot.c​:224
224 dVAR; dSP; dATARGET; tryAMAGICbin(concat,opASSIGN);
(gdb) call Perl_sv_dump(my_perl, *sp)
SV = NULL(0x0) at 0x86f010
REFCNT = 0
FLAGS = ()
(gdb) call Perl_sv_dump(my_perl, sp[-1])
SV = NULL(0x0) at 0x86f010
REFCNT = 0
FLAGS = ()

[tryAMAGICbin is a mess, but it's something like​:

(void)( { SV* const left = *(sp-1); SV* const right = *(sp); if (((((left)->sv_flags & 0x00000800) && ((((left)->sv_u.svu_rv))->sv_flags & 0x10000000))||(((right)->sv_flags & 0x00000800) && ((((right)->sv_u.svu_rv))->sv_flags & 0x10000000))))

It's in the part that looks at​:

(((right)->sv_u.svu_rv))->sv_flags

sv_flags is 8 bytes offset from the start of an SV, which in this case
puts us 8 bytes north of NULL​:

This is because RvDEEPCP does this

  SvRV_set(rv, AMG_CALLun(rv,copy));

and AMG_CALLun is returning NULL. It returns NULL because there is no
copy constructor defined (overloaded '=') and the autogeneration can
only deal with objects that are scalar refs. This is sort of documented
but it sure doesn't say it will segfault if your objects are not scalar
refs.

Anyway, patch attached.

--
Rick Delaney
rick@​bort.ca

@p5pRT
Copy link
Author

p5pRT commented Jun 14, 2008

From rick@bort.ca

ov_copy.patch
diff -pruN perl-current/lib/overload.pm perl-current-dev/lib/overload.pm
--- perl-current/lib/overload.pm	2007-04-25 11:19:52.000000000 -0400
+++ perl-current-dev/lib/overload.pm	2008-06-14 14:39:40.000000000 -0400
@@ -588,7 +588,8 @@ appear as lvalue when the above code is 
 
 If the copy constructor is required during the execution of some mutator,
 but a method for C<'='> was not specified, it can be autogenerated as a
-string copy if the object is a plain scalar.
+string copy if the object is a plain scalar or a simple assignment if it
+is not.
 
 =over 5
 
@@ -675,7 +676,8 @@ C<E<lt>=E<gt>> or C<cmp>:
 =item I<Copy operator>
 
 can be expressed in terms of an assignment to the dereferenced value, if this
-value is a scalar and not a reference.
+value is a scalar and not a reference, or simply a reference assignment
+otherwise.
 
 =back
 
diff -pruN perl-current/lib/overload.t perl-current-dev/lib/overload.t
--- perl-current/lib/overload.t	2008-01-06 15:36:14.000000000 -0500
+++ perl-current-dev/lib/overload.t	2008-06-14 13:06:08.000000000 -0400
@@ -47,7 +47,7 @@ sub numify { 0 + "${$_[0]}" }	# Not need
 package main;
 
 $| = 1;
-use Test::More tests => 556;
+use Test::More tests => 558;
 
 
 $a = new Oscalar "087";
@@ -1427,4 +1427,20 @@ foreach my $op (qw(<=> == != < <= > >=))
     is($aref**1, $num_val, 'exponentiation of ref');
 }
 
+{
+    package CopyConstructorFallback;
+    use overload
+        '++'        => sub { "$_[0]"; $_[0] },
+        fallback    => 1;
+    sub new { bless {} => shift }
+
+    package main;
+
+    my $o = CopyConstructorFallback->new;
+    my $x = $o++; # would segfault
+    my $y = ++$o;
+    is($x, $o, "copy constructor falls back to assignment (postinc)");
+    is($y, $o, "copy constructor falls back to assignment (preinc)");
+}
+
 # EOF
diff -pruN perl-current/pp.h perl-current-dev/pp.h
--- perl-current/pp.h	2008-01-04 15:32:34.000000000 -0500
+++ perl-current-dev/pp.h	2008-06-14 13:40:38.000000000 -0400
@@ -487,9 +487,9 @@ Does not use C<TARG>.  See also C<XPUSHu
 
 /* SV* ref causes confusion with the member variable
    changed SV* ref to SV* tmpRef */
-#define RvDEEPCP(rv) STMT_START { SV* tmpRef=SvRV(rv);      \
-  if (SvREFCNT(tmpRef)>1) {                 \
-    SvRV_set(rv, AMG_CALLun(rv,copy));	\
+#define RvDEEPCP(rv) STMT_START { SV* tmpRef=SvRV(rv); SV* rv_copy;     \
+  if (SvREFCNT(tmpRef)>1 && (rv_copy = AMG_CALLun(rv,copy))) {          \
+    SvRV_set(rv, rv_copy);		    \
     SvREFCNT_dec(tmpRef);                   \
   } } STMT_END
 

@p5pRT
Copy link
Author

p5pRT commented Jun 15, 2008

From @rgs

2008/6/14 via RT Rick Delaney <perlbug-followup@​perl.org>​:

This is because RvDEEPCP does this

SvRV_set(rv, AMG_CALLun(rv,copy));

and AMG_CALLun is returning NULL. It returns NULL because there is no
copy constructor defined (overloaded '=') and the autogeneration can
only deal with objects that are scalar refs. This is sort of documented
but it sure doesn't say it will segfault if your objects are not scalar
refs.

Anyway, patch attached.

Thanks, applied to bleadperl as change #34055.

@p5pRT
Copy link
Author

p5pRT commented Jun 15, 2008

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jun 15, 2008

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

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