]> git.vpit.fr Git - perl/modules/Scope-Upper.git/blobdiff - Upper.xs
Harden t/54-unwind-threads.t against stray exits
[perl/modules/Scope-Upper.git] / Upper.xs
index d34c7ffd7bc220db87bc44fc90373f19c7f9630d..0e36df1e98a4cbc7f5b65be2d703442e3b61d2be 100644 (file)
--- a/Upper.xs
+++ b/Upper.xs
@@ -256,6 +256,11 @@ static U8 su_op_gimme_reverse(U8 gimme) {
 # define MY_CXT_CLONE NOOP
 #endif
 
+/* --- Error messages ------------------------------------------------------ */
+
+static const char su_stack_smash[]    = "Cannot target a scope outside of the current stack";
+static const char su_no_such_target[] = "No targetable %s scope in the current stack";
+
 /* --- Unique context ID global storage ------------------------------------ */
 
 /* ... Sequence ID counter ................................................. */
@@ -758,11 +763,12 @@ typedef struct {
 
 typedef struct {
  su_ud_common ci;
- SV *cb;
+ SV          *cb;
 } su_ud_reap;
 
-static void su_call(pTHX_ void *ud_) {
- su_ud_reap *ud = (su_ud_reap *) ud_;
+#define SU_UD_REAP_CB(U) (((su_ud_reap *) (U))->cb)
+
+static void su_call(pTHX_ SV *cb) {
 #if SU_SAVE_LAST_CX
  I32 cxix;
  PERL_CONTEXT saved_cx;
@@ -772,8 +778,8 @@ static void su_call(pTHX_ void *ud_) {
 
  SU_D({
   PerlIO_printf(Perl_debug_log,
-                "%p: @@@ call\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
-                 ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
+                "@@@ call scope_ix=%2d save_ix=%2d\n",
+                PL_scopestack_ix, PL_savestack_ix);
  });
 
  ENTER;
@@ -789,7 +795,7 @@ static void su_call(pTHX_ void *ud_) {
  saved_cx = cxstack[cxix];
 #endif /* SU_SAVE_LAST_CX */
 
- call_sv(ud->cb, G_VOID);
+ call_sv(cb, G_VOID);
 
 #if SU_SAVE_LAST_CX
  cxstack[cxix] = saved_cx;
@@ -800,35 +806,29 @@ static void su_call(pTHX_ void *ud_) {
  FREETMPS;
  LEAVE;
 
- SvREFCNT_dec(ud->cb);
- SU_UD_FREE(ud);
-}
+ SvREFCNT_dec(cb);
 
-static void su_reap(pTHX_ void *ud) {
-#define su_reap(U) su_reap(aTHX_ (U))
- SU_D({
-  PerlIO_printf(Perl_debug_log,
-                "%p: === reap\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
-                 ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
- });
-
- SAVEDESTRUCTOR_X(su_call, ud);
+ return;
 }
 
 /* ... Localize & localize array/hash element .............................. */
 
 typedef struct {
  su_ud_common ci;
- SV    *sv;
- SV    *val;
- SV    *elem;
+ SV          *sv;
+ SV          *val;
+ SV          *elem;
 } su_ud_localize;
 
+#define SU_UD_LOCALIZE_SV(U)   (((su_ud_localize *) (U))->sv)
+#define SU_UD_LOCALIZE_VAL(U)  (((su_ud_localize *) (U))->val)
+#define SU_UD_LOCALIZE_ELEM(U) (((su_ud_localize *) (U))->elem)
+
 #define SU_UD_LOCALIZE_FREE(U) STMT_START { \
- SvREFCNT_dec((U)->elem); \
- SvREFCNT_dec((U)->val);  \
- SvREFCNT_dec((U)->sv);   \
- SU_UD_FREE(U);           \
+ SvREFCNT_dec(SU_UD_LOCALIZE_ELEM(U)); \
+ SvREFCNT_dec(SU_UD_LOCALIZE_VAL(U)); \
+ SvREFCNT_dec(SU_UD_LOCALIZE_SV(U)); \
+ SU_UD_FREE(U); \
 } STMT_END
 
 static I32 su_ud_localize_init(pTHX_ su_ud_localize *ud, SV *sv, SV *val, SV *elem) {
@@ -949,14 +949,14 @@ static void su_localize(pTHX_ void *ud_) {
   case SVt_PVAV:
    if (elem) {
     su_save_aelem(GvAV(gv), elem, val);
-    goto done;
+    return;
    } else
     save_ary(gv);
    break;
   case SVt_PVHV:
    if (elem) {
     su_save_helem(GvHV(gv), elem, val);
-    goto done;
+    return;
    } else
     save_hash(gv);
    break;
@@ -974,8 +974,24 @@ static void su_localize(pTHX_ void *ud_) {
  if (val)
   SvSetMagicSV((SV *) gv, val);
 
-done:
- SU_UD_LOCALIZE_FREE(ud);
+ return;
+}
+
+/* ... Unique context ID ................................................... */
+
+typedef struct {
+ su_ud_common ci;
+ su_uid      *uid;
+} su_ud_uid;
+
+#define SU_UD_UID_UID(U) (((su_ud_uid *) (U))->uid)
+
+static void su_uid_drop(pTHX_ void *ud_) {
+ su_uid *uid = ud_;
+
+ uid->flags &= ~SU_UID_ACTIVE;
+
+ return;
 }
 
 /* --- Pop a context back -------------------------------------------------- */
@@ -1026,14 +1042,6 @@ static const char *su_block_type[] = {
 # define SU_CXNAME(C) su_block_type[CxTYPE(C)]
 #endif
 
-static void su_uid_bump(pTHX_ void *);
-
-static void (*su_handler[])(pTHX_ void *) = {
- su_reap,
- su_localize,
- su_uid_bump
-};
-
 static void su_pop(pTHX_ void *ud) {
 #define su_pop(U) su_pop(aTHX_ (U))
  I32 depth, base, mark, *origin;
@@ -1099,7 +1107,26 @@ static void su_pop(pTHX_ void *ud) {
            ud,                       depth, PL_scopestack_ix, PL_savestack_ix));
   SAVEDESTRUCTOR_X(su_pop, ud);
  } else {
-  su_handler[SU_UD_TYPE(ud)](aTHX_ ud);
+  switch (SU_UD_TYPE(ud)) {
+   case SU_UD_TYPE_REAP: {
+    SU_D({
+     PerlIO_printf(Perl_debug_log,
+                "%p: === reap\n%p: depth=%2d scope_ix=%2d save_ix=%2d\n",
+                 ud, ud, SU_UD_DEPTH(ud), PL_scopestack_ix, PL_savestack_ix);
+    });
+    SAVEDESTRUCTOR_X(su_call, SU_UD_REAP_CB(ud));
+    SU_UD_FREE(ud);
+    break;
+   }
+   case SU_UD_TYPE_LOCALIZE:
+    su_localize(ud);
+    SU_UD_LOCALIZE_FREE(ud);
+    break;
+   case SU_UD_TYPE_UID:
+    SAVEDESTRUCTOR_X(su_uid_drop, SU_UD_UID_UID(ud));
+    SU_UD_FREE(ud);
+    break;
+  }
  }
 
  SU_D(PerlIO_printf(Perl_debug_log,
@@ -2004,20 +2031,6 @@ static int su_uid_storage_check(pTHX_ UV depth, UV seq) {
  return uid && (uid->seq == seq) && (uid->flags & SU_UID_ACTIVE);
 }
 
-static void su_uid_drop(pTHX_ void *ud_) {
- su_uid *uid = ud_;
-
- uid->flags &= ~SU_UID_ACTIVE;
-}
-
-static void su_uid_bump(pTHX_ void *ud_) {
- su_ud_reap *ud  = ud_;
-
- SAVEDESTRUCTOR_X(su_uid_drop, ud->cb);
-
- SU_UD_FREE(ud);
-}
-
 static SV *su_uid_get(pTHX_ I32 cxix) {
 #define su_uid_get(I) su_uid_get(aTHX_ (I))
  su_uid *uid;
@@ -2028,15 +2041,14 @@ static SV *su_uid_get(pTHX_ I32 cxix) {
  uid   = su_uid_storage_fetch(depth);
 
  if (!(uid->flags & SU_UID_ACTIVE)) {
-  su_ud_reap *ud;
+  su_ud_uid *ud;
 
-  uid->seq = su_uid_seq_next(depth);
+  uid->seq    = su_uid_seq_next(depth);
   uid->flags |= SU_UID_ACTIVE;
 
-  Newx(ud, 1, su_ud_reap);
-  SU_UD_ORIGIN(ud)  = NULL;
-  SU_UD_TYPE(ud)    = SU_UD_TYPE_UID;
-  ud->cb = (SV *) uid;
+  Newx(ud, 1, su_ud_uid);
+  SU_UD_TYPE(ud) = SU_UD_TYPE_UID;
+  ud->uid        = uid;
   su_init(ud, cxix, SU_SAVE_DESTRUCTOR_SIZE);
  }
 
@@ -2579,6 +2591,8 @@ PPCODE:
   --cxix;
   cxix = su_context_skip_db(cxix);
   cxix = su_context_normalize_up(cxix);
+ } else {
+  warn(su_stack_smash);
  }
  EXTEND(SP, 1);
  mPUSHi(cxix);
@@ -2604,6 +2618,7 @@ PPCODE:
     XSRETURN(1);
   }
  }
+ warn(su_no_such_target, "subroutine");
  XSRETURN_UNDEF;
 
 void
@@ -2624,6 +2639,7 @@ PPCODE:
     XSRETURN(1);
   }
  }
+ warn(su_no_such_target, "eval");
  XSRETURN_UNDEF;
 
 void
@@ -2635,8 +2651,10 @@ PPCODE:
  SU_GET_LEVEL(0, 0);
  cxix = su_context_here();
  while (--level >= 0) {
-  if (cxix <= 0)
+  if (cxix <= 0) {
+   warn(su_stack_smash);
    break;
+  }
   --cxix;
   cxix = su_context_skip_db(cxix);
   cxix = su_context_normalize_up(cxix);
@@ -2666,6 +2684,8 @@ PPCODE:
   }
  }
 done:
+ if (level >= 0)
+  warn(su_stack_smash);
  EXTEND(SP, 1);
  mPUSHi(cxix);
  XSRETURN(1);
@@ -2864,9 +2884,10 @@ CODE:
  SU_GET_CONTEXT(1, 1, su_context_skip_db(cxstack_ix));
  cxix = su_context_normalize_down(cxix);
  Newx(ud, 1, su_ud_reap);
- SU_UD_ORIGIN(ud) = NULL;
- SU_UD_TYPE(ud)   = SU_UD_TYPE_REAP;
- ud->cb = newSVsv(hook);
+ SU_UD_TYPE(ud) = SU_UD_TYPE_REAP;
+ ud->cb         = (SvROK(hook) && SvTYPE(SvRV(hook)) >= SVt_PVCV)
+                  ? SvRV(hook) : hook;
+ SvREFCNT_inc_simple_void(ud->cb);
  su_init(ud, cxix, SU_SAVE_DESTRUCTOR_SIZE);
 
 void
@@ -2880,8 +2901,7 @@ CODE:
  SU_GET_CONTEXT(2, 2, su_context_skip_db(cxstack_ix));
  cxix = su_context_normalize_down(cxix);
  Newx(ud, 1, su_ud_localize);
- SU_UD_ORIGIN(ud) = NULL;
- SU_UD_TYPE(ud)   = SU_UD_TYPE_LOCALIZE;
+ SU_UD_TYPE(ud) = SU_UD_TYPE_LOCALIZE;
  size = su_ud_localize_init(ud, sv, val, NULL);
  su_init(ud, cxix, size);
 
@@ -2898,6 +2918,7 @@ CODE:
  SU_GET_CONTEXT(3, 3, su_context_skip_db(cxstack_ix));
  cxix = su_context_normalize_down(cxix);
  Newx(ud, 1, su_ud_localize);
+ /* Initialize SU_UD_ORIGIN(ud) in case SU_UD_LOCALIZE_FREE(ud) needs it */
  SU_UD_ORIGIN(ud) = NULL;
  SU_UD_TYPE(ud)   = SU_UD_TYPE_LOCALIZE;
  size = su_ud_localize_init(ud, sv, val, elem);
@@ -2918,8 +2939,7 @@ CODE:
  SU_GET_CONTEXT(2, 2, su_context_skip_db(cxstack_ix));
  cxix = su_context_normalize_down(cxix);
  Newx(ud, 1, su_ud_localize);
- SU_UD_ORIGIN(ud) = NULL;
- SU_UD_TYPE(ud)   = SU_UD_TYPE_LOCALIZE;
+ SU_UD_TYPE(ud) = SU_UD_TYPE_LOCALIZE;
  size = su_ud_localize_init(ud, sv, NULL, elem);
  su_init(ud, cxix, size);