#define gp_dup Perl_gp_dup
#define mg_dup Perl_mg_dup
#define sv_dup Perl_sv_dup
+#define gv_share S_gv_share
#if defined(HAVE_INTERP_INTERN)
#define sys_intern_dup Perl_sys_intern_dup
#endif
#define gp_dup(a) Perl_gp_dup(aTHX_ a)
#define mg_dup(a) Perl_mg_dup(aTHX_ a)
#define sv_dup(a) Perl_sv_dup(aTHX_ a)
+#define gv_share(a) S_gv_share(aTHX_ a)
#if defined(HAVE_INTERP_INTERN)
#define sys_intern_dup(a,b) Perl_sys_intern_dup(aTHX_ a,b)
#endif
#define mg_dup Perl_mg_dup
#define Perl_sv_dup CPerlObj::Perl_sv_dup
#define sv_dup Perl_sv_dup
+#define S_gv_share CPerlObj::S_gv_share
+#define gv_share S_gv_share
#if defined(HAVE_INTERP_INTERN)
#define Perl_sys_intern_dup CPerlObj::Perl_sys_intern_dup
#define sys_intern_dup Perl_sys_intern_dup
Ap |GP* |gp_dup |GP* gp
Ap |MAGIC* |mg_dup |MAGIC* mg
Ap |SV* |sv_dup |SV* sstr
+s |SV* |gv_share |SV *sv
#if defined(HAVE_INTERP_INTERN)
Ap |void |sys_intern_dup |struct interp_intern* src \
|struct interp_intern* dst
{
if (!gv || SvTYPE((SV*)gv) != SVt_PVGV)
Perl_croak(aTHX_ "Bad symbol for filehandle");
- if (!GvIOp(gv))
+ if (!GvIOp(gv)) {
+#ifdef GV_SHARED_CHECK
+ if (GvSHARED(gv)) {
+ Perl_croak(aTHX_ "Bad symbol for filehandle (GV is shared)");
+ }
+#endif
GvIOp(gv) = newIO();
+ }
return gv;
}
#define GvIN_PAD_on(gv) (GvFLAGS(gv) |= GVf_IN_PAD)
#define GvIN_PAD_off(gv) (GvFLAGS(gv) &= ~GVf_IN_PAD)
+/* XXX: all GvFLAGS options are used, borrowing GvGPFLAGS for the moment */
+
+#define GVf_SHARED 0x0001
+#define GvSHARED(gv) (GvGP(gv) && (GvGPFLAGS(gv) & GVf_SHARED))
+#define GvSHARED_on(gv) (GvGPFLAGS(gv) |= GVf_SHARED)
+#define GvSHARED_off(gv) (GvGPFLAGS(gv) &= ~GVf_SHARED)
+
+#ifdef USE_ITHREADS
+#define GV_SHARED_CHECK
+#else
+#undef GV_SHARED_CHECK
+#endif
+
#define Nullgv Null(GV*)
#define DM_UID 0x003
cv = (!name || GvCVGEN(gv)) ? Nullcv : GvCV(gv);
+#ifdef GV_SHARED_CHECK
+ if (cv && GvSHARED(gv) && SvREADONLY(cv)) {
+ Perl_croak(aTHX_ "Can't define subroutine %s (GV is shared)", name);
+ }
+#endif
+
if (!block || !ps || *ps || attrs)
const_sv = Nullsv;
else
if (cv) {
bool exists = CvROOT(cv) || CvXSUB(cv);
+
+#ifdef GV_SHARED_CHECK
+ if (exists && GvSHARED(gv)) {
+ Perl_croak(aTHX_ "Can't redefine shared subroutine %s", name);
+ }
+#endif
+
/* if the subroutine doesn't exist and wasn't pre-declared
* with a prototype, assume it will be AUTOLOADed,
* skipping the prototype check
else
name = "STDOUT";
gv = gv_fetchpv(name,TRUE, SVt_PVFM);
+#ifdef GV_SHARED_CHECK
+ if (GvSHARED(gv)) {
+ Perl_croak(aTHX_ "Bad symbol for form (GV is shared)");
+ }
+#endif
GvMULTI_on(gv);
if ((cv = GvFORM(gv))) {
if (ckWARN(WARN_REDEFINE)) {
methname = "TIEARRAY";
break;
case SVt_PVGV:
+#ifdef GV_SHARED_CHECK
+ if (GvSHARED((GV*)varsv)) {
+ Perl_croak(aTHX_ "Attempt to tie shared GV");
+ }
+#endif
methname = "TIEHANDLE";
how = 'q';
break;
PERL_CALLCONV GP* Perl_gp_dup(pTHX_ GP* gp);
PERL_CALLCONV MAGIC* Perl_mg_dup(pTHX_ MAGIC* mg);
PERL_CALLCONV SV* Perl_sv_dup(pTHX_ SV* sstr);
+STATIC SV* S_gv_share(pTHX_ SV *sv);
#if defined(HAVE_INTERP_INTERN)
PERL_CALLCONV void Perl_sys_intern_dup(pTHX_ struct interp_intern* src, struct interp_intern* dst);
#endif
&& GvCV(dstr) && PL_sortcop == CvSTART(GvCV(dstr)))
Perl_croak(aTHX_ "Can't redefine active sort subroutine %s",
GvNAME(dstr));
+
+#ifdef GV_SHARED_CHECK
+ if (GvSHARED((GV*)dstr)) {
+ Perl_croak(aTHX_ PL_no_modify);
+ }
+#endif
+
(void)SvOK_off(dstr);
GvINTRO_off(dstr); /* one-shot flag */
gp_free((GV*)dstr);
SV *dref = 0;
int intro = GvINTRO(dstr);
+#ifdef GV_SHARED_CHECK
+ if (GvSHARED((GV*)dstr)) {
+ Perl_croak(aTHX_ PL_no_modify);
+ }
+#endif
+
if (intro) {
GP *gp;
gp_free((GV*)dstr);
char *PL_watch_pvx;
#endif
+STATIC SV *
+S_gv_share(pTHX_ SV *sstr)
+{
+ GV *gv = (GV*)sstr;
+ SV *sv = &PL_sv_no; /* just need SvREADONLY-ness */
+
+ if (GvIO(gv) || GvFORM(gv)) {
+ GvSHARED_off(gv); /* GvIOs cannot be shared. nor can GvFORMs */
+ }
+ else if (!GvCV(gv)) {
+ GvCV(gv) = (CV*)sv;
+ }
+ else {
+ /* CvPADLISTs cannot be shared */
+ if (!CvXSUB(GvCV(gv))) {
+ GvSHARED_off(gv);
+ }
+ }
+
+ if (!GvSHARED(gv)) {
+#if 0
+ PerlIO_printf(Perl_debug_log, "gv_share: unable to share %s::%s\n",
+ HvNAME(GvSTASH(gv)), GvNAME(gv));
+#endif
+ return Nullsv;
+ }
+
+ /*
+ * write attempts will die with
+ * "Modification of a read-only value attempted"
+ */
+ if (!GvSV(gv)) {
+ GvSV(gv) = sv;
+ }
+ else {
+ SvREADONLY_on(GvSV(gv));
+ }
+
+ if (!GvAV(gv)) {
+ GvAV(gv) = (AV*)sv;
+ }
+ else {
+ SvREADONLY_on(GvAV(gv));
+ }
+
+ if (!GvHV(gv)) {
+ GvHV(gv) = (HV*)sv;
+ }
+ else {
+ SvREADONLY_on(GvAV(gv));
+ }
+
+ return sstr; /* he_dup() will SvREFCNT_inc() */
+}
+
SV *
Perl_sv_dup(pTHX_ SV *sstr)
{
LvTYPE(dstr) = LvTYPE(sstr);
break;
case SVt_PVGV:
+ if (GvSHARED((GV*)sstr)) {
+ SV *share;
+ if ((share = gv_share(sstr))) {
+ del_SV(dstr);
+ dstr = share;
+#if 0
+ PerlIO_printf(Perl_debug_log, "sv_dup: sharing %s::%s\n",
+ HvNAME(GvSTASH(share)), GvNAME(share));
+#endif
+ break;
+ }
+ }
SvANY(dstr) = new_XPVGV();
SvCUR(dstr) = SvCUR(sstr);
SvLEN(dstr) = SvLEN(sstr);