develooper Front page | perl.perl5.porters | Postings from February 2013

Re: PL_sv_objcount

Thread Previous | Thread Next
From:
Nicholas Clark
Date:
February 28, 2013 14:38
Subject:
Re: PL_sv_objcount
Message ID:
20130228143822.GI5653@plum.flirble.org
On Thu, Feb 28, 2013 at 07:58:00AM +0100, Steffen Mueller wrote:

> static void
> do_curse(pTHX_ SV * const sv) {
>    if ((PL_stderrgv && GvGP(PL_stderrgv) && (SV*)GvIO(PL_stderrgv) == sv)
>     || (PL_defoutgv && GvGP(PL_defoutgv) && (SV*)GvIO(PL_defoutgv) ==sv))
>      return;
>    (void)curse(sv, 0);
> }
> 
> I can make it fail *without* my changes by loading Exporter in the test 
> code:
> 
> # Used to warn
> # Unbalanced string table refcount: (1) for "A::" during global destruction.
> # for ithreads.
> {
>      local $ENV{PERL_DESTRUCT_LEVEL} = 2;
>      fresh_perl_is(
> 		  'use Exporter; package A; sub a { // }; %::=""',
> 		  '',
> 		  '',
> 		  );
> }
> 
> I'm willing to poke at this, but the global destruction logic is 
> daunting. So I'm very willing to concede this to somebody else or accept 
> any kind of advice and support.

Bisecting shows that the failure first appears in commit 4155e4fe81b9987a
which introduces do_curse(). (It temporarily disappears when that commit
is reverted, and is restored when the reversion is reverted).

The problem is that that the interpreter maintains a pointer, PL_stderrgv,
direct to *{STDERR}, without owning a reference count. Should that SV get
freed up, the interpreter *still* points to it. I've appended a fix for the
SEGV (pushed as smoke-me/nicholas/PL_stderrgv) which makes everything pass.

However, I'm not certain whether having the interpreter in a state where
PL_stderrgv is NULL is actually sane. Neither is wiping out the main symbol
table sane, but as it's something you can do from Perl space, it's not
supposed to create crashes. Whilst we could forbid the directly assignment to
%:: (much like VMS forbids list assignment to %ENV), I don't think that we
can forbid all routes that cause the GV pointed to by PL_stderrgv to be
freed. I guess unless we have the interpreter structure *own* a reference
to it.

Maybe that's the right solution.

Nicholas Clark

commit 1dae1d82c3edb8ba5fd619691fc1ac5d57fad68c
Author: Nicholas Clark <nick@ccl4.org>
Date:   Thu Feb 28 15:12:47 2013 +0100

    Set PL_stderrgv to NULL if it is freed.
    
    Without this, it's possible to hit assertion failures when global destruction
    attempts to skip the PVIO for PL_stderrgv while cleaning up all objects.

diff --git a/sv.c b/sv.c
index 727e283..09b180f 100644
--- a/sv.c
+++ b/sv.c
@@ -6257,6 +6257,8 @@ Perl_sv_clear(pTHX_ SV *const orig_sv)
 		PL_last_in_gv = NULL;
 	    else if ((const GV *)sv == PL_statgv)
 		PL_statgv = NULL;
+            else if ((const GV *)sv == PL_stderrgv)
+                PL_stderrgv = NULL;
 	case SVt_PVMG:
 	case SVt_PVNV:
 	case SVt_PVIV:
diff --git a/t/op/stash.t b/t/op/stash.t
index 616853b..fd5450e 100644
--- a/t/op/stash.t
+++ b/t/op/stash.t
@@ -7,7 +7,7 @@ BEGIN {
 
 BEGIN { require "./test.pl"; }
 
-plan( tests => 57 );
+plan( tests => 58 );
 
 # Used to segfault (bug #15479)
 fresh_perl_like(
@@ -63,6 +63,13 @@ package main;
 		  '',
 		  '',
 		  );
+    # Variant of the above which creates an object that persists until global
+    # destruction.
+    fresh_perl_is(
+		  'use Exporter; package A; sub a { // }; %::=""',
+		  '',
+		  '',
+		  );
 }
 
 # now tests in eval

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About