This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Revert "Globs that are in the symbol table can be unglobbed"
[perl5.git] / hv.c
diff --git a/hv.c b/hv.c
index e82b74f..376b5dc 100644 (file)
--- a/hv.c
+++ b/hv.c
@@ -988,8 +988,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
     for (; entry; oentry = &HeNEXT(entry), entry = *oentry) {
        SV *sv;
        U8 mro_changes = 0; /* 1 = isa; 2 = package moved */
-       const char *name = NULL;
-       STRLEN namlen;
+       GV *gv = NULL;
        HV *stash = NULL;
 
        if (HeHASH(entry) != hash)              /* strings can't be equal */
@@ -1023,35 +1022,24 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
 
        /* If this is a stash and the key ends with ::, then someone is 
         * deleting a package.
-        * Check whether the gv (HeVAL(entry)) is still in the symbol
-        * table and then save the name to pass to mro_package_moved after
-        * the deletion.
-        * We cannot pass the gv to mro_package_moved directly, as that
-        * function also checks whether the gv is to be found at the loca-
-        * tion its name indicates, which will no longer be the case once
-        * this element is deleted. So we have to do that check here.
         */
        if (HeVAL(entry) && HvENAME_get(hv)) {
-               sv = HeVAL(entry);
+               gv = (GV *)HeVAL(entry);
                if (keysv) key = SvPV(keysv, klen);
                if (klen > 1 && key[klen-2] == ':' && key[klen-1] == ':'
                 && (klen != 6 || hv!=PL_defstash || memNE(key,"main::",6))
-                && SvTYPE(sv) == SVt_PVGV && (stash = GvHV((GV *)sv))
+                && SvTYPE(gv) == SVt_PVGV && (stash = GvHV((GV *)gv))
                 && HvENAME_get(stash)) {
-                   SV * const namesv = sv_newmortal();
-                   gv_fullname4(namesv, (GV *)sv, NULL, 0);
-                   if (
-                    gv_fetchsv(namesv, GV_NOADD_NOINIT, SVt_PVGV)
-                      == (GV *)sv
-                   ) {
+                       /* A previous version of this code checked that the
+                        * GV was still in the symbol table by fetching the
+                        * GV with its name. That is not necessary (and
+                        * sometimes incorrect), as HvENAME cannot be set
+                        * on hv if it is not in the symtab. */
                        mro_changes = 2;
-                       name = SvPV_const(namesv, namlen);
-                       namlen -= 2; /* skip trailing :: */
                        /* Hang on to it for a bit. */
                        SvREFCNT_inc_simple_void_NN(
-                        sv_2mortal((SV *)stash)
+                        sv_2mortal((SV *)gv)
                        );
-                   }
                }
                else if (klen == 3 && strnEQ(key, "ISA", 3))
                    mro_changes = 1;
@@ -1089,7 +1077,7 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
 
        if (mro_changes == 1) mro_isa_changed_in(hv);
        else if (mro_changes == 2)
-           mro_package_moved(NULL, stash, NULL, name, namlen);
+           mro_package_moved(NULL, stash, gv, 1);
 
        return sv;
     }
@@ -1654,28 +1642,18 @@ S_hfreeentries(pTHX_ HV *hv)
 {
     /* This is the array that we're going to restore  */
     HE **const orig_array = HvARRAY(hv);
-    HEK *name;
-    I32 name_count;
+    HE **tmp_array = NULL;
+    const bool has_aux = SvOOK(hv);
+    struct xpvhv_aux * current_aux = NULL;
     int attempts = 100;
+    
+    const bool mpm = PL_phase != PERL_PHASE_DESTRUCT && HvENAME(hv);
 
     PERL_ARGS_ASSERT_HFREEENTRIES;
 
     if (!orig_array)
        return;
 
-    if (SvOOK(hv)) {
-       /* If the hash is actually a symbol table with a name, look after the
-          name.  */
-       struct xpvhv_aux *iter = HvAUX(hv);
-
-       name = iter->xhv_name;
-       name_count = iter->xhv_name_count;
-       iter->xhv_name = NULL;
-    } else {
-       name = NULL;
-       name_count = 0;
-    }
-
     /* orig_array remains unchanged throughout the loop. If after freeing all
        the entries it turns out that one of the little blighters has triggered
        an action that has caused HvARRAY to be re-allocated, then we set
@@ -1688,14 +1666,36 @@ S_hfreeentries(pTHX_ HV *hv)
        HE ** const array = HvARRAY(hv);
        I32 i = HvMAX(hv);
 
-       /* Because we have taken xhv_name out, the only allocated pointer
-          in the aux structure that might exist is the backreference array.
-       */
+       struct xpvhv_aux *iter = SvOOK(hv) ? HvAUX(hv) : NULL;
+
+       /* make everyone else think the array is empty, so that the destructors
+        * called for freed entries can't recursively mess with us */
+       HvARRAY(hv) = NULL;
 
        if (SvOOK(hv)) {
            HE *entry;
-            struct mro_meta *meta;
-           struct xpvhv_aux *iter = HvAUX(hv);
+
+           SvFLAGS(hv) &= ~SVf_OOK; /* Goodbye, aux structure.  */
+           /* What aux structure?  */
+           /* (But we still have a pointer to it in iter.) */
+
+           /* Copy the name and MRO stuff to a new aux structure
+              if present. */
+           if (iter->xhv_name || iter->xhv_mro_meta) {
+               struct xpvhv_aux * const newaux = hv_auxinit(hv);
+               newaux->xhv_name = iter->xhv_name;
+               newaux->xhv_name_count = iter->xhv_name_count;
+               iter->xhv_name = NULL;
+               newaux->xhv_mro_meta = iter->xhv_mro_meta;
+               iter->xhv_mro_meta = NULL;
+           }
+
+           /* Because we have taken xhv_name and
+              xhv_mro_meta out, the only allocated
+              pointers in the aux structure that might exist are the back-
+              reference array and xhv_eiter.
+            */
+
            /* weak references: if called from sv_clear(), the backrefs
             * should already have been killed; if there are any left, its
             * because we're doing hv_clear() or hv_undef(), and the HV
@@ -1745,35 +1745,15 @@ S_hfreeentries(pTHX_ HV *hv)
            iter->xhv_riter = -1;       /* HvRITER(hv) = -1 */
            iter->xhv_eiter = NULL;     /* HvEITER(hv) = NULL */
 
-            if((meta = iter->xhv_mro_meta)) {
-               if (meta->mro_linear_all) {
-                   SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_all));
-                   meta->mro_linear_all = NULL;
-                   /* This is just acting as a shortcut pointer.  */
-                   meta->mro_linear_current = NULL;
-               } else if (meta->mro_linear_current) {
-                   /* Only the current MRO is stored, so this owns the data.
-                    */
-                   SvREFCNT_dec(meta->mro_linear_current);
-                   meta->mro_linear_current = NULL;
-               }
-                if(meta->mro_nextmethod) SvREFCNT_dec(meta->mro_nextmethod);
-                SvREFCNT_dec(meta->isa);
-                Safefree(meta);
-                iter->xhv_mro_meta = NULL;
-            }
-
            /* There are now no allocated pointers in the aux structure.  */
-
-           SvFLAGS(hv) &= ~SVf_OOK; /* Goodbye, aux structure.  */
-           /* What aux structure?  */
        }
 
-       /* make everyone else think the array is empty, so that the destructors
-        * called for freed entries can't recursively mess with us */
-       HvARRAY(hv) = NULL;
-       ((XPVHV*) SvANY(hv))->xhv_keys = 0;
+       /* If there are no keys, there is nothing left to free. */
+       if (!((XPVHV*) SvANY(hv))->xhv_keys) break;
 
+       /* Since we have removed the HvARRAY (and possibly replaced it by
+          calling hv_auxinit), set the number of keys accordingly. */
+       ((XPVHV*) SvANY(hv))->xhv_keys = 0;
 
        do {
            /* Loop down the linked list heads  */
@@ -1782,6 +1762,19 @@ S_hfreeentries(pTHX_ HV *hv)
            while (entry) {
                register HE * const oentry = entry;
                entry = HeNEXT(entry);
+               if (
+                 mpm && HeVAL(oentry) && isGV(HeVAL(oentry)) &&
+                 GvHV(HeVAL(oentry)) && HvENAME(GvHV(HeVAL(oentry)))
+               ) {
+                   STRLEN klen;
+                   const char * const key = HePV(oentry,klen);
+                   if (klen > 1 && key[klen-1]==':' && key[klen-2]==':') {
+                       mro_package_moved(
+                        NULL, GvHV(HeVAL(oentry)),
+                        (GV *)HeVAL(oentry), 0
+                       );
+                   }
+               }
                hv_free_ent(hv, oentry);
            }
        } while (--i >= 0);
@@ -1798,42 +1791,34 @@ S_hfreeentries(pTHX_ HV *hv)
            break;
        }
 
-       if (SvOOK(hv)) {
-           /* Someone attempted to iterate or set the hash name while we had
-              the array set to 0.  We'll catch backferences on the next time
-              round the while loop.  */
-           assert(HvARRAY(hv));
-
-           if (HvAUX(hv)->xhv_name) {
-               if(HvAUX(hv)->xhv_name_count) {
-                   HEK ** const name = (HEK **)HvAUX(hv)->xhv_name;
-                   I32 const count = HvAUX(hv)->xhv_name_count;
-                   HEK **hekp = name + (count < 0 ? -count : count);
-                   while(hekp-- > name) 
-                       unshare_hek_or_pvn(*hekp, 0, 0, 0);
-                   Safefree(name);
-               }
-               else unshare_hek_or_pvn(HvAUX(hv)->xhv_name, 0, 0, 0);
-           }
-       }
-
        if (--attempts == 0) {
            Perl_die(aTHX_ "panic: hfreeentries failed to free hash - something is repeatedly re-creating entries");
        }
     }
        
+    /* Set aside the current array for now, in case we still need it. */
+    if (SvOOK(hv)) current_aux = HvAUX(hv);
+    if (HvARRAY(hv) && HvARRAY(hv) != orig_array)
+       tmp_array = HvARRAY(hv);
+
     HvARRAY(hv) = orig_array;
 
-    /* If the hash was actually a symbol table, put the name back.  */
-    if (name) {
-       /* We have restored the original array.  If name is non-NULL, then
-          the original array had an aux structure at the end. So this is
-          valid:  */
-       struct xpvhv_aux * const aux = HvAUX(hv);
+    if (has_aux)
        SvFLAGS(hv) |= SVf_OOK;
-       aux->xhv_name = name;
-       aux->xhv_name_count = name_count;
+    else
+       SvFLAGS(hv) &=~SVf_OOK;
+
+    /* If the hash was actually a symbol table, put the name and MRO
+       caches back.  */
+    if (current_aux) {
+       struct xpvhv_aux * const aux
+        = SvOOK(hv) ? HvAUX(hv) : hv_auxinit(hv);
+       aux->xhv_name = current_aux->xhv_name;
+       aux->xhv_name_count = current_aux->xhv_name_count;
+       aux->xhv_mro_meta   = current_aux->xhv_mro_meta;
     }
+
+    if (tmp_array) Safefree(tmp_array);
 }
 
 /*
@@ -1845,7 +1830,7 @@ Undefines the hash.
 */
 
 void
-Perl_hv_undef(pTHX_ HV *hv)
+Perl_hv_undef_flags(pTHX_ HV *hv, U32 flags)
 {
     dVAR;
     register XPVHV* xhv;
@@ -1856,19 +1841,75 @@ Perl_hv_undef(pTHX_ HV *hv)
     DEBUG_A(Perl_hv_assert(aTHX_ hv));
     xhv = (XPVHV*)SvANY(hv);
 
-    if ((name = HvENAME_get(hv)) && !PL_dirty)
-        mro_isa_changed_in(hv);
-
-    hfreeentries(hv);
-    if (name || (name = HvNAME(hv))) {
+    /* The name must be deleted before the call to hfreeeeentries so that
+       CVs are anonymised properly. But the effective name must be pre-
+       served until after that call (and only deleted afterwards if the
+       call originated from sv_clear). For stashes with one name that is
+       both the canonical name and the effective name, hv_name_set has to
+       allocate an array for storing the effective name. We can skip that
+       during global destruction, as it does not matter where the CVs point
+       if they will be freed anyway. */
+    if (PL_phase != PERL_PHASE_DESTRUCT && (name = HvNAME(hv))) {
         if (PL_stashcache)
            (void)hv_delete(PL_stashcache, name, HvNAMELEN_get(hv), G_DISCARD);
        hv_name_set(hv, NULL, 0, 0);
     }
-    SvFLAGS(hv) &= ~SVf_OOK;
-    Safefree(HvARRAY(hv));
-    xhv->xhv_max   = 7;        /* HvMAX(hv) = 7 (it's a normal hash) */
-    HvARRAY(hv) = 0;
+    hfreeentries(hv);
+    if (SvOOK(hv)) {
+      struct xpvhv_aux * const aux = HvAUX(hv);
+      struct mro_meta *meta;
+      bool zeroed = FALSE;
+
+      if ((name = HvENAME_get(hv))) {
+       if (PL_phase != PERL_PHASE_DESTRUCT) {
+           /* This must come at this point in case
+              mro_isa_changed_in dies. */
+           Zero(HvARRAY(hv), xhv->xhv_max+1 /* HvMAX(hv)+1 */, HE*);
+           zeroed = TRUE;
+
+           mro_isa_changed_in(hv);
+       }
+        if (PL_stashcache)
+           (void)hv_delete(
+                   PL_stashcache, name, HvENAMELEN_get(hv), G_DISCARD
+                 );
+      }
+
+      /* If this call originated from sv_clear, then we must check for
+       * effective names that need freeing, as well as the usual name. */
+      name = HvNAME(hv);
+      if (flags & HV_NAME_SETALL ? (const char *)aux->xhv_name : name) {
+        if (name && PL_stashcache)
+           (void)hv_delete(PL_stashcache, name, HvNAMELEN_get(hv), G_DISCARD);
+       hv_name_set(hv, NULL, 0, flags);
+      }
+      if((meta = aux->xhv_mro_meta)) {
+       if (meta->mro_linear_all) {
+           SvREFCNT_dec(MUTABLE_SV(meta->mro_linear_all));
+           meta->mro_linear_all = NULL;
+           /* This is just acting as a shortcut pointer.  */
+           meta->mro_linear_current = NULL;
+       } else if (meta->mro_linear_current) {
+           /* Only the current MRO is stored, so this owns the data.
+            */
+           SvREFCNT_dec(meta->mro_linear_current);
+           meta->mro_linear_current = NULL;
+       }
+       if(meta->mro_nextmethod) SvREFCNT_dec(meta->mro_nextmethod);
+       SvREFCNT_dec(meta->isa);
+       Safefree(meta);
+       aux->xhv_mro_meta = NULL;
+      }
+      if (!aux->xhv_name)
+       SvFLAGS(hv) &= ~SVf_OOK;
+      else if (!zeroed)
+       Zero(HvARRAY(hv), xhv->xhv_max+1 /* HvMAX(hv)+1 */, HE*);
+    }
+    if (!SvOOK(hv)) {
+       Safefree(HvARRAY(hv));
+       xhv->xhv_max   = 7;     /* HvMAX(hv) = 7 (it's a normal hash) */
+       HvARRAY(hv) = 0;
+    }
     HvPLACEHOLDERS_set(hv, 0);
 
     if (SvRMAGICAL(hv))
@@ -2064,7 +2105,7 @@ Perl_hv_name_set(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
        iter = HvAUX(hv);
        if (iter->xhv_name) {
            if(iter->xhv_name_count) {
-             if(!name) {
+             if(flags & HV_NAME_SETALL) {
                HEK ** const name = (HEK **)HvAUX(hv)->xhv_name;
                HEK **hekp = name + (
                    iter->xhv_name_count < 0
@@ -2080,24 +2121,34 @@ Perl_hv_name_set(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
                iter->xhv_name_count = 0;
              }
              else {
-               spot = (HEK **)iter->xhv_name;
                if(iter->xhv_name_count > 0) {
                    /* shift some things over */
-                   Renew(spot, iter->xhv_name_count, HEK *);
-                   spot[iter->xhv_name_count++] = spot[1];
+                   Renewc(
+                    iter->xhv_name, iter->xhv_name_count + 1, HEK *, HEK
+                   );
+                   spot = (HEK **)iter->xhv_name;
+                   spot[iter->xhv_name_count] = spot[1];
                    spot[1] = spot[0];
+                   iter->xhv_name_count = -(iter->xhv_name_count + 1);
                }
-               else if(*spot) {
+               else if(*(spot = (HEK **)iter->xhv_name)) {
                    unshare_hek_or_pvn(*spot, 0, 0, 0);
                }
              }
            }
-           else {
+           else if (flags & HV_NAME_SETALL) {
                unshare_hek_or_pvn(iter->xhv_name, 0, 0, 0);
                spot = &iter->xhv_name;
            }
+           else {
+               HEK * const existing_name = iter->xhv_name;
+               Newxc(iter->xhv_name, 2, HEK *, HEK);
+               iter->xhv_name_count = -2;
+               spot = (HEK **)iter->xhv_name;
+               spot[1] = existing_name;
+           }
        }
-       else spot = &iter->xhv_name;
+       else { spot = &iter->xhv_name; iter->xhv_name_count = 0; }
     } else {
        if (name == 0)
            return;
@@ -2107,7 +2158,6 @@ Perl_hv_name_set(pTHX_ HV *hv, const char *name, U32 len, U32 flags)
     }
     PERL_HASH(hash, name, len);
     *spot = name ? share_hek(name, len, hash) : NULL;
-    iter->xhv_name_count = 0;
 }
 
 /*