X-Git-Url: http://git.vpit.fr/?a=blobdiff_plain;f=Magic.xs;h=c19b2f3cc04fe549a207266dbd417d506355c9b9;hb=9dce2bfe18bcd7d9914310c81b8832d40fb04fbb;hp=183bfbd7521bfe193b2085d9b299315df5db4ef8;hpb=990ac0f214d44bda5d26733979f647b855cb5702;p=perl%2Fmodules%2FVariable-Magic.git diff --git a/Magic.xs b/Magic.xs index 183bfbd..c19b2f3 100644 --- a/Magic.xs +++ b/Magic.xs @@ -100,12 +100,16 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { # define SvMAGIC_set(sv, val) (SvMAGIC(sv) = (val)) #endif -#ifndef mPUSHu -# define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U))) +#ifndef SvRV_const +# define SvRV_const(sv) SvRV((SV *) sv) #endif -#ifndef SvPV_const -# define SvPV_const SvPV +#ifndef SvREFCNT_inc_simple_void +# define SvREFCNT_inc_simple_void(sv) SvREFCNT_inc(sv) +#endif + +#ifndef mPUSHu +# define mPUSHu(U) PUSHs(sv_2mortal(newSVuv(U))) #endif #ifndef PERL_MAGIC_ext @@ -132,18 +136,8 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { # define IN_PERL_COMPILETIME (PL_curcop == &PL_compiling) #endif -#if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser) -# ifndef PL_error_count -# define PL_error_count PL_parser->error_count -# endif -#else -# ifndef PL_error_count -# define PL_error_count PL_Ierror_count -# endif -#endif - -/* uvar magic and Hash::Util::FieldHash were commited with 28419, but only - * enable it on 5.10 */ +/* uvar magic and Hash::Util::FieldHash were commited with 28419, but we only + * enable them on 5.10 */ #if VMG_HAS_PERL(5, 10, 0) # define VMG_UVAR 1 #else @@ -171,7 +165,7 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { #endif /* Applied to dev-5.11 as 34908 */ -#if VMG_HAS_PERL_MAINT(5, 11, 0, 34908) +#if VMG_HAS_PERL_MAINT(5, 11, 0, 34908) || VMG_HAS_PERL(5, 12, 0) # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 1 #else # define VMG_COMPAT_ARRAY_UNSHIFT_NOLEN_VOID 0 @@ -184,15 +178,18 @@ STATIC SV *vmg_clone(pTHX_ SV *sv, tTHX owner) { # define VMG_COMPAT_ARRAY_UNDEF_CLEAR 0 #endif -#if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) +#if VMG_HAS_PERL_MAINT(5, 11, 0, 32969) || VMG_HAS_PERL(5, 12, 0) # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 1 #else # define VMG_COMPAT_SCALAR_LENGTH_NOLEN 0 #endif +/* ... Bug-free mg_magical ................................................. */ + +/* See the discussion at http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html. This version is specialized to our needs. */ + #if VMG_UVAR -/* Bug-free mg_magical - see http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2008-01/msg00036.html - but specialized to our needs. */ STATIC void vmg_sv_magicuvar(pTHX_ SV *sv, const char *uf, I32 len) { #define vmg_sv_magicuvar(S, U, L) vmg_sv_magicuvar(aTHX_ (S), (U), (L)) const MAGIC* mg; @@ -214,6 +211,75 @@ STATIC void vmg_sv_magicuvar(pTHX_ SV *sv, const char *uf, I32 len) { #endif /* VMG_UVAR */ +/* ... Safe version of call_sv() ........................................... */ + +#define VMG_SAVE_LAST_CX (!VMG_HAS_PERL(5, 8, 4) || VMG_HAS_PERL(5, 9, 5)) + +STATIC I32 vmg_call_sv(pTHX_ SV *sv, I32 flags, I32 destructor) { +#define vmg_call_sv(S, F, D) vmg_call_sv(aTHX_ (S), (F), (D)) + I32 ret, cxix = 0, in_eval = 0; +#if VMG_SAVE_LAST_CX + PERL_CONTEXT saved_cx; +#endif + SV *old_err = NULL; + + if (SvTRUE(ERRSV)) { + old_err = ERRSV; + ERRSV = newSV(0); + } + + if (cxstack_ix < cxstack_max) { + cxix = cxstack_ix + 1; + if (destructor && CxTYPE(cxstack + cxix) == CXt_EVAL) + in_eval = 1; + } + +#if VMG_SAVE_LAST_CX + /* The last popped context will be reused by call_sv(), but our callers may + * still need its previous value. Back it up so that it isn't clobbered. */ + saved_cx = cxstack[cxix]; +#endif + + ret = call_sv(sv, flags | G_EVAL); + +#if VMG_SAVE_LAST_CX + cxstack[cxix] = saved_cx; +#endif + + if (SvTRUE(ERRSV)) { + if (old_err) { + sv_setsv(old_err, ERRSV); + SvREFCNT_dec(ERRSV); + ERRSV = old_err; + } + if (IN_PERL_COMPILETIME) { + if (!PL_in_eval) { + if (PL_errors) + sv_catsv(PL_errors, ERRSV); + else + Perl_warn(aTHX_ "%s", SvPV_nolen(ERRSV)); + SvCUR_set(ERRSV, 0); + } +#if VMG_HAS_PERL(5, 10, 0) || defined(PL_parser) + if (PL_parser) + ++PL_parser->error_count; +#elif defined(PL_error_count) + ++PL_error_count; +#else + ++PL_Ierror_count; +#endif + } else if (!in_eval) + croak(NULL); + } else { + if (old_err) { + SvREFCNT_dec(ERRSV); + ERRSV = old_err; + } + } + + return ret; +} + /* --- Stolen chunk of B --------------------------------------------------- */ typedef enum { @@ -335,8 +401,8 @@ STATIC const char vmg_argstorefailed[] = "Error while storing arguments"; typedef struct { MGVTBL *vtbl; - U8 uvar; U8 opinfo; + U8 uvar; SV *cb_data; SV *cb_get, *cb_set, *cb_len, *cb_clear, *cb_free; @@ -530,7 +596,7 @@ STATIC SV *vmg_wizard_new(pTHX_ const MGWIZ *w) { STATIC const SV *vmg_wizard_validate(pTHX_ const SV *wiz) { #define vmg_wizard_validate(W) vmg_wizard_validate(aTHX_ (W)) if (SvROK(wiz)) { - wiz = SvRV(wiz); + wiz = SvRV_const(wiz); if (SvIOK(wiz)) return wiz; } @@ -591,7 +657,7 @@ STATIC const MGWIZ *vmg_wizard_mgwiz(pTHX_ const SV *wiz) { STATIC const MAGIC *vmg_find(const SV *sv, const SV *wiz) { const MAGIC *mg, *moremagic; - UV wid; + IV wid; if (SvTYPE(sv) < SVt_PVMG) return NULL; @@ -600,7 +666,7 @@ STATIC const MAGIC *vmg_find(const SV *sv, const SV *wiz) { for (mg = SvMAGIC(sv); mg; mg = moremagic) { moremagic = mg->mg_moremagic; if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) { - UV zid = vmg_wizard_id(mg->mg_ptr); + IV zid = vmg_wizard_id(mg->mg_ptr); if (zid == wid) return mg; } @@ -628,14 +694,14 @@ STATIC SV *vmg_data_new(pTHX_ SV *ctor, SV *sv, SV **args, I32 items) { PUSHs(args[i]); PUTBACK; - call_sv(ctor, G_SCALAR); + vmg_call_sv(ctor, G_SCALAR, 0); SPAGAIN; nsv = POPs; #if VMG_HAS_PERL(5, 8, 3) - SvREFCNT_inc(nsv); /* Or it will be destroyed in FREETMPS */ + SvREFCNT_inc_simple_void(nsv); /* Or it will be destroyed in FREETMPS */ #else - nsv = sv_newref(nsv); /* Workaround some bug in SvREFCNT_inc() */ + nsv = sv_newref(nsv); /* Workaround some bug in SvREFCNT_inc() */ #endif PUTBACK; @@ -757,7 +823,7 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, const SV *wiz) { U32 uvars = 0; #endif /* VMG_UVAR */ MAGIC *mg, *prevmagic, *moremagic = NULL; - UV wid = vmg_wizard_id(wiz); + IV wid = vmg_wizard_id(wiz); if (SvTYPE(sv) < SVt_PVMG) return 0; @@ -766,7 +832,7 @@ STATIC UV vmg_dispell(pTHX_ SV *sv, const SV *wiz) { moremagic = mg->mg_moremagic; if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) { const MGWIZ *z = vmg_wizard_mgwiz(mg->mg_ptr); - UV zid = vmg_wizard_id(mg->mg_ptr); + IV zid = vmg_wizard_id(mg->mg_ptr); if (zid == wid) { #if VMG_UVAR /* If the current has no uvar, short-circuit uvar deletion. */ @@ -907,23 +973,15 @@ STATIC SV *vmg_op_info(pTHX_ unsigned int opinfo) { /* ... svt callbacks ....................................................... */ -#define VMG_CB_CALL_SET_RET(D) \ - { \ - SV *svr; \ - SPAGAIN; \ - svr = POPs; \ - ret = SvOK(svr) ? SvIV(svr) : (D); \ - PUTBACK; \ - } - #define VMG_CB_CALL_ARGS_MASK 15 #define VMG_CB_CALL_ARGS_SHIFT 4 #define VMG_CB_CALL_OPINFO (VMG_OP_INFO_NAME|VMG_OP_INFO_OBJECT) STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) { va_list ap; - int ret; + int ret = 0; unsigned int i, args, opinfo; + SV *svr; dSP; @@ -947,9 +1005,13 @@ STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) { XPUSHs(vmg_op_info(opinfo)); PUTBACK; - call_sv(cb, G_SCALAR); + vmg_call_sv(cb, G_SCALAR, 0); - VMG_CB_CALL_SET_RET(0); + SPAGAIN; + svr = POPs; + if (SvOK(svr)) + ret = (int) SvIV(svr); + PUTBACK; FREETMPS; LEAVE; @@ -957,12 +1019,15 @@ STATIC int vmg_cb_call(pTHX_ SV *cb, unsigned int flags, SV *sv, ...) { return ret; } -#define vmg_cb_call1(I, F, S, A1) \ - vmg_cb_call(aTHX_ (I), (((F) << VMG_CB_CALL_ARGS_SHIFT) | 1), (S), (A1)) -#define vmg_cb_call2(I, F, S, A1, A2) \ - vmg_cb_call(aTHX_ (I), (((F) << VMG_CB_CALL_ARGS_SHIFT) | 2), (S), (A1), (A2)) -#define vmg_cb_call3(I, F, S, A1, A2, A3) \ - vmg_cb_call(aTHX_ (I), (((F) << VMG_CB_CALL_ARGS_SHIFT) | 3), (S), (A1), (A2), (A3)) +#define VMG_CB_FLAGS(OI, A) \ + ((((unsigned int) (OI)) << VMG_CB_CALL_ARGS_SHIFT) | (A)) + +#define vmg_cb_call1(I, OI, S, A1) \ + vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 1), (S), (A1)) +#define vmg_cb_call2(I, OI, S, A1, A2) \ + vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 2), (S), (A1), (A2)) +#define vmg_cb_call3(I, OI, S, A1, A2, A3) \ + vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 3), (S), (A1), (A2), (A3)) STATIC int vmg_svt_get(pTHX_ SV *sv, MAGIC *mg) { const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr); @@ -978,6 +1043,7 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) { const MGWIZ *w = vmg_wizard_mgwiz(mg->mg_ptr); unsigned int opinfo = w->opinfo; U32 len, ret; + SV *svr; svtype t = SvTYPE(sv); dSP; @@ -991,7 +1057,11 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) { PUSHs(mg->mg_obj ? mg->mg_obj : &PL_sv_undef); if (t < SVt_PVAV) { STRLEN l; - const U8 *s = (const U8 *) SvPV_const(sv, l); +#if VMG_HAS_PERL(5, 9, 3) + const U8 *s = SvPV_const(sv, l); +#else + U8 *s = SvPV(sv, l); +#endif if (DO_UTF8(sv)) len = utf8_length(s, s + l); else @@ -1008,14 +1078,19 @@ STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) { XPUSHs(vmg_op_info(opinfo)); PUTBACK; - call_sv(w->cb_len, G_SCALAR); + vmg_call_sv(w->cb_len, G_SCALAR, 0); - VMG_CB_CALL_SET_RET(len); + SPAGAIN; + svr = POPs; + ret = SvOK(svr) ? (U32) SvUV(svr) : len; + if (t == SVt_PVAV) + --ret; + PUTBACK; FREETMPS; LEAVE; - return t == SVt_PVAV ? ret - 1 : ret; + return ret; } STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) { @@ -1025,12 +1100,8 @@ STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) { STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { const MGWIZ *w; -#if VMG_HAS_PERL(5, 9, 5) - PERL_CONTEXT saved_cx; - I32 cxix; -#endif - unsigned int had_err, has_err, flags = G_SCALAR | G_EVAL; int ret = 0; + SV *svr; dSP; @@ -1042,9 +1113,9 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { w = vmg_wizard_mgwiz(mg->mg_ptr); /* So that it survives the temp cleanup below */ - SvREFCNT_inc(sv); + SvREFCNT_inc_simple_void(sv); -#if !VMG_HAS_PERL_MAINT(5, 11, 0, 32686) +#if !(VMG_HAS_PERL_MAINT(5, 11, 0, 32686) || VMG_HAS_PERL(5, 12, 0)) /* The previous magic tokens were freed but the magic chain wasn't updated, so * if you access the sv from the callback the old deleted magics will trigger * and cause memory misreads. Change 32686 solved it that way : */ @@ -1062,32 +1133,13 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { XPUSHs(vmg_op_info(w->opinfo)); PUTBACK; - had_err = SvTRUE(ERRSV); - if (had_err) - flags |= G_KEEPERR; - -#if VMG_HAS_PERL(5, 9, 5) - /* This context should not be used anymore, but since we croak in places the - * core doesn't even dare to, some pointers to it may remain in the upper call - * stack. Make sure call_sv() doesn't clobber it. */ - if (cxstack_ix < cxstack_max) - cxix = cxstack_ix + 1; - else - cxix = Perl_cxinc(aTHX); - saved_cx = cxstack[cxix]; -#endif - - call_sv(w->cb_free, flags); - -#if VMG_HAS_PERL(5, 9, 5) - cxstack[cxix] = saved_cx; -#endif - - has_err = SvTRUE(ERRSV); - if (IN_PERL_COMPILETIME && !had_err && has_err) - ++PL_error_count; + vmg_call_sv(w->cb_free, G_SCALAR, 1); - VMG_CB_CALL_SET_RET(0); + SPAGAIN; + svr = POPs; + if (SvOK(svr)) + ret = (int) SvIV(svr); + PUTBACK; FREETMPS; LEAVE; @@ -1103,7 +1155,7 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { #if MGf_COPY STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *key, -# if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) +# if VMG_HAS_PERL_MAINT(5, 11, 0, 33256) || VMG_HAS_PERL(5, 12, 0) I32 keylen # else int keylen @@ -1340,6 +1392,7 @@ SV *_wizard(...) PROTOTYPE: DISABLE PREINIT: I32 i = 0; + UV opinfo; MGWIZ *w; MGVTBL *t; SV *cb; @@ -1365,10 +1418,13 @@ CODE: Newx(w, 1, MGWIZ); VMG_SET_CB(ST(i++), data); + cb = ST(i++); - w->opinfo = SvOK(cb) ? SvUV(cb) : 0; + opinfo = SvOK(cb) ? SvUV(cb) : 0; + w->opinfo = (U8) ((opinfo < 255) ? opinfo : 255); if (w->opinfo) vmg_op_info_init(w->opinfo); + VMG_SET_SVT_CB(ST(i++), get); VMG_SET_SVT_CB(ST(i++), set); VMG_SET_SVT_CB(ST(i++), len); @@ -1414,15 +1470,12 @@ PROTOTYPE: \[$@%&*]$@ PREINIT: SV **args = NULL; I32 i = 0; - SV *ret; CODE: if (items > 2) { i = items - 2; args = &ST(2); } - ret = newSVuv(vmg_cast(SvRV(sv), vmg_wizard_validate(wiz), args, i)); - SvREFCNT_dec(args); - RETVAL = ret; + RETVAL = newSVuv(vmg_cast(SvRV(sv), vmg_wizard_validate(wiz), args, i)); OUTPUT: RETVAL