This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
msgrcv: properly downgrade the receive buffer
[perl5.git] / mg.c
diff --git a/mg.c b/mg.c
index 7d2314f..8b90aa4 100644 (file)
--- a/mg.c
+++ b/mg.c
@@ -16,7 +16,7 @@
  */
 
 /*
-=head1 Magical Functions
+=head1 Magic
 "Magic" is special data attached to SV structures in order to give them
 "magical" properties.  When any Perl code tries to read from, or assign to,
 an SV marked as magical, it calls the 'get' or 'set' function associated
@@ -34,6 +34,8 @@ plus space for some flags and pointers.  For example, a tied variable has
 a MAGIC structure that contains a pointer to the object associated with the
 tie.
 
+=for apidoc Ayh||MAGIC
+
 =cut
 
 */
@@ -41,6 +43,7 @@ tie.
 #include "EXTERN.h"
 #define PERL_IN_MG_C
 #include "perl.h"
+#include "feature.h"
 
 #if defined(HAS_GETGROUPS) || defined(HAS_SETGROUPS)
 #  ifdef I_GRP
@@ -62,12 +65,6 @@ tie.
 #  include <sys/prctl.h>
 #endif
 
-#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-Signal_t Perl_csighandler(int sig, siginfo_t *, void *);
-#else
-Signal_t Perl_csighandler(int sig);
-#endif
-
 #ifdef __Lynx__
 /* Missing protos on LynxOS */
 void setruid(uid_t id);
@@ -557,16 +554,10 @@ S_mg_free_struct(pTHX_ SV *sv, MAGIC *mg)
     if (vtbl && vtbl->svt_free)
        vtbl->svt_free(aTHX_ sv, mg);
 
-    if (mg->mg_type == PERL_MAGIC_collxfrm && mg->mg_len >= 0)
-        /* collate magic uses string len not buffer len, so
-         * free even with mg_len == 0 */
+    if (mg->mg_len > 0)
         Safefree(mg->mg_ptr);
-    else if (mg->mg_ptr && mg->mg_type != PERL_MAGIC_regex_global) {
-       if (mg->mg_len > 0 || mg->mg_type == PERL_MAGIC_utf8)
-           Safefree(mg->mg_ptr);
-       else if (mg->mg_len == HEf_SVKEY)
-           SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
-    }
+    else if (mg->mg_len == HEf_SVKEY)
+        SvREFCNT_dec(MUTABLE_SV(mg->mg_ptr));
 
     if (mg->mg_flags & MGf_REFCOUNTED)
        SvREFCNT_dec(mg->mg_obj);
@@ -851,6 +842,7 @@ S_fixup_errno_string(pTHX_ SV* sv)
 }
 
 /*
+=for apidoc_section $errno
 =for apidoc sv_string_from_errnum
 
 Generates the message string describing an OS error and returns it as
@@ -1035,9 +1027,6 @@ Perl_magic_get(pTHX_ SV *sv, MAGIC *mg)
         if (nextchar == '\0') {
             sv_setiv(sv, (IV)PL_maxsysfd);
         }
-        else if (strEQ(remaining, "EATURE_BITS")) {
-            sv_setuv(sv, PL_compiling.cop_features);
-        }
        break;
     case '\007':               /* ^GLOBAL_PHASE */
        if (strEQ(remaining, "LOBAL_PHASE")) {
@@ -1486,19 +1475,45 @@ Perl_magic_clearsig(pTHX_ SV *sv, MAGIC *mg)
     return sv_unmagic(sv, mg->mg_type);
 }
 
+
+#ifdef PERL_USE_3ARG_SIGHANDLER
 Signal_t
-#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-Perl_csighandler(int sig, siginfo_t *sip PERL_UNUSED_DECL, void *uap PERL_UNUSED_DECL)
+Perl_csighandler(int sig, Siginfo_t *sip, void *uap)
+{
+    Perl_csighandler3(sig, sip, uap);
+}
 #else
+Signal_t
 Perl_csighandler(int sig)
+{
+    Perl_csighandler3(sig, NULL, NULL);
+}
 #endif
+
+Signal_t
+Perl_csighandler1(int sig)
+{
+    Perl_csighandler3(sig, NULL, NULL);
+}
+
+/* Handler intended to directly handle signal calls from the kernel.
+ * (Depending on configuration, the kernel may actually call one of the
+ * wrappers csighandler() or csighandler1() instead.)
+ * It either queues up the signal or dispatches it immediately depending
+ * on whether safe signals are enabled and whether the signal is capable
+ * of being deferred (e.g. SEGV isn't).
+ */
+
+Signal_t
+Perl_csighandler3(int sig, Siginfo_t *sip PERL_UNUSED_DECL, void *uap PERL_UNUSED_DECL)
 {
 #ifdef PERL_GET_SIG_CONTEXT
     dTHXa(PERL_GET_SIG_CONTEXT);
 #else
     dTHX;
 #endif
-#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
+
+#ifdef PERL_USE_3ARG_SIGHANDLER
 #if defined(__cplusplus) && defined(__GNUC__)
     /* g++ doesn't support PERL_UNUSED_DECL, so the sip and uap
      * parameters would be warned about. */
@@ -1506,6 +1521,7 @@ Perl_csighandler(int sig)
     PERL_UNUSED_ARG(uap);
 #endif
 #endif
+
 #ifdef FAKE_PERSISTENT_SIGNAL_HANDLERS
     (void) rsignal(sig, PL_csighandlerp);
     if (PL_sig_ignoring[sig]) return;
@@ -1531,11 +1547,20 @@ Perl_csighandler(int sig)
           (PL_signals & PERL_SIGNALS_UNSAFE_FLAG))
        /* Call the perl level handler now--
         * with risk we may be in malloc() or being destructed etc. */
-#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-       (*PL_sighandlerp)(sig, NULL, NULL);
+    {
+        if (PL_sighandlerp == Perl_sighandler)
+            /* default handler, so can call perly_sighandler() directly
+             * rather than via Perl_sighandler, passing the extra
+             * 'safe = false' arg
+             */
+            Perl_perly_sighandler(sig, NULL, NULL, 0 /* unsafe */);
+        else
+#ifdef PERL_USE_3ARG_SIGHANDLER
+            (*PL_sighandlerp)(sig, NULL, NULL);
 #else
-       (*PL_sighandlerp)(sig);
+            (*PL_sighandlerp)(sig);
 #endif
+    }
     else {
        if (!PL_psig_pend) return;
        /* Set a flag to say this signal is pending, that is awaiting delivery after
@@ -1613,11 +1638,19 @@ Perl_despatch_signals(pTHX)
            }
 #endif
            PL_psig_pend[sig] = 0;
-#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-           (*PL_sighandlerp)(sig, NULL, NULL);
+            if (PL_sighandlerp == Perl_sighandler)
+                /* default handler, so can call perly_sighandler() directly
+                 * rather than via Perl_sighandler, passing the extra
+                 * 'safe = true' arg
+                 */
+                Perl_perly_sighandler(sig, NULL, NULL, 1 /* safe */);
+            else
+#ifdef PERL_USE_3ARG_SIGHANDLER
+                (*PL_sighandlerp)(sig, NULL, NULL);
 #else
-           (*PL_sighandlerp)(sig);
+                (*PL_sighandlerp)(sig);
 #endif
+
 #ifdef HAS_SIGPROCMASK
            if (!was_blocked)
                LEAVE;
@@ -1631,7 +1664,6 @@ Perl_despatch_signals(pTHX)
 int
 Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
 {
-    dVAR;
     I32 i;
     SV** svp = NULL;
     /* Need to be careful with SvREFCNT_dec(), because that can have side
@@ -1717,7 +1749,8 @@ Perl_magic_setsig(pTHX_ SV *sv, MAGIC *mg)
               Ideally we'd find some way of making SVs at (C) compile time, or
               at least, doing most of the work.  */
            if (!PL_psig_name[i]) {
-               PL_psig_name[i] = newSVpvn(s, len);
+               const char* name = PL_sig_name[i];
+               PL_psig_name[i] = newSVpvn(name, strlen(name));
                SvREADONLY_on(PL_psig_name[i]);
            }
        } else {
@@ -1873,6 +1906,7 @@ Perl_magic_setnkeys(pTHX_ SV *sv, MAGIC *mg)
 }
 
 /*
+=for apidoc_section $magic
 =for apidoc magic_methcall
 
 Invoke a magic method (like FETCH).
@@ -1933,8 +1967,8 @@ Perl_magic_methcall(pTHX_ SV *sv, const MAGIC *mg, SV *meth, U32 flags,
        va_start(args, argc);
 
        do {
-           SV *const sv = va_arg(args, SV *);
-           PUSHs(sv);
+           SV *const this_sv = va_arg(args, SV *);
+           PUSHs(this_sv);
        } while (--argc);
 
        va_end(args);
@@ -2564,6 +2598,23 @@ Perl_magic_setmglob(pTHX_ SV *sv, MAGIC *mg)
     return 0;
 }
 
+
+int
+Perl_magic_freemglob(pTHX_ SV *sv, MAGIC *mg)
+{
+    PERL_ARGS_ASSERT_MAGIC_FREEMGLOB;
+    PERL_UNUSED_ARG(sv);
+
+    /* glob magic uses mg_len as a string length rather than a buffer
+     * length, so we need to free even with mg_len == 0: hence we can't
+     * rely on standard magic free handling */
+    assert(mg->mg_type == PERL_MAGIC_regex_global && mg->mg_len >= -1);
+    Safefree(mg->mg_ptr);
+    mg->mg_ptr = NULL;
+    return 0;
+}
+
+
 int
 Perl_magic_setuvar(pTHX_ SV *sv, MAGIC *mg)
 {
@@ -2608,6 +2659,24 @@ Perl_magic_setcollxfrm(pTHX_ SV *sv, MAGIC *mg)
     }
     return 0;
 }
+
+int
+Perl_magic_freecollxfrm(pTHX_ SV *sv, MAGIC *mg)
+{
+    PERL_ARGS_ASSERT_MAGIC_FREECOLLXFRM;
+    PERL_UNUSED_ARG(sv);
+
+    /* Collate magic uses mg_len as a string length rather than a buffer
+     * length, so we need to free even with mg_len == 0: hence we can't
+     * rely on standard magic free handling */
+    if (mg->mg_len >= 0) {
+        assert(mg->mg_type == PERL_MAGIC_collxfrm);
+        Safefree(mg->mg_ptr);
+        mg->mg_ptr = NULL;
+    }
+
+    return 0;
+}
 #endif /* USE_LOCALE_COLLATE */
 
 /* Just clear the UTF-8 cache data. */
@@ -2624,6 +2693,22 @@ Perl_magic_setutf8(pTHX_ SV *sv, MAGIC *mg)
 }
 
 int
+Perl_magic_freeutf8(pTHX_ SV *sv, MAGIC *mg)
+{
+    PERL_ARGS_ASSERT_MAGIC_FREEUTF8;
+    PERL_UNUSED_ARG(sv);
+
+    /* utf8 magic uses mg_len as a string length rather than a buffer
+     * length, so we need to free even with mg_len == 0: hence we can't
+     * rely on standard magic free handling */
+    assert(mg->mg_type == PERL_MAGIC_utf8 && mg->mg_len >= -1);
+    Safefree(mg->mg_ptr);
+    mg->mg_ptr = NULL;
+    return 0;
+}
+
+
+int
 Perl_magic_setlvref(pTHX_ SV *sv, MAGIC *mg)
 {
     const char *bad = NULL;
@@ -2685,7 +2770,6 @@ S_set_dollarzero(pTHX_ SV *sv)
     PERL_TSA_REQUIRES(PL_dollarzero_mutex)
 {
 #ifdef USE_ITHREADS
-    dVAR;
 #endif
     const char *s;
     STRLEN len;
@@ -2764,7 +2848,6 @@ int
 Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
 {
 #ifdef USE_ITHREADS
-    dVAR;
 #endif
     I32 paren;
     const REGEXP * rx;
@@ -2848,9 +2931,6 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
         if (mg->mg_ptr[1] == '\0') {
             PL_maxsysfd = SvIV(sv);
         }
-        else if (strEQ(mg->mg_ptr + 1, "EATURE_BITS")) {
-            PL_compiling.cop_features = SvUV(sv);
-        }
        break;
     case '\010':       /* ^H */
         {
@@ -2932,9 +3012,7 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
        else if (strEQ(mg->mg_ptr+1, "ARNING_BITS")) {
            if ( ! (PL_dowarn & G_WARN_ALL_MASK)) {
                if (!SvPOK(sv)) {
-                    if (!specialWARN(PL_compiling.cop_warnings))
-                        PerlMemShared_free(PL_compiling.cop_warnings);
-                   PL_compiling.cop_warnings = pWARN_STD;
+            free_and_set_cop_warnings(&PL_compiling, pWARN_STD);
                    break;
                }
                {
@@ -2946,33 +3024,29 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
                        not_all |= ptr[i] ^ 0x55;
                    }
                    if (!not_none) {
-                       if (!specialWARN(PL_compiling.cop_warnings))
-                           PerlMemShared_free(PL_compiling.cop_warnings);
-                       PL_compiling.cop_warnings = pWARN_NONE;
+                free_and_set_cop_warnings(&PL_compiling, pWARN_NONE);
                    } else if (len >= WARNsize && !not_all) {
-                       if (!specialWARN(PL_compiling.cop_warnings))
-                           PerlMemShared_free(PL_compiling.cop_warnings);
-                       PL_compiling.cop_warnings = pWARN_ALL;
-                       PL_dowarn |= G_WARN_ONCE ;
-                   }
-                    else {
-                       STRLEN len;
-                       const char *const p = SvPV_const(sv, len);
-
-                       PL_compiling.cop_warnings
-                           = Perl_new_warnings_bitfield(aTHX_ PL_compiling.cop_warnings,
+                free_and_set_cop_warnings(&PL_compiling, pWARN_ALL);
+                   PL_dowarn |= G_WARN_ONCE ;
+               }
+            else {
+                            STRLEN len;
+                            const char *const p = SvPV_const(sv, len);
+
+                            PL_compiling.cop_warnings
+                                = Perl_new_warnings_bitfield(aTHX_ PL_compiling.cop_warnings,
                                                         p, len);
 
-                       if (isWARN_on(PL_compiling.cop_warnings, WARN_ONCE))
+                    if (isWARN_on(PL_compiling.cop_warnings, WARN_ONCE))
                            PL_dowarn |= G_WARN_ONCE ;
-                   }
+              }
 
                }
            }
        }
 #ifdef WIN32
        else if (strEQ(mg->mg_ptr+1, "IN32_SLOPPY_STAT")) {
-           w32_sloppystat = (bool)sv_true(sv);
+           w32_sloppystat = SvTRUE(sv);
        }
 #endif
        break;
@@ -3278,6 +3352,31 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
     return 0;
 }
 
+/*
+=for apidoc_section $signals
+=for apidoc whichsig
+=for apidoc_item whichsig_pv
+=for apidoc_item whichsig_pvn
+=for apidoc_item whichsig_sv
+
+These all convert a signal name into its corresponding signal number;
+returning -1 if no corresponding number was found.
+
+They differ only in the source of the signal name:
+
+C<whichsig_pv> takes the name from the C<NUL>-terminated string starting at
+C<sig>.
+
+C<whichsig> is merely a different spelling, a synonym, of C<whichsig_pv>.
+
+C<whichsig_pvn> takes the name from the string starting at C<sig>, with length
+C<len> bytes.
+
+C<whichsig_sv> takes the name from the PV stored in the SV C<sigsv>.
+
+=cut
+*/
+
 I32
 Perl_whichsig_sv(pTHX_ SV *sigsv)
 {
@@ -3317,12 +3416,62 @@ Perl_whichsig_pvn(pTHX_ const char *sig, STRLEN len)
     return -1;
 }
 
+
+/* Perl_sighandler(), Perl_sighandler1(), Perl_sighandler3():
+ * these three function are intended to be called by the OS as 'C' level
+ * signal handler functions in the case where unsafe signals are being
+ * used - i.e. they immediately invoke Perl_perly_sighandler() to call the
+ * perl-level sighandler, rather than deferring.
+ * In fact, the core itself will normally use Perl_csighandler as the
+ * OS-level handler; that function will then decide whether to queue the
+ * signal or call Perl_sighandler / Perl_perly_sighandler itself. So these
+ * functions are more useful for e.g. POSIX.xs when it wants explicit
+ * control of what's happening.
+ */
+
+
+#ifdef PERL_USE_3ARG_SIGHANDLER
+
 Signal_t
-#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-Perl_sighandler(int sig, siginfo_t *sip, void *uap)
+Perl_sighandler(int sig, Siginfo_t *sip, void *uap)
+{
+    Perl_perly_sighandler(sig, sip, uap, 0);
+}
+
 #else
+
+Signal_t
 Perl_sighandler(int sig)
+{
+    Perl_perly_sighandler(sig, NULL, NULL, 0);
+}
+
 #endif
+
+Signal_t
+Perl_sighandler1(int sig)
+{
+    Perl_perly_sighandler(sig, NULL, NULL, 0);
+}
+
+Signal_t
+Perl_sighandler3(int sig, Siginfo_t *sip PERL_UNUSED_DECL, void *uap PERL_UNUSED_DECL)
+{
+    Perl_perly_sighandler(sig, sip, uap, 0);
+}
+
+
+/* Invoke the perl-level signal handler. This function is called either
+ * directly from one of the C-level signals handlers (Perl_sighandler or
+ * Perl_csighandler), or for safe signals, later from
+ * Perl_despatch_signals() at a suitable safe point during execution.
+ *
+ * 'safe' is a boolean indicating the latter call path.
+ */
+
+Signal_t
+Perl_perly_sighandler(int sig, Siginfo_t *sip PERL_UNUSED_DECL,
+                    void *uap PERL_UNUSED_DECL, bool safe)
 {
 #ifdef PERL_GET_SIG_CONTEXT
     dTHXa(PERL_GET_SIG_CONTEXT);
@@ -3395,48 +3544,48 @@ Perl_sighandler(int sig)
     PUSHSTACKi(PERLSI_SIGNAL);
     PUSHMARK(SP);
     PUSHs(sv);
+
 #if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
     {
         struct sigaction oact;
 
-        if (sigaction(sig, 0, &oact) == 0 && oact.sa_flags & SA_SIGINFO) {
-             if (sip) {
-                  HV *sih = newHV();
-                  SV *rv  = newRV_noinc(MUTABLE_SV(sih));
-                  /* The siginfo fields signo, code, errno, pid, uid,
-                   * addr, status, and band are defined by POSIX/SUSv3. */
-                  (void)hv_stores(sih, "signo", newSViv(sip->si_signo));
-                  (void)hv_stores(sih, "code", newSViv(sip->si_code));
-#ifdef HAS_SIGINFO_SI_ERRNO
-                  (void)hv_stores(sih, "errno",      newSViv(sip->si_errno));
-#endif
-#ifdef HAS_SIGINFO_SI_STATUS
-                  (void)hv_stores(sih, "status",     newSViv(sip->si_status));
-#endif
-#ifdef HAS_SIGINFO_SI_UID
-                  {
-                       SV *uid = newSV(0);
-                       sv_setuid(uid, sip->si_uid);
-                       (void)hv_stores(sih, "uid", uid);
-                  }
-#endif
-#ifdef HAS_SIGINFO_SI_PID
-                  (void)hv_stores(sih, "pid",        newSViv(sip->si_pid));
-#endif
-#ifdef HAS_SIGINFO_SI_ADDR
-                  (void)hv_stores(sih, "addr",       newSVuv(PTR2UV(sip->si_addr)));
-#endif
-#ifdef HAS_SIGINFO_SI_BAND
-                  (void)hv_stores(sih, "band",       newSViv(sip->si_band));
-#endif
-                  EXTEND(SP, 2);
-                  PUSHs(rv);
-                  mPUSHp((char *)sip, sizeof(*sip));
-             }
+        if (sip && sigaction(sig, 0, &oact) == 0 && oact.sa_flags & SA_SIGINFO) {
+               HV *sih = newHV();
+               SV *rv  = newRV_noinc(MUTABLE_SV(sih));
+               /* The siginfo fields signo, code, errno, pid, uid,
+                * addr, status, and band are defined by POSIX/SUSv3. */
+               (void)hv_stores(sih, "signo", newSViv(sip->si_signo));
+               (void)hv_stores(sih, "code", newSViv(sip->si_code));
+#  ifdef HAS_SIGINFO_SI_ERRNO
+               (void)hv_stores(sih, "errno",      newSViv(sip->si_errno));
+#  endif
+#  ifdef HAS_SIGINFO_SI_STATUS
+               (void)hv_stores(sih, "status",     newSViv(sip->si_status));
+#  endif
+#  ifdef HAS_SIGINFO_SI_UID
+               {
+                    SV *uid = newSV(0);
+                    sv_setuid(uid, sip->si_uid);
+                    (void)hv_stores(sih, "uid", uid);
+               }
+#  endif
+#  ifdef HAS_SIGINFO_SI_PID
+               (void)hv_stores(sih, "pid",        newSViv(sip->si_pid));
+#  endif
+#  ifdef HAS_SIGINFO_SI_ADDR
+               (void)hv_stores(sih, "addr",       newSVuv(PTR2UV(sip->si_addr)));
+#  endif
+#  ifdef HAS_SIGINFO_SI_BAND
+               (void)hv_stores(sih, "band",       newSViv(sip->si_band));
+#  endif
+               EXTEND(SP, 2);
+               PUSHs(rv);
+               mPUSHp((char *)sip, sizeof(*sip));
 
         }
     }
 #endif
+
     PUTBACK;
 
     errsv_save = newSVsv(ERRSV);
@@ -3448,27 +3597,35 @@ Perl_sighandler(int sig)
        SV * const errsv = ERRSV;
        if (SvTRUE_NN(errsv)) {
            SvREFCNT_dec(errsv_save);
+
 #ifndef PERL_MICRO
-       /* Handler "died", for example to get out of a restart-able read().
-        * Before we re-do that on its behalf re-enable the signal which was
-        * blocked by the system when we entered.
-        */
-#ifdef HAS_SIGPROCMASK
-#if defined(HAS_SIGACTION) && defined(SA_SIGINFO)
-           if (sip || uap)
-#endif
-           {
+            /* Handler "died", for example to get out of a restart-able read().
+             * Before we re-do that on its behalf re-enable the signal which was
+             * blocked by the system when we entered.
+             */
+#  ifdef HAS_SIGPROCMASK
+           if (!safe) {
+                /* safe signals called via dispatch_signals() set up a
+                 * savestack destructor, unblock_sigmask(), to
+                 * automatically unblock the handler at the end. If
+                 * instead we get here directly, we have to do it
+                 * ourselves
+                 */
                sigset_t set;
                sigemptyset(&set);
                sigaddset(&set,sig);
                sigprocmask(SIG_UNBLOCK, &set, NULL);
            }
-#else
+#  else
            /* Not clear if this will work */
+            /* XXX not clear if this should be protected by 'if (safe)'
+             * too */
+
            (void)rsignal(sig, SIG_IGN);
            (void)rsignal(sig, PL_csighandlerp);
-#endif
+#  endif
 #endif /* !PERL_MICRO */
+
            die_sv(errsv);
        }
        else {
@@ -3556,6 +3713,7 @@ S_unwind_handler_stack(pTHX_ const void *p)
 }
 
 /*
+=for apidoc_section $magic
 =for apidoc magic_sethint
 
 Triggered by a store to C<%^H>, records the key/value pair to
@@ -3584,6 +3742,7 @@ Perl_magic_sethint(pTHX_ SV *sv, MAGIC *mg)
     PL_hints |= HINT_LOCALIZE_HH;
     CopHINTHASH_set(&PL_compiling,
        cophh_store_sv(CopHINTHASH_get(&PL_compiling), key, 0, sv, 0));
+    magic_sethint_feature(key, NULL, 0, sv, 0);
     return 0;
 }
 
@@ -3608,6 +3767,10 @@ Perl_magic_clearhint(pTHX_ SV *sv, MAGIC *mg)
                                 MUTABLE_SV(mg->mg_ptr), 0, 0)
         : cophh_delete_pvn(CopHINTHASH_get(&PL_compiling),
                                 mg->mg_ptr, mg->mg_len, 0, 0));
+    if (mg->mg_len == HEf_SVKEY)
+        magic_sethint_feature(MUTABLE_SV(mg->mg_ptr), NULL, 0, NULL, FALSE);
+    else
+        magic_sethint_feature(NULL, mg->mg_ptr, mg->mg_len, NULL, FALSE);
     return 0;
 }
 
@@ -3626,6 +3789,7 @@ Perl_magic_clearhints(pTHX_ SV *sv, MAGIC *mg)
     PERL_UNUSED_ARG(mg);
     cophh_free(CopHINTHASH_get(&PL_compiling));
     CopHINTHASH_set(&PL_compiling, cophh_new_empty());
+    CLEARFEATUREBITS();
     return 0;
 }