summaryrefslogtreecommitdiff
path: root/hv.c
diff options
context:
space:
mode:
authorNicholas Clark <nick@ccl4.org>2021-07-25 20:12:25 +0000
committerNicholas Clark <nick@ccl4.org>2021-09-18 18:40:19 +0000
commit73ace1cb5078023d3dca765f0f10329b8606fc05 (patch)
tree603228c3caeafb05a20e7fd743d05617c1230123 /hv.c
parent6a3871b339dd83437e4d00d00f6fd5e3e4069cec (diff)
downloadperl-73ace1cb5078023d3dca765f0f10329b8606fc05.tar.gz
Call mro_method_changed_in() later in hv_delete_common()
Move the call as late as possible - just before the deleted hash key is freed if G_DISCARD is set. In particular, move it *after* the HE is freed. Move the code that sets HeVAL() to &PL_sv_placeholder into the if block that handles restricted hashes - no need to set this on normal hashes, as the structure is about to be freed anyway.
Diffstat (limited to 'hv.c')
-rw-r--r--hv.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/hv.c b/hv.c
index 3dece08a6d..7f4a2e83db 100644
--- a/hv.c
+++ b/hv.c
@@ -1354,13 +1354,6 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
Safefree(key);
sv = d_flags & G_DISCARD ? HeVAL(entry) : sv_2mortal(HeVAL(entry));
- HeVAL(entry) = &PL_sv_placeholder;
- if (sv) {
- /* deletion of method from stash */
- if (isGV(sv) && isGV_with_GP(sv) && GvCVu(sv)
- && HvENAME_get(hv))
- mro_method_changed_in(hv);
- }
/*
* If a restricted hash, rather than really deleting the entry, put
@@ -1368,11 +1361,14 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
* we can still access via not-really-existing key without raising
* an error.
*/
- if (SvREADONLY(hv))
+ if (SvREADONLY(hv)) {
/* We'll be saving this slot, so the number of allocated keys
* doesn't go down, but the number placeholders goes up */
+ HeVAL(entry) = &PL_sv_placeholder;
HvPLACEHOLDERS(hv)++;
+ }
else {
+ HeVAL(entry) = NULL;
*oentry = HeNEXT(entry);
if (SvOOK(hv) && entry == HvAUX(hv)->xhv_eiter /* HvEITER(hv) */)
HvLAZYDEL_on(hv);
@@ -1387,6 +1383,13 @@ S_hv_delete_common(pTHX_ HV *hv, SV *keysv, const char *key, STRLEN klen,
HvHASKFLAGS_off(hv);
}
+ if (sv) {
+ /* deletion of method from stash */
+ if (isGV(sv) && isGV_with_GP(sv) && GvCVu(sv)
+ && HvENAME_get(hv))
+ mro_method_changed_in(hv);
+ }
+
if (d_flags & G_DISCARD) {
SvREFCNT_dec(sv);
sv = NULL;