Stop $unicode =~ /[[:posix:]]/ from leaking
authorFather Chrysostomos <sprout@cpan.org>
Sun, 18 Nov 2012 21:29:56 +0000 (13:29 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Sun, 18 Nov 2012 22:02:37 +0000 (14:02 -0800)
If we have just created an SV, it has a reference count of 1, so using
newRV_inc on it will create a leak.  So we need to use newRV_noinc and
do SvREFCNT_inc in those cases where the SV is not new.

This has leaked since v5.17.3-117-g87367d5.

t/op/svleak.t
utf8.c

index 3c35fc6..2d9c692 100644 (file)
@@ -15,7 +15,7 @@ BEGIN {
 
 use Config;
 
-plan tests => 72;
+plan tests => 74;
 
 # run some code N times. If the number of SVs at the end of loop N is
 # greater than (N-1)*delta at the end of loop 1, we've got a leak
@@ -184,6 +184,8 @@ eleak(2,0,'/[\xdf]/i');
 eleak(2,0,'s![^/]!!');
 eleak(2,0,'/[pp]/');
 eleak(2,0,'/[[:ascii:]]/');
+eleak(2,0,'chr(0x100) =~ /[[:punct:]]/');
+eleak(2,0,'chr(0x100) =~ /[[:^punct:]]/');
 leak(2,0,sub { /(??{})/ }, '/(??{})/');
 
 leak(2,0,sub { !$^V }, '[perl #109762] version object in boolean context');
diff --git a/utf8.c b/utf8.c
index 322bc46..bde7f87 100644 (file)
--- a/utf8.c
+++ b/utf8.c
@@ -2945,6 +2945,8 @@ Perl__core_swash_init(pTHX_ const char* pkg, const char* name, SV *listsv, I32 m
        SV** swash_invlistsvp = NULL;
        SV* swash_invlist = NULL;
        bool invlist_in_swash_is_valid = FALSE;
+       bool swash_invlist_unclaimed = FALSE; /* whether swash_invlist has
+                                           an unclaimed reference count */
 
         /* If this operation fetched a swash, get its already existing
          * inversion list, or create one for it */
@@ -2957,6 +2959,7 @@ Perl__core_swash_init(pTHX_ const char* pkg, const char* name, SV *listsv, I32 m
            }
            else {
                swash_invlist = _swash_to_invlist(retval);
+               swash_invlist_unclaimed = TRUE;
            }
        }
 
@@ -2999,7 +3002,9 @@ Perl__core_swash_init(pTHX_ const char* pkg, const char* name, SV *listsv, I32 m
 
         if ((int) _invlist_len(swash_invlist) <= invlist_swash_boundary) {
            SvREFCNT_dec(retval);
-            retval = newRV_inc(swash_invlist);
+           if (!swash_invlist_unclaimed)
+               SvREFCNT_inc_simple_void_NN(swash_invlist);
+            retval = newRV_noinc(swash_invlist);
         }
     }