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

[Win32] Unable to build 64-bit blead using gcc-4.8.2 #14556

Closed
p5pRT opened this issue Mar 4, 2015 · 35 comments
Closed

[Win32] Unable to build 64-bit blead using gcc-4.8.2 #14556

p5pRT opened this issue Mar 4, 2015 · 35 comments

Comments

@p5pRT
Copy link

p5pRT commented Mar 4, 2015

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

Searchable as RT123976$

@p5pRT
Copy link
Author

p5pRT commented Mar 4, 2015

From @sisyphus

Hi,

This is a bug report following on from the p5p thread
http​://www.nntp.perl.org/group/perl.perl5.porters/2014/12/msg223791.html

AFAIK, no bug report was filed for this, but the issue is still unresolved.
(As Tony Cook pointed out in that thread, there's no such problem if we use
gcc-4.7.3.)

To re-iterate, early on in the 'dmake' stage we get​:

..\miniperl.exe -I..\lib -f ..\write_buildcustomize.pl ..
Attempt to free unreferenced scalar​: SV 0x6cb218 at ..\lib/strict.pm line
38.
dmake​: Warning​: -- Found file corresponding to virtual target
[..\uudmap.h].
dmake​: Error code 244, while making '..\lib\buildcustomize.pl'

Cheers,
Rob

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

On Tue Mar 03 18​:22​:30 2015, sisyphus wrote​:

Hi,

This is a bug report following on from the p5p thread
http​://www.nntp.perl.org/group/perl.perl5.porters/2014/12/msg223791.html

Attached is a dump with the breakpoint in the correct place.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

(gdb) dir ..
Source directories searched​: j​:\dev\perl\git\perl\win32/..;$cdir;$cwd
(gdb) list gv.c​:2285,+6
2285 else gv = *gvp, addmg = 0;
2286 if (full_len == 8 && strEQ(nambeg, "all_bits")) {
2287 Perl_warn(aTHX_ "Perl_gv_fetchpvn_flags()​: $​::{all_bits} = \n");
2288 sv_dump((SV*)gv);
2289 }
2290 /* From this point on, addmg means gv has not been inserted in the
2291 symtab yet. */
(gdb) b gv.c​:2287
Breakpoint 1 at 0x429d13​: file ..\gv.c, line 2287.
(gdb) r -I..\lib -f ../write_buildcustomize.pl ..
Starting program​: j​:\dev\perl\git\perl\miniperl.exe -I..\lib -f ../write_buildcustomize.pl ..
[New Thread 5860.0x1be8]

Breakpoint 1, Perl_gv_fetchpvn_flags (nambeg=<optimized out>, full_len=8,
  flags=2, sv_type=SVt_PVGV) at ..\gv.c​:2287
2287 Perl_warn(aTHX_ "Perl_gv_fetchpvn_flags()​: $​::{all_bits} = \n");
(gdb) c
Continuing.
Perl_gv_fetchpvn_flags()​: $​::{all_bits} =
SV = NULL(0x0) at 0x278eed0
  REFCNT = 1
  FLAGS = ()
Perl_gv_init_pvn()​: pre-upgrade GV=
SV = NULL(0x0) at 0x278eed0
  REFCNT = 1
  FLAGS = ()
Perl_gv_init_pvn()​: post-upgrade GV=
SV = PVGV(0x2784070) at 0x278eed0
  REFCNT = 1
  FLAGS = ()
  IV = 0
  NV = 0
  PV = 0
Perl_gv_init_pvn()​: prior to assert, GV =
SV = PVGV(0x2784070) at 0x278eed0
  REFCNT = 1
  FLAGS = ()
  IV = 0
  NV = 0
  PV = 0

Breakpoint 1, Perl_gv_fetchpvn_flags (nambeg=<optimized out>, full_len=8,
  flags=0, sv_type=sv_type@​entry=SVt_PVGV) at ..\gv.c​:2287
2287 Perl_warn(aTHX_ "Perl_gv_fetchpvn_flags()​: $​::{all_bits} = \n");
(gdb) fin
Run till exit from #0 Perl_gv_fetchpvn_flags (nambeg=<optimized out>,
  full_len=8, flags=0, sv_type=sv_type@​entry=SVt_PVGV) at ..\gv.c​:2287
Perl_gv_fetchpvn_flags()​: $​::{all_bits} =
SV = PVGV(0x2784070) at 0x278eed0
  REFCNT = 1
  FLAGS = (MULTI)
  NAME = "all_bits"
  NAMELEN = 8
  GvSTASH = 0x278e9a8 "strict"
  FLAGS = 0x2
  GP = 0x27a33f0
  SV = 0x0
  REFCNT = 1
  IO = 0x0
  FORM = 0x0
  AV = 0x0
  HV = 0x0
  CV = 0x0
  CVGEN = 0x0
  GPFLAGS = 0x0 ()
  LINE = 31
  FILE = "..\lib/strict.pm"
  EGV = 0x278eed0 "all_bits"
Perl_gv_fetchsv (name=name@​entry=0x278eeb8, flags=0, sv_type=SVt_PVGV)
  at ..\gv.c​:1538
1538 }
Value returned is $1 = (GV *) 0x278eed0
(gdb) fin
Run till exit from #0 Perl_gv_fetchsv (name=name@​entry=0x278eeb8, flags=0,
  sv_type=SVt_PVGV) at ..\gv.c​:1538
Perl_ck_rvconst (o=0x27a0ef8) at op.c​:9831
9831 if (gv) {
Value returned is $2 = (GV *) 0x278eed0
(gdb) n
9817 gv = gv_fetchsv(kidsv,
(gdb)
9831 if (gv) {
(gdb)
9832 if (!isGV(gv)) {
(gdb)
9839 OpTYPE_set(kid, OP_GV);
(gdb)
9840 SvREFCNT_dec(kid->op_sv);
(gdb)
9839 OpTYPE_set(kid, OP_GV);
(gdb)
9840 SvREFCNT_dec(kid->op_sv);
(gdb)
9839 OpTYPE_set(kid, OP_GV);
(gdb)
9840 SvREFCNT_dec(kid->op_sv);
(gdb)
9848 kid->op_sv = SvREFCNT_inc_simple_NN(gv);
(gdb)
9850 kid->op_private = 0;
(gdb)
9856 }
(gdb) call Perl_sv_dump((SV*)0x278eed0)
SV = PVGV(0x2784070) at 0x278eed0
  REFCNT = 2
  FLAGS = (MULTI)
  NAME = "all_bits"
  NAMELEN = 8
  GvSTASH = 0x278e9a8 "strict"
  FLAGS = 0x2
  GP = 0x27a33f0
  SV = 0x0
  REFCNT = 1
  IO = 0x0
  FORM = 0x0
  AV = 0x0
  HV = 0x0
  CV = 0x0
  CVGEN = 0x0
  GPFLAGS = 0x0 ()
  LINE = 31
  FILE = "..\lib/strict.pm"
  EGV = 0x278eed0 "all_bits"
(gdb) n
9848 kid->op_sv = SvREFCNT_inc_simple_NN(gv);
(gdb)
9852 SvFAKE_off(gv);
(gdb)
9856 }
(gdb)
Perl_newUNOP (type=type@​entry=14, flags=<optimized out>, flags@​entry=16,
  first=0x27a0f38) at op.c​:4816
4816 if (unop->op_next)
(gdb)
4815 unop = (UNOP*) CHECKOP(type, unop);
(gdb) p unop
$3 = <optimized out>
(gdb) n
4816 if (unop->op_next)
(gdb)
4819 return fold_constants(op_integerize(op_std_init((OP *) unop)));
(gdb) c
Continuing.
Attempt to free unreferenced scalar​: SV 0x269268 at ..\lib/strict.pm line 38.

Breakpoint 1, Perl_gv_fetchpvn_flags (nambeg=<optimized out>, full_len=8,
  flags=64, sv_type=sv_type@​entry=SVt_PVCV) at ..\gv.c​:2287
2287 Perl_warn(aTHX_ "Perl_gv_fetchpvn_flags()​: $​::{all_bits} = \n");
(gdb) n
Perl_gv_fetchpvn_flags()​: $​::{all_bits} =
2288 sv_dump((SV*)gv);
(gdb)
SV = PVAV(0x26b298) at 0x278eed0
  REFCNT = 1
  FLAGS = ()
  ARRAY = 0x0
  FILL = -1
  MAX = -1
  ARYLEN = 0x0
  FLAGS = (REAL)
2293 if (SvTYPE(gv) == SVt_PVGV) {
(gdb) q
A debugging session is active.

  Inferior 1 [process 5860] will be killed.

Quit anyway? (y or n) [answered Y; input not from terminal]

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

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

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

On Tue Mar 31 17​:56​:12 2015, tonyc wrote​:

On Tue Mar 03 18​:22​:30 2015, sisyphus wrote​:

Hi,

This is a bug report following on from the p5p thread
http​://www.nntp.perl.org/group/perl.perl5.porters/2014/12/msg223791.html

Attached is a dump with the breakpoint in the correct place.

Here's a simpler reproducer​:

BEGIN {
  my $bits = 0;
  *foo = sub () { $bits };
}
foo();

Produces​:

Attempt to free unreferenced scalar​: SV 0x346ec0.

*without* the call to foo().

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

On Tue Mar 31 19​:08​:05 2015, tonyc wrote​:

On Tue Mar 31 17​:56​:12 2015, tonyc wrote​:

On Tue Mar 03 18​:22​:30 2015, sisyphus wrote​:

Hi,

This is a bug report following on from the p5p thread
http​://www.nntp.perl.org/group/perl.perl5.porters/2014/12/msg223791.html

Attached is a dump with the breakpoint in the correct place.

Here's a simpler reproducer​:

BEGIN {
my $bits = 0;
*foo = sub () { $bits };
}
foo();

You don't need the variable, so just​:

BEGIN {
  *foo = sub () { 0 };
}
foo();

will produce the "Attempt to free unreferenced scalar" and the assertion failure.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

On Tue Mar 03 18​:22​:30 2015, sisyphus wrote​:

Hi,

This is a bug report following on from the p5p thread
http​://www.nntp.perl.org/group/perl.perl5.porters/2014/12/msg223791.html

The attached seems to fix the problem for me, though I'm not sure if it's fixing
a real problem or just beating a possible bug in gcc's optimizer.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

0001-prevent-any-other-code-from-freeing-the-op-s-gv-whil.patch
From 5078dd92544f00fa245a5272bc399e690d5711a6 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Wed, 1 Apr 2015 16:36:51 +1100
Subject: [PATCH 1/2] prevent any other code from freeing the op's gv while we
 do

assuming I understand why this is breaking, which is unlikely
---
 op.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/op.c b/op.c
index ad0b0b0..efacd31 100644
--- a/op.c
+++ b/op.c
@@ -824,17 +824,22 @@ void S_op_clear_gv(pTHX_ OP *o, SV**svp)
        so any *valid* code that happens to do this during global
        destruction might well trigger premature cleanup.  */
     bool still_valid = gv && SvREFCNT(gv);
+#ifdef USE_ITHREADS
+    PADOFFSET ix = *ixp;
+#else
+    SV *sv = *svp;
+#endif
 
     if (still_valid)
         SvREFCNT_inc_simple_void(gv);
 #ifdef USE_ITHREADS
-    if (*ixp > 0) {
-        pad_swipe(*ixp, TRUE);
+    if (ix > 0) {
         *ixp = 0;
+        pad_swipe(ix, TRUE);
     }
 #else
-    SvREFCNT_dec(*svp);
     *svp = NULL;
+    SvREFCNT_dec(sv);
 #endif
     if (still_valid) {
         int try_downgrade = SvREFCNT(gv) == 2;
-- 
1.9.5.msysgit.0

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @iabyn

On Tue, Mar 31, 2015 at 10​:44​:34PM -0700, Tony Cook via RT wrote​:

The attached seems to fix the problem for me, though I'm not sure if it's fixing
a real problem or just beating a possible bug in gcc's optimizer.

Hmm, I've stared and stared at it and can't see a real problem there.
Perhaps you should single step through S_op_clear_gv() and see if the
value of *ixp changes at any point, or whether pad_swipe() is called with
the wrong value.

One slightly odd thing about that particular bit of perl code is that the
BEGIN cv is freed by this code in perly.y​:

  for (i=0; i< parser->yylen; i++) {
  SvREFCNT_dec(ps[-i].compcv);
  }

and at that point, PL_curpad is null - so all the pad manipulation that
would be done by S_op_clear_gv() and pad_swipe() is in fact skipped.
I'm not sure whether that's a bug or not.

--
Red sky at night - gerroff my land!
Red sky at morning - gerroff my land!
  -- old farmers' sayings #14

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

On Wed Apr 01 05​:43​:08 2015, davem wrote​:

On Tue, Mar 31, 2015 at 10​:44​:34PM -0700, Tony Cook via RT wrote​:

The attached seems to fix the problem for me, though I'm not sure if
it's fixing
a real problem or just beating a possible bug in gcc's optimizer.

Hmm, I've stared and stared at it and can't see a real problem there.
Perhaps you should single step through S_op_clear_gv() and see if the
value of *ixp changes at any point, or whether pad_swipe() is called
with
the wrong value.

One slightly odd thing about that particular bit of perl code is that
the
BEGIN cv is freed by this code in perly.y​:

for (i=0; i< parser->yylen; i++) {
SvREFCNT_dec(ps[-i].compcv);
}

and at that point, PL_curpad is null - so all the pad manipulation
that
would be done by S_op_clear_gv() and pad_swipe() is in fact skipped.
I'm not sure whether that's a bug or not.

miniperl is built as non-threaded on Win32, so PL_curpad isn't checked and
*ixp is irrelevant.

I've added a trace through of S_op_clear_gv - which asserts on the second
SvREFCNT_dec()

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

On Wed Apr 01 15​:43​:20 2015, tonyc wrote​:

I've added a trace through of S_op_clear_gv - which asserts on the second
SvREFCNT_dec()

Really added now.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 1, 2015

From @tonycoz

j​:\dev\perl\git\perl\win32>gdb ..\miniperl.exe
gdb ..\miniperl.exe
GNU gdb (GDB) 7.7.1
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+​: GNU GPL version 3 or later <http​://gnu.org/licenses/gpl.html>
This is free software​: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-w64-mingw32".
Type "show configuration" for configuration details.
For bug reporting instructions, please see​:
<http​://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at​:
<http​://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ..\miniperl.exe...done.
(gdb) b S_op_clear_gv
Breakpoint 1 at 0x462450​: file op.c, line 802.
(gdb) r ..\..\123976.pl
Starting program​: j​:\dev\perl\git\perl\miniperl.exe ..\..\123976.pl
[New Thread 7084.0xd90]

Breakpoint 1, S_op_clear_gv (o=o@​entry=0x2784d38, svp=svp@​entry=0x2784d60)
  at op.c​:802
802 op.c​: No such file or directory.
(gdb) dir ..
Source directories searched​: j​:\dev\perl\git\perl\win32/..;$cdir;$cwd
(gdb) n
805 || o->op_type == OP_MULTIDEREF)
(gdb) p *svp
$1 = (SV *) 0x277e7b8
(gdb) n
802 {
(gdb)
805 || o->op_type == OP_MULTIDEREF)
(gdb)
810 ? (GV*)(*svp) : NULL;
(gdb)
826 bool still_valid = gv && SvREFCNT(gv);
(gdb) p gv
$2 = (GV *) 0x277e7b8
(gdb) b op.c​:845
Breakpoint 2 at 0x4624bd​: file op.c, line 845.
(gdb) display *svp
1​: *svp = (SV *) 0x277e7b8
(gdb) n
829 SvREFCNT_inc_simple_void(gv);
1​: *svp = (SV *) 0x277e7b8
(gdb)
826 bool still_valid = gv && SvREFCNT(gv);
1​: *svp = (SV *) 0x277e7b8
(gdb)
836 SvREFCNT_dec(*svp);
1​: *svp = (SV *) 0x277e7b8
(gdb)
829 SvREFCNT_inc_simple_void(gv);
1​: *svp = (SV *) 0x277e7b8
(gdb)
836 SvREFCNT_dec(*svp);
1​: *svp = (SV *) 0x277e7b8
(gdb)
839 if (still_valid) {
1​: *svp = (SV *) 0x277e7b8
(gdb)
837 *svp = NULL;
1​: *svp = (SV *) 0x277e7b8
(gdb)
839 if (still_valid) {
1​: *svp = (SV *) 0x0
(gdb)
840 int try_downgrade = SvREFCNT(gv) == 2;
1​: *svp = (SV *) 0x0
(gdb)
841 SvREFCNT_dec_NN(gv);
1​: *svp = (SV *) 0x0
(gdb)
845 }
1​: *svp = (SV *) 0x0
(gdb)
841 SvREFCNT_dec_NN(gv);
1​: *svp = (SV *) 0x0
(gdb)

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
A s s e r t i o n f a i l e d !

P r o g r a m : j : \ d e v \ p e r l \ g i t \ p e r l \ m i n i p e r l . e x e
F i l e : . . \ g v . c , L i n e 4 1 0

E x p r e s s i o n : S v T Y P E ( g v ) = = S V t _ P V G V | | S v T Y P E ( g v ) = = S V t _ P V L V
[Inferior 1 (process 7084) exited with code 03]
(gdb) q

@p5pRT
Copy link
Author

p5pRT commented Apr 2, 2015

From @iabyn

On Wed, Apr 01, 2015 at 03​:43​:21PM -0700, Tony Cook via RT wrote​:

miniperl is built as non-threaded on Win32, so PL_curpad isn't checked and
*ixp is irrelevant.

Ah, I hadn't realised.

I've added a trace through of S_op_clear_gv - which asserts on the second
SvREFCNT_dec()

I'm not sure that's the case. The optimised code is showing enough random
jumping about between the lines under the debugger that that's probably a
red herring. The assert is in Perl_gv_init_pvn(), and it would be
interesting to see the call stack at that point.

On my system, Perl_gv_init_pvn() isn't invoked at all around that time.
The following session (with extraneous output trimmed) shows that after
the first call call to S_op_clear_gv(), there aren't any calls to
Perl_gv_init_pvn() until destruct time​:

$ cat /tmp/p
BEGIN { *foo = sub () { 0 } }
foo();

$ gdb ./miniperl
(gdb) b S_op_clear_gv
(gdb) run /tmp/p
Breakpoint 1, S_op_clear_gv (o=0xa4ffb8, svp=0xa4ffe0) at op.c​:804
804 GV *gv = (o->op_type == OP_GV || o->op_type == OP_GVSV
(gdb) b Perl_gv_init_pvn
(gdb) c
Breakpoint 1, S_op_clear_gv (o=0xa4fc68, svp=0xa4fc90) at op.c​:804
804 GV *gv = (o->op_type == OP_GV || o->op_type == OP_GVSV
(gdb) c
Breakpoint 2, Perl_gv_init_pvn (gv=0xa2d2c8, stash=0xa41ae0,
  name=0x7bb5c1 "DESTROY", len=0x7, flags=0x2) at gv.c​:367
367 const U32 old_type = SvTYPE(gv);
(gdb) bt
...
#10 0x0000000000595bef in Perl_sv_clean_objs () at sv.c​:662
#11 0x00000000004059e5 in perl_destruct (my_perl=0xa2b010) at perl.c​:801
#12 0x0000000000451161 in main (argc=0x2, argv=0x7fffffffe0b8,
  env=0x7fffffffe0d0) at miniperlmain.c​:133

--
Fire extinguisher (n) a device for holding open fire doors.

@p5pRT
Copy link
Author

p5pRT commented Apr 2, 2015

From @tonycoz

On Thu Apr 02 11​:20​:19 2015, davem wrote​:

Ah, I hadn't realised.

I've added a trace through of S_op_clear_gv - which asserts on the second
SvREFCNT_dec()

I'm not sure that's the case. The optimised code is showing enough random
jumping about between the lines under the debugger that that's probably a
red herring. The assert is in Perl_gv_init_pvn(), and it would be
interesting to see the call stack at that point.

You're right, it wasn't in the SvREFCNT_dec().

Here's the backtrace, I added code to break into the debugger when the SvTYPE()
was wrong, and to dump gv just before the second Sv.REFCNT_dec​:

(gdb) list gv.c​:411
406 } else
407 Safefree(SvPVX_mutable(gv));
408 }
409 SvIOK_off(gv);
410 if (!(SvTYPE(gv) == SVt_PVGV || SvTYPE(gv) == SVt_PVLV)) {
411 sv_dump((SV*)gv);
412 *(char *)0 = 0;
413 }
414 isGV_with_GP_on(gv);
415
(gdb) list op.c​:841
836 SvREFCNT_dec(*svp);
837 *svp = NULL;
838 #endif
839 if (still_valid) {
840 int try_downgrade = SvREFCNT(gv) == 2;
841 sv_dump((SV*)gv);
842 SvREFCNT_dec_NN(gv);
843 if (try_downgrade)
844 gv_try_downgrade(gv);
845 }
(gdb) r ..\..\123976.pl
Starting program​: j​:\dev\perl\git\perl\miniperl.exe ..\..\123976.pl
[New Thread 6848.0x1b50]
SV = PVGV(0x27d3da0) at 0x27de7b8
  REFCNT = 1
  FLAGS = (MULTI,ASSUMECV)
  NAME = "foo"
  NAMELEN = 3
  GvSTASH = 0xec8ff8 "main"
  FLAGS = 0x6
  GP = 0x27e4e00
  SV = 0x0
  REFCNT = 1
  IO = 0x0
  FORM = 0x0
  AV = 0x0
  HV = 0x0
  CV = 0x27de848
  CVGEN = 0x0
  GPFLAGS = 0x0 ()
  LINE = 2
  FILE = "..\..\123976.pl"
  EGV = 0x27de7b8 "foo"
SV = UNKNOWN(0xff) (0x27de7d0) at 0x27de7b8
  REFCNT = 0
  FLAGS = ()

Program received signal SIGSEGV, Segmentation fault.
Perl_gv_init_pvn (gv=0x27de7b8, stash=0xec8ff8, name=0x27e0d50 "foo", len=3,
  flags=flags@​entry=0) at ..\gv.c​:412
412 *(char *)0 = 0;
(gdb) bt
#0 Perl_gv_init_pvn (gv=0x27de7b8, stash=0xec8ff8, name=0x27e0d50 "foo",
  len=3, flags=flags@​entry=0) at ..\gv.c​:412
#1 0x0000000000429f2c in Perl_gv_fetchpvn_flags (nambeg=0x27e0d50 "foo",
  full_len=<optimized out>, flags=<optimized out>,
  sv_type=sv_type@​entry=SVt_PVCV) at ..\gv.c​:2334
#2 0x000000000042d26e in Perl_gv_fetchsv (name=name@​entry=0x27de770,
  flags=64, sv_type=SVt_PVCV) at ..\gv.c​:1526
#3 0x0000000000467408 in Perl_ck_rvconst (o=0x27e4878) at op.c​:9817
#4 0x000000000046c147 in Perl_newUNOP (type=type@​entry=17,
  flags=<optimized out>, flags@​entry=8192, first=0x27e48b8) at op.c​:4815
#5 0x000000000046cafb in Perl_newCVREF (flags=flags@​entry=8192,
  o=<optimized out>) at op.c​:9380
#6 0x00000000005da770 in Perl_yylex () at ..\toke.c​:6680
#7 0x000000000049c283 in Perl_yyparse (gramtype=gramtype@​entry=258)
  at ..\perly.c​:322
#8 0x0000000000499902 in S_parse_body (xsinit=0x2c,
  env=0x4013b5 <__tmainCRTStartup+565>) at perl.c​:2296
#9 perl_parse (my_perl=<optimized out>, xsinit=0x2c,
  xsinit@​entry=0x608520 <xs_init>, argc=<optimized out>,
  argv=<optimized out>, env=env@​entry=0x0) at perl.c​:1626
#10 0x00000000006225d0 in main (argc=2, argv=0xec4ef0, env=0xec2e30)
  at ..\miniperlmain.c​:120
(gdb)

I also traced to see what was freeing the GV​:

(gdb) b S_op_clear_gv
Breakpoint 1 at 0x462470​: file op.c, line 802.
(gdb) r ..\..\123976.pl
Starting program​: j​:\dev\perl\git\perl\miniperl.exe ..\..\123976.pl
[New Thread 6876.0x194c]

Breakpoint 1, S_op_clear_gv (o=o@​entry=0x2884218, svp=svp@​entry=0x2884240)
  at op.c​:802
802 {
(gdb) n
805 || o->op_type == OP_MULTIDEREF)
(gdb)
802 {
(gdb)
805 || o->op_type == OP_MULTIDEREF)
(gdb)
810 ? (GV*)(*svp) : NULL;
(gdb)
826 bool still_valid = gv && SvREFCNT(gv);
(gdb) p gv
$1 = (GV *) 0x287dc88
(gdb) p gv->sv_refcnt
$2 = 2
(gdb) watch -l gv->sv_refcnt
Hardware watchpoint 2​: -location gv->sv_refcnt
(gdb) c
Continuing.
Hardware watchpoint 2​: -location gv->sv_refcnt

Old value = 2
New value = 3
S_op_clear_gv (o=o@​entry=0x2884218, svp=svp@​entry=0x2884240) at op.c​:836
836 SvREFCNT_dec(*svp);
(gdb) c
Continuing.
Hardware watchpoint 2​: -location gv->sv_refcnt

Old value = 3
New value = 1
S_op_clear_gv (o=o@​entry=0x2884218, svp=svp@​entry=0x2884240) at op.c​:837
837 *svp = NULL;
(gdb) c
Continuing.
SV = PVGV(0x2873640) at 0x287dc88
  REFCNT = 1
  FLAGS = (MULTI,ASSUMECV)
  NAME = "foo"
  NAMELEN = 3
  GvSTASH = 0x11783b8 "main"
  FLAGS = 0x6
  GP = 0x28842e0
  SV = 0x0
  REFCNT = 1
  IO = 0x0
  FORM = 0x0
  AV = 0x0
  HV = 0x0
  CV = 0x287dd18
  CVGEN = 0x0
  GPFLAGS = 0x0 ()
  LINE = 2
  FILE = "..\..\123976.pl"
  EGV = 0x287dc88 "foo"
Hardware watchpoint 2​: -location gv->sv_refcnt

Old value = 1
New value = 0
Perl_sv_free2 (sv=sv@​entry=0x287dc88, rc=1) at ..\sv.c​:7021
7021 if (SvTEMP(sv)) {
(gdb) bt
#0 Perl_sv_free2 (sv=sv@​entry=0x287dc88, rc=1) at ..\sv.c​:7021
#1 0x0000000000462558 in S_SvREFCNT_dec_NN (sv=0x287dc88) at ../inline.h​:177
#2 S_op_clear_gv (o=o@​entry=0x2884218, svp=svp@​entry=0x2884240) at op.c​:842
#3 0x00000000004628d0 in Perl_op_clear (o=o@​entry=0x2884218) at op.c​:875
#4 0x0000000000462b48 in Perl_op_free (o=0x2884218) at op.c​:784
#5 0x0000000000462b12 in Perl_op_free (o=0x28841d8) at op.c​:767
#6 0x000000000048f409 in Perl_cv_undef_flags (cv=cv@​entry=0x287dc40,
  flags=flags@​entry=0) at ..\pad.c​:337
#7 0x000000000048fb27 in Perl_cv_undef (cv=cv@​entry=0x287dc40)
  at ..\pad.c​:299
#8 0x0000000000585955 in Perl_sv_clear (orig_sv=orig_sv@​entry=0x287dc40)
  at ..\sv.c​:6603
#9 0x0000000000586874 in Perl_sv_free2 (sv=0x287dc40, rc=<optimized out>)
  at ..\sv.c​:7033
#10 0x000000000049bdff in S_SvREFCNT_dec (sv=<optimized out>)
  at ../inline.h​:166
#11 Perl_yyparse (gramtype=gramtype@​entry=258) at ..\perly.c​:423
#12 0x0000000000499902 in S_parse_body (xsinit=0x2c,
  env=0x4013b5 <__tmainCRTStartup+565>) at perl.c​:2296
#13 perl_parse (my_perl=<optimized out>, xsinit=0x2c,
  xsinit@​entry=0x608520 <xs_init>, argc=<optimized out>,
  argv=<optimized out>, env=env@​entry=0x0) at perl.c​:1626
#14 0x00000000006225d0 in main (argc=2, argv=0x11722d0, env=0x1172a70)
  at ..\miniperlmain.c​:120
(gdb) c
Continuing.
SV = UNKNOWN(0xff) (0x287dca0) at 0x287dc88
  REFCNT = 0
  FLAGS = ()

Program received signal SIGSEGV, Segmentation fault.
Perl_gv_init_pvn (gv=0x287dc88, stash=0x11783b8, name=0x28842e0 "foo", len=3,
  flags=flags@​entry=0) at ..\gv.c​:412
412 *(char *)0 = 0;
(gdb) q

I'm not sure that tells us anything useful.

Tony

@p5pRT
Copy link
Author

p5pRT commented Apr 3, 2015

From @iabyn

On Thu, Apr 02, 2015 at 02​:58​:01PM -0700, Tony Cook via RT wrote​:

I also traced to see what was freeing the GV​:
[snip]
836 SvREFCNT_dec(*svp);
(gdb) c
Continuing.
Hardware watchpoint 2​: -location gv->sv_refcnt

Old value = 3
New value = 1
S_op_clear_gv (o=o@​entry=0x2884218, svp=svp@​entry=0x2884240) at op.c​:837
837 *svp = NULL;

I think that's the error. SvREFCNT_dec() appears to be decreasing
the refcount by *2* at that point; the "SvREFCNT_dec_NN(gv)" a few lines
later then reduces the count from 1 to 0 and so prematurely frees the
gv. By comparison, S_op_clear_gv() on my system changes the refcount in
steps as 2 => 3 => 2 => 1

I suspect that's a compiler bug.

--
The optimist believes that he lives in the best of all possible worlds.
As does the pessimist.

@p5pRT
Copy link
Author

p5pRT commented Apr 3, 2015

From @bulk88

On Fri Apr 03 01​:30​:31 2015, davem wrote​:

I think that's the error. SvREFCNT_dec() appears to be decreasing
the refcount by *2* at that point; the "SvREFCNT_dec_NN(gv)" a few lines
later then reduces the count from 1 to 0 and so prematurely frees the
gv. By comparison, S_op_clear_gv() on my system changes the refcount in
steps as 2 => 3 => 2 => 1

I suspect that's a compiler bug.

Can someone attach the broken binary? I want to take a peek in it.

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Apr 3, 2015

From @steve-m-hay

On Fri Apr 03 08​:35​:00 2015, bulk88 wrote​:

On Fri Apr 03 01​:30​:31 2015, davem wrote​:

I think that's the error. SvREFCNT_dec() appears to be decreasing
the refcount by *2* at that point; the "SvREFCNT_dec_NN(gv)" a few lines
later then reduces the count from 1 to 0 and so prematurely frees the
gv. By comparison, S_op_clear_gv() on my system changes the refcount in
steps as 2 => 3 => 2 => 1

I suspect that's a compiler bug.

Can someone attach the broken binary? I want to take a peek in it.

Attached.

C​:\Dev\Git\perl\win32>..\miniperl.exe -I..\lib -f ..\write_buildcustomize.pl ..
Attempt to free unreferenced scalar​: SV 0x389ca8 at ..\lib/strict.pm line 38.

@p5pRT
Copy link
Author

p5pRT commented Apr 3, 2015

From @steve-m-hay

miniperl.exe.gz

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2015

From @bulk88

On Fri Apr 03 10​:09​:21 2015, shay wrote​:

Attached.

C​:\Dev\Git\perl\win32>..\miniperl.exe -I..\lib -f
..\write_buildcustomize.pl ..
Attempt to free unreferenced scalar​: SV 0x389ca8 at ..\lib/strict.pm
line 38.

Does the perl521.dll version crash and can you attach the crashing perl.exe and perl521.dll, preferably unstripped? I can't really analyze the GCC miniperl.exe since it doesn't export anything (except accidental exports) and doesn't have symbols. Mingw64-64 4.8.2 isn't crashing for me, with out Cfg=Debug and with it on.

C​:\p521\srcpara>gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c​:/sources/mingw64/bin/../libexec/gcc/i686-w64-mingw32/4.8.2
/lto-wrapper.exe
Target​: i686-w64-mingw32
Configured with​: ../../../src/gcc-4.8.2/configure --host=i686-w64-mingw32 --buil
d=i686-w64-mingw32 --target=i686-w64-mingw32 --prefix=/mingw32 --with-sysroot=/t
mp/i686-482-win32-sjlj-rt_v3-r0/mingw32 --enable-shared --enable-static --enable
-targets=all --enable-multilib --enable-languages=ada,c,c++,fortran,objc,obj-c++
,lto --enable-libstdcxx-time=yes --enable-threads=win32 --enable-libgomp --enabl
e-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string
--enable-version-specific-runtime-libs --enable-sjlj-exceptions --disable-isl-ve
rsion-check --disable-cloog-version-check --disable-libstdcxx-pch --disable-libs
tdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disabl
e-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch
-32=i686 --with-arch-64=nocona --with-tune-32=generic --with-tune-64=core2 --wit
h-libiconv --with-system-zlib --with-gmp=/tmp/prerequisites/i686-w64-mingw32-sta
tic --with-mpfr=/tmp/prerequisites/i686-w64-mingw32-static --with-mpc=/tmp/prere
quisites/i686-w64-mingw32-static --with-isl=/tmp/prerequisites/i686-w64-mingw32-
static --with-cloog=/tmp/prerequisites/i686-w64-mingw32-static --enable-cloog-ba
ckend=isl --with-pkgversion='rev0, Built by MinGW-W64 project' --with-bugurl=htt
p​://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -I/tmp/i686-482-win32-s
jlj-rt_v3-r0/mingw32/opt/include -I/tmp/prerequisites/i686-zlib-static/include -
I/tmp/prerequisites/i686-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -I/tmp/
i686-482-win32-sjlj-rt_v3-r0/mingw32/opt/include -I/tmp/prerequisites/i686-zlib-
static/include -I/tmp/prerequisites/i686-w64-mingw32-static/include' CPPFLAGS= L
DFLAGS='-pipe -L/tmp/i686-482-win32-sjlj-rt_v3-r0/mingw32/opt/lib -L/tmp/prerequ
isites/i686-zlib-static/lib -L/tmp/prerequisites/i686-w64-mingw32-static/lib -Wl
,--large-address-aware'
Thread model​: win32
gcc version 4.8.2 (rev0, Built by MinGW-W64 project)

C​:\p521\srcpara>


BEGIN {
  my $bits = 0;
  *foo = sub () { $bits };
}
foo();


C​:\p521\srcpara>miniperl.exe -Ilib c.pl

C​:\p521\srcpara>


Also Strawberry 5.20-32 comes with 4.8.3, not 4.8.2, and it doesn't crash either.

-v reproduced below of SP 5.20's GCC


Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=C​:/sp3220/c/bin/../libexec/gcc/i686-w64-mingw32/4.8.3/lto-wr
apper.exe
Target​: i686-w64-mingw32
Configured with​: ../../../src/gcc-4.8.3/configure --host=i686-w64-mingw32 --buil
d=i686-w64-mingw32 --target=i686-w64-mingw32 --prefix=/mingw32 --with-gxx-includ
e-dir=/mingw32/i686-w64-mingw32/include/c++ --enable-shared --enable-static --di
sable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes
--enable-threads=posix --enable-libgomp --enable-lto --enable-graphite --enable-
checking=release --enable-fully-dynamic-string --enable-version-specific-runtime
-libs --enable-sjlj-exceptions --disable-isl-version-check --disable-cloog-versi
on-check --disable-libstdcxx-pch --disable-libstdcxx-debug --disable-bootstrap -
-disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable
-symvers --with-gnu-as --with-gnu-ld --with-arch=i686 --with-tune=generic --with
-libiconv --with-system-zlib --with-gmp=/opt/build/prerequisites/i686-w64-mingw3
2-static --with-mpfr=/opt/build/prerequisites/i686-w64-mingw32-static --with-mpc
=/opt/build/prerequisites/i686-w64-mingw32-static --with-isl=/opt/build/prerequi
sites/i686-w64-mingw32-static --with-cloog=/opt/build/prerequisites/i686-w64-min
gw32-static --enable-cloog-backend=isl --with-pkgversion='i686-posix-sjlj, built
by strawberryperl.com project' CFLAGS='-O2 -pipe -I/opt/build/i686-483-posix-sj
lj-rt_v3/mingw32/opt/include -I/opt/build/prerequisites/i686-zlib-static/include
-I/opt/build/prerequisites/i686-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe
-I/opt/build/i686-483-posix-sjlj-rt_v3/mingw32/opt/include -I/opt/build/prerequ
isites/i686-zlib-static/include -I/opt/build/prerequisites/i686-w64-mingw32-stat
ic/include' CPPFLAGS= LDFLAGS='-pipe -L/opt/build/i686-483-posix-sjlj-rt_v3/ming
w32/opt/lib -L/opt/build/prerequisites/i686-zlib-static/lib -L/opt/build/prerequ
isites/i686-w64-mingw32-static/lib'
Thread model​: posix
gcc version 4.8.3 (i686-posix-sjlj, built by strawberryperl.com project)


--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2015

From @steve-m-hay

On Sun Apr 05 02​:08​:22 2015, bulk88 wrote​:

On Fri Apr 03 10​:09​:21 2015, shay wrote​:

Attached.

C​:\Dev\Git\perl\win32>..\miniperl.exe -I..\lib -f
..\write_buildcustomize.pl ..
Attempt to free unreferenced scalar​: SV 0x389ca8 at ..\lib/strict.pm
line 38.

Does the perl521.dll version crash and can you attach the crashing
perl.exe and perl521.dll, preferably unstripped? I can't really
analyze the GCC miniperl.exe since it doesn't export anything (except
accidental exports) and doesn't have symbols. Mingw64-64 4.8.2 isn't
crashing for me, with out Cfg=Debug and with it on.

It doesn't get as far as building perl521.dll/perl.exe because the miniperl.exe that would be used to build them crashes. It crashes in either release or debug (CFG=Debug) configurations. I've attached the miniperl.exe from a debug build in case its of any use, but it sounds like it won't be.

I will try putting a miniperl from a different perl build in place and see if that lets the build continue to produce a perl521.dll/perl.exe...

Meanwhile, here is the configuration of the MinGW-w64 gcc-4.8.0 that I'm using (It's a 64-bit Windows build which targets 64-bit Windows. The download file is called "x86_64-w64-mingw32-gcc-4.8.0-win64_rubenvb.7z" and I downloaded it from http​://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/rubenvb/gcc-4.8-release/ )​:

Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=c​:/dev/software/mingw-w64/x64/4.8.0/bin/../libexec/gcc/x86_64-w64-mingw32/4.8.0/lto-wrapper.exe
Target​: x86_64-w64-mingw32
Configured with​: /home/ruben/mingw-w64/src/gcc/configure --host=x86_64-w64-mingw32 --build=x86_64-linux-gnu --target=x86_64-w64-mingw32 --with-sysroot=/home/ruben/mingw-w64/mingw64mingw64/mingw64 --prefix=/home/ruben/mingw-w64/mingw64mingw64/mingw64 --with-gmp=/home/ruben/mingw-w64/prereq/x86_64-w64-mingw32/install --with-mpfr=/home/ruben/mingw-w64/prereq/x86_64-w64-mingw32/install --with-mpc=/home/ruben/mingw-w64/prereq/x86_64-w64-mingw32/install --with-cloog=/home/ruben/mingw-w64/prereq/x86_64-w64-mingw32/install --disable-cloog-version-check --with-isl=/home/ruben/mingw-w64/prereq/x86_64-w64-mingw32/install --enable-cloog-backend=isl --with-host-libstdcxx='-static -lstdc++ -lm' --enable-shared --enable-static --enable-threads=win32 --enable-plugins --disable-multilib --enable-languages=c,lto,c++,objc,obj-c++,fortran,java --enable-libgomp --enable-fully-dynamic-string --enable-libstdcxx-time --disable-nls --disable-werror --enable-checking=release --with-gnu-as --with-gnu-ld --disable-win32-registry --disable-rpath --disable-werror --with-libiconv-prefix=/home/ruben/mingw-w64/prereq/x86_64-w64-mingw32/install --with-pkgversion=rubenvb-4.8.0 --with-bugurl=mingw-w64-public@​lists.sourceforge.net CC= CFLAGS='-O2 -march=nocona -mtune=core2 -fomit-frame-pointer -momit-leaf-frame-pointer' CXXFLAGS='-O2 -march=nocona -mtune=core2 -fomit-frame-pointer -momit-leaf-frame-pointer' LDFLAGS= 'BOOT_CFLAGS=-O2 -march=nocona -mtune=core2 -fomit-frame-pointer -momit-leaf-frame-pointer' 'BOOT_CXXFLAGS=-O2 -march=nocona -mtune=core2 -fomit-frame-pointer -momit-leaf-frame-pointer' BOOT_LDFLAGS= 'CFLAGS_FOR_TARGET= -O2 -march=nocona -mtune=core2 -fgraphite-identity -floop-interchange -floop-block -floop-parallelize-all' 'CXXFLAGS_FOR_TARGET= -O2 -march=nocona -mtune=core2 -fgraphite-identity -floop-interchange -floop-block -floop-parallelize-all' LDFLAGS_FOR_TARGET=
Thread model​: win32
gcc version 4.8.0 (rubenvb-4.8.0)

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2015

From @steve-m-hay

miniperl.exe.gz

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2015

From @steve-m-hay

On Sun Apr 05 09​:40​:01 2015, shay wrote​:

On Sun Apr 05 02​:08​:22 2015, bulk88 wrote​:

On Fri Apr 03 10​:09​:21 2015, shay wrote​:

Attached.

C​:\Dev\Git\perl\win32>..\miniperl.exe -I..\lib -f
..\write_buildcustomize.pl ..
Attempt to free unreferenced scalar​: SV 0x389ca8 at
..\lib/strict.pm
line 38.

Does the perl521.dll version crash and can you attach the crashing
perl.exe and perl521.dll, preferably unstripped? I can't really
analyze the GCC miniperl.exe since it doesn't export anything (except
accidental exports) and doesn't have symbols. Mingw64-64 4.8.2 isn't
crashing for me, with out Cfg=Debug and with it on.

It doesn't get as far as building perl521.dll/perl.exe because the
miniperl.exe that would be used to build them crashes. It crashes in
either release or debug (CFG=Debug) configurations. I've attached the
miniperl.exe from a debug build in case its of any use, but it sounds
like it won't be.

I will try putting a miniperl from a different perl build in place and
see if that lets the build continue to produce a
perl521.dll/perl.exe...

I put a miniperl.exe from a gcc-4.7.2 build into place and that allowed the gcc-4.8.0 build to complete, but the resulting perl.exe doesn't suffer the same problem as the miniperl.exe did, even when used to run the same write_buildcustomize.pl command.

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2015

From @bulk88

On Sun Apr 05 10​:05​:55 2015, shay wrote​:

I put a miniperl.exe from a gcc-4.7.2 build into place and that
allowed the gcc-4.8.0 build to complete, but the resulting perl.exe
doesn't suffer the same problem as the miniperl.exe did, even when
used to run the same write_buildcustomize.pl command.

I can reproduce now with the rubenvb build. But if I breath at the bug, the attempt to free unreferenced goes away. This tiny little patch fixed it for me. Also -O0 and -O1 dont have the bug.

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2015

From @bulk88

0001-add-watchsv.patch
From 564879a4ea0ae4391693b5f1c8c9237f96c64da8 Mon Sep 17 00:00:00 2001
From: Daniel Dragan <bulk88@hotmail.com>
Date: Sun, 5 Apr 2015 19:21:58 -0400
Subject: [PATCH] add watchsv

---
 inline.h   | 4 ++++
 perlvars.h | 1 +
 sv.c       | 1 +
 3 files changed, 6 insertions(+)

diff --git a/inline.h b/inline.h
index 46a8cb6..2919384 100644
--- a/inline.h
+++ b/inline.h
@@ -159,6 +159,8 @@ PERL_STATIC_INLINE void
 S_SvREFCNT_dec(pTHX_ SV *sv)
 {
     if (LIKELY(sv != NULL)) {
+	if(sv == PL_watch_sv)
+	    DebugBreak();
 	U32 rc = SvREFCNT(sv);
 	if (LIKELY(rc > 1))
 	    SvREFCNT(sv) = rc - 1;
@@ -171,6 +173,8 @@ PERL_STATIC_INLINE void
 S_SvREFCNT_dec_NN(pTHX_ SV *sv)
 {
     U32 rc = SvREFCNT(sv);
+    if(sv == PL_watch_sv)
+	    DebugBreak();
     if (LIKELY(rc > 1))
 	SvREFCNT(sv) = rc - 1;
     else
diff --git a/perlvars.h b/perlvars.h
index 7bafa40..c2262e8 100644
--- a/perlvars.h
+++ b/perlvars.h
@@ -237,3 +237,4 @@ PERLVAR(G, malloc_mutex, perl_mutex)	/* Mutex for malloc */
 
 PERLVARI(G, hash_seed_set, bool, FALSE)	/* perl.c */
 PERLVARA(G, hash_seed, PERL_HASH_SEED_BYTES, unsigned char) /* perl.c and hv.h */
+PERLVARI(G, watch_sv, SV *, NULL)
diff --git a/sv.c b/sv.c
index 467dc24..67524cc 100644
--- a/sv.c
+++ b/sv.c
@@ -7066,6 +7066,7 @@ Perl_sv_free2(pTHX_ SV *const sv, const U32 rc)
         }
 #endif
         /* This may not return:  */
+        DebugBreak();
         Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
                     "Attempt to free unreferenced scalar: SV 0x%"UVxf
                     pTHX__FORMAT, PTR2UV(sv) pTHX__VALUE);
-- 
1.8.0.msysgit.0

@p5pRT
Copy link
Author

p5pRT commented Apr 5, 2015

From @bulk88

On Sun Apr 05 16​:30​:37 2015, bulk88 wrote​:

PERL_STATIC_INLINE void
S_SvREFCNT_dec(pTHX_ SV *sv)
{
  if (LIKELY(sv != NULL)) {
  volatile U32 rc = SvREFCNT(sv);
  if (LIKELY(rc > 1))
  SvREFCNT(sv) = rc - 1;
  else
  Perl_sv_free2(aTHX_ sv, rc);
  }
}

fixes it. IDK why yet.

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Apr 6, 2015

From @bulk88

The sin that http​://perl5.git.perl.org/perl.git/commitdiff/ab57679753417e2765475e79c13a2adc48615ac0 "add S_op_clear_gv() to op.c" did was creating a pointer alias. GV * gv, in 1 one branch might be created from "(GV*(*svp)".

Then in quick succession, and function call free (side effects dont have to be stored to mem until the next function call (ABI reasons)), this executes, ++ the SV/GV *'s refcnt by 1.


  if (still_valid)
  SvREFCNT_inc_simple_void(gv);


then right after


#ifdef USE_ITHREADS
  if (*ixp > 0) {/* IGNORE THIS COMPILED OUT */
  pad_swipe(*ixp, TRUE);
  *ixp = 0;
  }
#else
  SvREFCNT_dec(*svp);
  *svp = NULL;
#endif


we -- the same SV *, but through a different C auto.

Since GCC -O2 always includes "-fstrict-aliasing" by default, 2 different C autos holding the same ptr is forbidden on paper (if I understand the concept correctly). VC doesn't do such dangerous optimizations so life is easy in VC land :D

I've included 2 pics of the asm code showing how the volatile version that writes to C stack, writes, then reads, while the version without volatile, READS, THEN WRITES a stale copy. Doing the read before the write, is http​://en.wikipedia.org/wiki/Instruction-level_parallelism or breaking up dependencies/pipline stalls in the CPU. In designing a CPU, writes to memory can be slower/lazier than reads from memory, since a slow read stops the CPU, while a slow write is invisible, and the next instruction can execute immediately. So GCC's "instruction scheduler" reordered them.

The real bug is GCC Win32 miniperl failed to do -fno-strict-aliasing the way Win32 GCC full perl does. The -fno-strict-aliasing for full Win32 perl is from http​://perl5.git.perl.org/perl.git/commitdiff/7a1f88acf2a2aec3c61c878c837070234df78c08 from 2000 with nothing that I can find (maybe you can find somethign) on the ML from Sarathy so it is unknown why he did that. I've attached a patch which fixes the lack of Win32 GCC miniperl not having fno-strict-aliasing. I have no comment on whether fno-strict-aliasing is appropriate for the perl 5 project or not but I did find this thread from 1999 when GCC first implemented the optimization. http​://markmail.org/message/v5r4lylkgv5zk2uk

--
bulk88 ~ bulk88 at hotmail.com

@p5pRT
Copy link
Author

p5pRT commented Apr 6, 2015

From @bulk88

0001-fix-123976-Win32-GCC-miniperl-needs-fno-strict-alias.patch
From 72e70f1bc568a8c06a2dd1d6ee9eef356e05d945 Mon Sep 17 00:00:00 2001
From: Daniel Dragan <bulk88@hotmail.com>
Date: Sun, 5 Apr 2015 21:39:14 -0400
Subject: [PATCH] fix #123976 Win32 GCC miniperl needs -fno-strict-aliasing

just like full perl uses -fno-strict-aliasing
---
 win32/makefile.mk | 1 +
 1 file changed, 1 insertion(+)

diff --git a/win32/makefile.mk b/win32/makefile.mk
index 5fd10dc..34dd7e9 100644
--- a/win32/makefile.mk
+++ b/win32/makefile.mk
@@ -511,6 +511,7 @@ EXEOUT_FLAG	= -o
 LIBOUT_FLAG	=
 
 BUILDOPT	+= -fno-strict-aliasing -mms-bitfields
+MINIBUILDOPT	+= -fno-strict-aliasing
 
 .ELSE
 
-- 
1.8.0.msysgit.0

@p5pRT
Copy link
Author

p5pRT commented Apr 6, 2015

From @bulk88

0001-selective-volatile-in-S_SvREFCNT_dec.patch
From 270a7da6c53a7fbe98992b850a9271a8bd808425 Mon Sep 17 00:00:00 2001
From: Daniel Dragan <bulk88@hotmail.com>
Date: Sun, 5 Apr 2015 21:15:39 -0400
Subject: [PATCH] selective volatile in S_SvREFCNT_dec

---
 inline.h |  3 +++
 op.c     | 32 ++++++++++++++++++++++++++++++--
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/inline.h b/inline.h
index 46a8cb6..92fe94b 100644
--- a/inline.h
+++ b/inline.h
@@ -155,6 +155,8 @@ S_SvREFCNT_inc_void(SV *sv)
     if (LIKELY(sv != NULL))
 	SvREFCNT(sv)++;
 }
+
+#ifndef NODEC
 PERL_STATIC_INLINE void
 S_SvREFCNT_dec(pTHX_ SV *sv)
 {
@@ -166,6 +168,7 @@ S_SvREFCNT_dec(pTHX_ SV *sv)
 	    Perl_sv_free2(aTHX_ sv, rc);
     }
 }
+#endif
 
 PERL_STATIC_INLINE void
 S_SvREFCNT_dec_NN(pTHX_ SV *sv)
diff --git a/op.c b/op.c
index ad0b0b0..cc59ad4 100644
--- a/op.c
+++ b/op.c
@@ -97,7 +97,8 @@ recursive, but it's recursive on basic blocks, not on tree nodes.
    saves the current C<PL_compiling.cop_hints_hash> on the save stack, so that
    it will be correctly restored when any inner compiling scope is exited.
 */
-
+#define NODEC
+#define S_SvREFCNT_dec S_SvREFCNT_decNV
 #include "EXTERN.h"
 #define PERL_IN_OP_C
 #include "perl.h"
@@ -105,6 +106,29 @@ recursive, but it's recursive on basic blocks, not on tree nodes.
 #include "feature.h"
 #include "regcomp.h"
 
+PERL_STATIC_INLINE void
+S_SvREFCNT_decV(pTHX_ SV *sv)
+{
+    if (LIKELY(sv != NULL)) {
+	volatile U32 rc = SvREFCNT(sv);
+	if (LIKELY(rc > 1))
+	    SvREFCNT(sv) = rc - 1;
+	else
+	    Perl_sv_free2(aTHX_ sv, rc);
+    }
+}
+PERL_STATIC_INLINE void
+S_SvREFCNT_decNV(pTHX_ SV *sv)
+{
+    if (LIKELY(sv != NULL)) {
+	U32 rc = SvREFCNT(sv);
+	if (LIKELY(rc > 1))
+	    SvREFCNT(sv) = rc - 1;
+	else
+	    Perl_sv_free2(aTHX_ sv, rc);
+    }
+}
+
 #define CALL_PEEP(o) PL_peepp(aTHX_ o)
 #define CALL_RPEEP(o) PL_rpeepp(aTHX_ o)
 #define CALL_OPFREEHOOK(o) if (PL_opfreehook) PL_opfreehook(aTHX_ o)
@@ -800,7 +824,9 @@ void S_op_clear_gv(pTHX_ OP *o, PADOFFSET *ixp)
 void S_op_clear_gv(pTHX_ OP *o, SV**svp)
 #endif
 {
-
+/* change from S_SvREFCNT_decV to S_SvREFCNT_decNV to see crash */
+#undef S_SvREFCNT_dec
+#define S_SvREFCNT_dec S_SvREFCNT_decV
     GV *gv = (o->op_type == OP_GV || o->op_type == OP_GVSV
             || o->op_type == OP_MULTIDEREF)
 #ifdef USE_ITHREADS
@@ -842,6 +868,8 @@ void S_op_clear_gv(pTHX_ OP *o, SV**svp)
         if (try_downgrade)
             gv_try_downgrade(gv);
     }
+#undef S_SvREFCNT_dec
+#define S_SvREFCNT_dec S_SvREFCNT_decNV
 }
 
 
-- 
1.8.0.msysgit.0

@p5pRT
Copy link
Author

p5pRT commented Apr 6, 2015

From @bulk88

withoutvol.PNG

@p5pRT
Copy link
Author

p5pRT commented Apr 6, 2015

From @bulk88

withvol.PNG

@p5pRT
Copy link
Author

p5pRT commented Apr 6, 2015

From @iabyn

On Sun, Apr 05, 2015 at 06​:55​:57PM -0700, bulk88 via RT wrote​:

The sin that
http​://perl5.git.perl.org/perl.git/commitdiff/ab57679753417e2765475e79c13a2adc48615ac0
"add S_op_clear_gv() to op.c" did was creating a pointer alias. GV * gv,
in 1 one branch might be created from "(GV*(*svp)".

That commit didn't introduce the aliasing - that was already present - it
just moved the code into a separate function.

I've attached a patch which fixes the lack of Win32 GCC miniperl not
having fno-strict-aliasing.

I think that is the correct approach.

I have no comment on whether fno-strict-aliasing is appropriate for the
perl 5 project or not

I think it's its definitely needed. For example it's a common core
practice to create an aliased var with a cast for convenience, e.g.

  switch (sv->sv_type) {
  case SVt_PVHV​: {
  HV *hv = (HV*)sv;
  ....
  }
  ....
  }

(Although it's perhaps less common to continue using the first var after
the alias has been created.)

--
My Dad used to say 'always fight fire with fire', which is probably why
he got thrown out of the fire brigade.

@p5pRT
Copy link
Author

p5pRT commented Apr 6, 2015

From @steve-m-hay

On 6 April 2015 at 11​:20, Dave Mitchell <davem@​iabyn.com> wrote​:

On Sun, Apr 05, 2015 at 06​:55​:57PM -0700, bulk88 via RT wrote​:

The sin that
http​://perl5.git.perl.org/perl.git/commitdiff/ab57679753417e2765475e79c13a2adc48615ac0
"add S_op_clear_gv() to op.c" did was creating a pointer alias. GV * gv,
in 1 one branch might be created from "(GV*(*svp)".

That commit didn't introduce the aliasing - that was already present - it
just moved the code into a separate function.

I've attached a patch which fixes the lack of Win32 GCC miniperl not
having fno-strict-aliasing.

I think that is the correct approach.

Confirmed it fixes the problem here too, so now applied in commit
c038896.

Many thanks for fixing this!

@p5pRT
Copy link
Author

p5pRT commented Apr 6, 2015

@steve-m-hay - Status changed from 'open' to 'pending release'

@p5pRT
Copy link
Author

p5pRT commented Jun 2, 2015

From @khwilliamson

Thank you for submitting this ticket.

The issue should now be resolved with the release today of Perl v5.22, which is available at http​://www.perl.org/get.html
--
Karl Williamson for the Perl 5 team

@p5pRT p5pRT closed this as completed Jun 2, 2015
@p5pRT
Copy link
Author

p5pRT commented Jun 2, 2015

@khwilliamson - Status changed from 'pending release' 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