From ce0d59fdd1c7d145efdf6bf8da56a259fed483e4 Mon Sep 17 00:00:00 2001 From: Father Chrysostomos Date: Tue, 2 Jul 2013 13:07:45 -0700 Subject: [PATCH] [perl #7508] Use NULL for nonexistent array elems MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This commit fixes bug #7508 and provides the groundwork for fixing several other bugs. Elements of @_ are aliased to the arguments, so that \$_[0] within sub foo will reference the same scalar as \$x if the sub is called as foo($x). &PL_sv_undef (the global read-only undef scalar returned by the ‘undef’ operator itself) was being used to represent nonexistent array elements. So the pattern would be broken for foo(undef), where \$_[0] would vivify a new $_[0] element, treating it as having been nonexistent. This also causes other problems with constants under ithreads (#105906) and causes a pending fix for another bug (#118691) to trig- ger this bug. This commit changes the internals to use a null pointer to represent a nonexistent element. This requires that Storable be changed to account for it. Also, IPC::Open3 was relying on the bug. So this commit patches both modules. --- av.c | 59 +++++++++++++++++++----------------------- dist/Storable/Storable.xs | 56 ++++++++++++++++++++++++++++++++++++--- dist/Storable/t/malice.t | 8 +++--- ext/B/t/showlex.t | 2 +- ext/Devel-Peek/Peek.xs | 1 + ext/IPC-Open3/lib/IPC/Open3.pm | 4 +++ pad.c | 30 ++++++++++++++------- pp.c | 4 +-- pp_hot.c | 12 ++++++--- regexec.c | 2 +- 10 files changed, 120 insertions(+), 58 deletions(-) diff --git a/av.c b/av.c index b15f6ff..aae70bf 100644 --- a/av.c +++ b/av.c @@ -40,16 +40,15 @@ Perl_av_reify(pTHX_ AV *av) #endif key = AvMAX(av) + 1; while (key > AvFILLp(av) + 1) - AvARRAY(av)[--key] = &PL_sv_undef; + AvARRAY(av)[--key] = NULL; while (key) { SV * const sv = AvARRAY(av)[--key]; - assert(sv); if (sv != &PL_sv_undef) - SvREFCNT_inc_simple_void_NN(sv); + SvREFCNT_inc_simple_void(sv); } key = AvARRAY(av) - AvALLOC(av); while (key) - AvALLOC(av)[--key] = &PL_sv_undef; + AvALLOC(av)[--key] = NULL; AvREIFY_off(av); AvREAL_on(av); } @@ -105,7 +104,7 @@ Perl_av_extend_guts(pTHX_ AV *av, I32 key, SSize_t *maxp, SV ***allocp, *arrayp = *allocp; if (AvREAL(av)) { while (tmp) - ary[--tmp] = &PL_sv_undef; + ary[--tmp] = NULL; } if (key > *maxp - 10) { newmax = key + *maxp; @@ -126,7 +125,7 @@ Perl_av_extend_guts(pTHX_ AV *av, I32 key, SSize_t *maxp, SV ***allocp, based on calling Perl_safesysmalloc_size() immediately after allocation, I'm not convinced that it is a great idea here. In an array we have to loop round setting everything to - &PL_sv_undef, which means writing to memory, potentially lots + NULL, which means writing to memory, potentially lots of it, whereas for the SV buffer case we don't touch the "bonus" memory. So there there is no cost in telling the world about it, whereas here we have to do work before we can @@ -161,11 +160,11 @@ Perl_av_extend_guts(pTHX_ AV *av, I32 key, SSize_t *maxp, SV ***allocp, Newx(*allocp, newmax+1, SV*); ary = *allocp + 1; tmp = newmax; - *allocp[0] = &PL_sv_undef; /* For the stacks */ + *allocp[0] = NULL; /* For the stacks */ } if (av && AvREAL(av)) { while (tmp) - ary[--tmp] = &PL_sv_undef; + ary[--tmp] = NULL; } *arrayp = *allocp; @@ -250,7 +249,7 @@ Perl_av_fetch(pTHX_ AV *av, I32 key, I32 lval) return NULL; } - if (key > AvFILLp(av) || AvARRAY(av)[key] == &PL_sv_undef) { + if (key > AvFILLp(av) || !AvARRAY(av)[key]) { emptyness: return lval ? av_store(av,key,newSV(0)) : NULL; } @@ -258,7 +257,7 @@ Perl_av_fetch(pTHX_ AV *av, I32 key, I32 lval) if (AvREIFY(av) && (!AvARRAY(av)[key] /* eg. @_ could have freed elts */ || SvIS_FREED(AvARRAY(av)[key]))) { - AvARRAY(av)[key] = &PL_sv_undef; /* 1/2 reify */ + AvARRAY(av)[key] = NULL; /* 1/2 reify */ goto emptyness; } return &AvARRAY(av)[key]; @@ -299,9 +298,6 @@ Perl_av_store(pTHX_ AV *av, I32 key, SV *val) (unicode_alternate may be NULL). */ - if (!val) - val = &PL_sv_undef; - if (SvRMAGICAL(av)) { const MAGIC * const tied_magic = mg_find((const SV *)av, PERL_MAGIC_tied); if (tied_magic) { @@ -309,7 +305,7 @@ Perl_av_store(pTHX_ AV *av, I32 key, SV *val) if (!S_adjust_index(aTHX_ av, tied_magic, &key)) return 0; } - if (val != &PL_sv_undef) { + if (val) { mg_copy(MUTABLE_SV(av), val, 0, key); } return NULL; @@ -336,7 +332,7 @@ Perl_av_store(pTHX_ AV *av, I32 key, SV *val) if (av == PL_curstack && key > PL_stack_sp - PL_stack_base) PL_stack_sp = PL_stack_base + key; /* XPUSH in disguise */ do { - ary[++AvFILLp(av)] = &PL_sv_undef; + ary[++AvFILLp(av)] = NULL; } while (AvFILLp(av) < key); } AvFILLp(av) = key; @@ -349,7 +345,7 @@ Perl_av_store(pTHX_ AV *av, I32 key, SV *val) bool set = TRUE; for (; mg; mg = mg->mg_moremagic) { if (!isUPPER(mg->mg_type)) continue; - if (val != &PL_sv_undef) { + if (val) { sv_magic(val, MUTABLE_SV(av), toLOWER(mg->mg_type), 0, key); } if (PL_delaymagic && mg->mg_type == PERL_MAGIC_isa) { @@ -465,7 +461,7 @@ Perl_av_clear(pTHX_ AV *av) SV * const sv = ary[--index]; /* undef the slot before freeing the value, because a * destructor might try to modify this array */ - ary[index] = &PL_sv_undef; + ary[index] = NULL; SvREFCNT_dec(sv); } } @@ -601,10 +597,10 @@ Perl_av_pop(pTHX_ AV *av) if (AvFILL(av) < 0) return &PL_sv_undef; retval = AvARRAY(av)[AvFILLp(av)]; - AvARRAY(av)[AvFILLp(av)--] = &PL_sv_undef; + AvARRAY(av)[AvFILLp(av)--] = NULL; if (SvSMAGICAL(av)) mg_set(MUTABLE_SV(av)); - return retval; + return retval ? retval : &PL_sv_undef; } /* @@ -685,7 +681,7 @@ Perl_av_unshift(pTHX_ AV *av, I32 num) ary = AvARRAY(av); Move(ary, ary + num, i + 1, SV*); do { - ary[--num] = &PL_sv_undef; + ary[--num] = NULL; } while (num); /* Make extra elements into a buffer */ AvMAX(av) -= slide; @@ -728,13 +724,13 @@ Perl_av_shift(pTHX_ AV *av) return &PL_sv_undef; retval = *AvARRAY(av); if (AvREAL(av)) - *AvARRAY(av) = &PL_sv_undef; + *AvARRAY(av) = NULL; AvARRAY(av) = AvARRAY(av) + 1; AvMAX(av)--; AvFILLp(av)--; if (SvSMAGICAL(av)) mg_set(MUTABLE_SV(av)); - return retval; + return retval ? retval : &PL_sv_undef; } /* @@ -772,7 +768,7 @@ Perl's C<$#array = $fill;>. The number of elements in the an array will be C after av_fill() returns. If the array was previously shorter, then the -additional elements appended are set to C. If the array +additional elements appended are set to NULL. If the array was longer, then the excess elements are freed. C is the same as C. @@ -803,12 +799,12 @@ Perl_av_fill(pTHX_ AV *av, I32 fill) if (AvREAL(av)) { while (key > fill) { SvREFCNT_dec(ary[key]); - ary[key--] = &PL_sv_undef; + ary[key--] = NULL; } } else { while (key < fill) - ary[++key] = &PL_sv_undef; + ary[++key] = NULL; } AvFILLp(av) = fill; @@ -816,7 +812,7 @@ Perl_av_fill(pTHX_ AV *av, I32 fill) mg_set(MUTABLE_SV(av)); } else - (void)av_store(av,fill,&PL_sv_undef); + (void)av_store(av,fill,NULL); } /* @@ -877,13 +873,13 @@ Perl_av_delete(pTHX_ AV *av, I32 key, I32 flags) av_reify(av); sv = AvARRAY(av)[key]; if (key == AvFILLp(av)) { - AvARRAY(av)[key] = &PL_sv_undef; + AvARRAY(av)[key] = NULL; do { AvFILLp(av)--; - } while (--key >= 0 && AvARRAY(av)[key] == &PL_sv_undef); + } while (--key >= 0 && !AvARRAY(av)[key]); } else - AvARRAY(av)[key] = &PL_sv_undef; + AvARRAY(av)[key] = NULL; if (SvSMAGICAL(av)) mg_set(MUTABLE_SV(av)); } @@ -902,7 +898,7 @@ Perl_av_delete(pTHX_ AV *av, I32 key, I32 flags) Returns true if the element indexed by C has been initialized. This relies on the fact that uninitialized array elements are set to -C<&PL_sv_undef>. +NULL. Perl equivalent: C. @@ -955,8 +951,7 @@ Perl_av_exists(pTHX_ AV *av, I32 key) return FALSE; } - if (key <= AvFILLp(av) && AvARRAY(av)[key] != &PL_sv_undef - && AvARRAY(av)[key]) + if (key <= AvFILLp(av) && AvARRAY(av)[key]) { return TRUE; } diff --git a/dist/Storable/Storable.xs b/dist/Storable/Storable.xs index 439009a..c895170 100644 --- a/dist/Storable/Storable.xs +++ b/dist/Storable/Storable.xs @@ -156,7 +156,8 @@ #define SX_WEAKOVERLOAD C(28) /* Overloaded weak reference */ #define SX_VSTRING C(29) /* vstring forthcoming (small) */ #define SX_LVSTRING C(30) /* vstring forthcoming (large) */ -#define SX_ERROR C(31) /* Error */ +#define SX_SVUNDEF_ELEM C(31) /* array element set to &PL_sv_undef */ +#define SX_ERROR C(32) /* Error */ /* * Those are only used to retrieve "old" pre-0.6 binary images. @@ -843,7 +844,7 @@ static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0}; #endif #define STORABLE_BIN_MAJOR 2 /* Binary major "version" */ -#define STORABLE_BIN_MINOR 9 /* Binary minor "version" */ +#define STORABLE_BIN_MINOR 10 /* Binary minor "version" */ #if (PATCHLEVEL <= 5) #define STORABLE_BIN_WRITE_MINOR 4 @@ -852,6 +853,9 @@ static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0}; * Perl 5.6.0-5.8.0 can do weak references, but not vstring magic. */ #define STORABLE_BIN_WRITE_MINOR 8 +#elif PATCHLEVEL >= 19 +/* Perl 5.19 takes away the special meaning of PL_sv_undef in arrays. */ +#define STORABLE_BIN_WRITE_MINOR 10 #else #define STORABLE_BIN_WRITE_MINOR 9 #endif /* (PATCHLEVEL <= 5) */ @@ -935,7 +939,9 @@ static const char byteorderstr_56[] = {BYTEORDER_BYTES_56, 0}; #define STORE_SCALAR(pv, len) STORE_PV_LEN(pv, len, SX_SCALAR, SX_LSCALAR) /* - * Store &PL_sv_undef in arrays without recursing through store(). + * Store &PL_sv_undef in arrays without recursing through store(). We + * actually use this to represent nonexistent elements, for historical + * reasons. */ #define STORE_SV_UNDEF() \ STMT_START { \ @@ -1186,6 +1192,7 @@ static const sv_retrieve_t sv_old_retrieve[] = { (sv_retrieve_t)retrieve_other, /* SX_WEAKOVERLOAD not supported */ (sv_retrieve_t)retrieve_other, /* SX_VSTRING not supported */ (sv_retrieve_t)retrieve_other, /* SX_LVSTRING not supported */ + (sv_retrieve_t)retrieve_other, /* SX_SVUNDEF_ELEM not supported */ (sv_retrieve_t)retrieve_other, /* SX_ERROR */ }; @@ -1206,6 +1213,7 @@ static SV *retrieve_weakref(pTHX_ stcxt_t *cxt, const char *cname); static SV *retrieve_weakoverloaded(pTHX_ stcxt_t *cxt, const char *cname); static SV *retrieve_vstring(pTHX_ stcxt_t *cxt, const char *cname); static SV *retrieve_lvstring(pTHX_ stcxt_t *cxt, const char *cname); +static SV *retrieve_svundef_elem(pTHX_ stcxt_t *cxt, const char *cname); static const sv_retrieve_t sv_retrieve[] = { 0, /* SX_OBJECT -- entry unused dynamically */ @@ -1239,6 +1247,7 @@ static const sv_retrieve_t sv_retrieve[] = { (sv_retrieve_t)retrieve_weakoverloaded, /* SX_WEAKOVERLOAD */ (sv_retrieve_t)retrieve_vstring, /* SX_VSTRING */ (sv_retrieve_t)retrieve_lvstring, /* SX_LVSTRING */ + (sv_retrieve_t)retrieve_svundef_elem, /* SX_SVUNDEF_ELEM */ (sv_retrieve_t)retrieve_other, /* SX_ERROR */ }; @@ -2253,10 +2262,23 @@ static int store_array(pTHX_ stcxt_t *cxt, AV *av) for (i = 0; i < len; i++) { sav = av_fetch(av, i, 0); if (!sav) { - TRACEME(("(#%d) undef item", i)); + TRACEME(("(#%d) nonexistent item", i)); STORE_SV_UNDEF(); continue; } +#if PATCHLEVEL >= 19 + /* In 5.19.3 and up, &PL_sv_undef can actually be stored in + * an array; it no longer represents nonexistent elements. + * Historically, we have used SX_SV_UNDEF in arrays for + * nonexistent elements, so we use SX_SVUNDEF_ELEM for + * &PL_sv_undef itself. */ + if (*sav == &PL_sv_undef) { + TRACEME(("(#%d) undef item", i)); + cxt->tagnum++; + PUTMARK(SX_SVUNDEF_ELEM); + continue; + } +#endif TRACEME(("(#%d) item", i)); if ((ret = store(aTHX_ cxt, *sav))) /* Extra () for -Wall, grr... */ return ret; @@ -5238,6 +5260,24 @@ static SV *retrieve_sv_no(pTHX_ stcxt_t *cxt, const char *cname) } /* + * retrieve_svundef_elem + * + * Return &PL_sv_placeholder, representing &PL_sv_undef in an array. This + * is a bit of a hack, but we already use SX_SV_UNDEF to mean a nonexistent + * element, for historical reasons. + */ +static SV *retrieve_svundef_elem(pTHX_ stcxt_t *cxt, const char *cname) +{ + TRACEME(("retrieve_svundef_elem")); + + /* SEEN reads the contents of its SV argument, which we are not + supposed to do with &PL_sv_placeholder. */ + SEEN(&PL_sv_undef, cname, 1); + + return &PL_sv_placeholder; +} + +/* * retrieve_array * * Retrieve a whole array. @@ -5253,6 +5293,7 @@ static SV *retrieve_array(pTHX_ stcxt_t *cxt, const char *cname) AV *av; SV *sv; HV *stash; + bool seen_null = FALSE; TRACEME(("retrieve_array (#%d)", cxt->tagnum)); @@ -5279,9 +5320,16 @@ static SV *retrieve_array(pTHX_ stcxt_t *cxt, const char *cname) sv = retrieve(aTHX_ cxt, 0); /* Retrieve item */ if (!sv) return (SV *) 0; + if (sv == &PL_sv_undef) { + seen_null = TRUE; + continue; + } + if (sv == &PL_sv_placeholder) + sv = &PL_sv_undef; if (av_store(av, i, sv) == 0) return (SV *) 0; } + if (seen_null) av_fill(av, len-1); TRACEME(("ok (retrieve_array at 0x%"UVxf")", PTR2UV(av))); diff --git a/dist/Storable/t/malice.t b/dist/Storable/t/malice.t index ffc9fcf..867a0d7 100644 --- a/dist/Storable/t/malice.t +++ b/dist/Storable/t/malice.t @@ -34,8 +34,8 @@ $file_magic_str = 'pst0'; $other_magic = 7 + length $byteorder; $network_magic = 2; $major = 2; -$minor = 9; -$minor_write = $] > 5.008 ? 9 : $] > 5.005_50 ? 8 : 4; +$minor = 10; +$minor_write = $] >= 5.019 ? 10 : $] > 5.008 ? 9 : $] > 5.005_50 ? 8 : 4; use Test::More; @@ -208,7 +208,7 @@ sub test_things { $where = $file_magic + $network_magic; } - # Just the header and a tag 255. As 30 is currently the highest tag, this + # Just the header and a tag 255. As 31 is currently the highest tag, this # is "unexpected" $copy = substr ($contents, 0, $where) . chr 255; @@ -228,7 +228,7 @@ sub test_things { # local $Storable::DEBUGME = 1; # This is the delayed croak test_corrupt ($copy, $sub, - "/^Storable binary image v$header->{major}.$minor6 contains data of type 255. This Storable is v$header->{major}.$minor and can only handle data types up to 30/", + "/^Storable binary image v$header->{major}.$minor6 contains data of type 255. This Storable is v$header->{major}.$minor and can only handle data types up to 31/", "bogus tag, minor plus 4"); # And check again that this croak is not delayed: { diff --git a/ext/B/t/showlex.t b/ext/B/t/showlex.t index 6a53182..2871622 100644 --- a/ext/B/t/showlex.t +++ b/ext/B/t/showlex.t @@ -31,7 +31,7 @@ if ($is_thread) { ok "# use5005threads: test skipped\n"; } else { $a = `$^X $path "-MO=Showlex" -e "my \@one" 2>&1`; - like ($a, qr/sv_undef.*PVNV.*\@one.*sv_undef.*AV/s, + like ($a, qr/sv_undef.*PVNV.*\@one.*Nullsv.*AV/s, "canonical usage works"); } diff --git a/ext/Devel-Peek/Peek.xs b/ext/Devel-Peek/Peek.xs index 1ea7f8f..73094b8 100644 --- a/ext/Devel-Peek/Peek.xs +++ b/ext/Devel-Peek/Peek.xs @@ -81,6 +81,7 @@ DeadCode(pTHX) } } for (j = 1; j < AvFILL((AV*)svp[1]); j++) { /* Vars. */ + if (!pad[j]) continue; if (SvROK(pad[j])) { levelref++; do_sv_dump(0, Perl_debug_log, pad[j], 0, 4, 0, 0); diff --git a/ext/IPC-Open3/lib/IPC/Open3.pm b/ext/IPC-Open3/lib/IPC/Open3.pm index af1d1e0..90bd9fb 100644 --- a/ext/IPC-Open3/lib/IPC/Open3.pm +++ b/ext/IPC-Open3/lib/IPC/Open3.pm @@ -185,6 +185,10 @@ sub _open3 { # it's too ugly to use @_ throughout to make perl do it for us # tchrist 5-Mar-00 + # Historically, open3(undef...) has silently worked, so keep + # it working. + splice @_, 0, 1, undef if \$_[0] == \undef; + splice @_, 1, 1, undef if \$_[1] == \undef; unless (eval { $_[0] = gensym unless defined $_[0] && length $_[0]; $_[1] = gensym unless defined $_[1] && length $_[1]; diff --git a/pad.c b/pad.c index d8d9322..92765f0 100644 --- a/pad.c +++ b/pad.c @@ -285,6 +285,7 @@ Perl_pad_new(pTHX_ int flags) av_store(pad, 0, NULL); padname = newAV(); AvPAD_NAMELIST_on(padname); + av_store(padname, 0, &PL_sv_undef); } /* Most subroutines never recurse, hence only need 2 entries in the padlist @@ -1651,11 +1652,13 @@ Perl_pad_swipe(pTHX_ PADOFFSET po, bool refadjust) PL_curpad[po] = newSV(0); SvPADTMP_on(PL_curpad[po]); #else - PL_curpad[po] = &PL_sv_undef; + PL_curpad[po] = NULL; #endif if (PadnamelistMAX(PL_comppad_name) != -1 && (PADOFFSET)PadnamelistMAX(PL_comppad_name) >= po) { - assert(!PadnameLEN(PadnamelistARRAY(PL_comppad_name)[po])); + if (PadnamelistARRAY(PL_comppad_name)[po]) { + assert(!PadnameLEN(PadnamelistARRAY(PL_comppad_name)[po])); + } PadnamelistARRAY(PL_comppad_name)[po] = &PL_sv_undef; } if ((I32)po < PL_padix) @@ -1767,21 +1770,23 @@ Perl_pad_tidy(pTHX_ padtidy_type type) av_store(PL_comppad_name, AvFILLp(PL_comppad), NULL); if (type == padtidy_SUBCLONE) { - SV * const * const namep = AvARRAY(PL_comppad_name); + SV ** const namep = AvARRAY(PL_comppad_name); PADOFFSET ix; for (ix = AvFILLp(PL_comppad); ix > 0; ix--) { SV *namesv; + if (!namep[ix]) namep[ix] = &PL_sv_undef; /* * The only things that a clonable function needs in its * pad are anonymous subs, constants and GVs. * The rest are created anew during cloning. */ - if (SvIMMORTAL(PL_curpad[ix]) || IS_PADGV(PL_curpad[ix])) + if (!PL_curpad[ix] || SvIMMORTAL(PL_curpad[ix]) + || IS_PADGV(PL_curpad[ix])) continue; - if (!((namesv = namep[ix]) != NULL && - PadnamePV(namesv) && + namesv = namep[ix]; + if (!(PadnamePV(namesv) && (!PadnameLEN(namesv) || *SvPVX_const(namesv) == '&'))) { SvREFCNT_dec(PL_curpad[ix]); @@ -1797,10 +1802,12 @@ Perl_pad_tidy(pTHX_ padtidy_type type) } if (type == padtidy_SUB || type == padtidy_FORMAT) { - SV * const * const namep = AvARRAY(PL_comppad_name); + SV ** const namep = AvARRAY(PL_comppad_name); PADOFFSET ix; for (ix = AvFILLp(PL_comppad); ix > 0; ix--) { - if (SvIMMORTAL(PL_curpad[ix]) || IS_PADGV(PL_curpad[ix]) || IS_PADCONST(PL_curpad[ix])) + if (!namep[ix]) namep[ix] = &PL_sv_undef; + if (!PL_curpad[ix] || SvIMMORTAL(PL_curpad[ix]) + || IS_PADGV(PL_curpad[ix]) || IS_PADCONST(PL_curpad[ix])) continue; if (!SvPADMY(PL_curpad[ix])) { SvPADTMP_on(PL_curpad[ix]); @@ -2417,7 +2424,8 @@ Perl_padlist_dup(pTHX_ PADLIST *srcpad, CLONE_PARAMS *param) for ( ;ix > 0; ix--) { if (!oldpad[ix]) { pad1a[ix] = NULL; - } else if (names_fill >= ix && PadnameLEN(names[ix])) { + } else if (names_fill >= ix && names[ix] && + PadnameLEN(names[ix])) { const char sigil = SvPVX_const(names[ix])[0]; if ((SvFLAGS(names[ix]) & SVf_FAKE) || (SvFLAGS(names[ix]) & SVpad_STATE) @@ -2446,7 +2454,9 @@ Perl_padlist_dup(pTHX_ PADLIST *srcpad, CLONE_PARAMS *param) } } } - else if (IS_PADGV(oldpad[ix]) || PadnamePV(names[ix])) { + else if (IS_PADGV(oldpad[ix]) + || ( names_fill >= ix && names[ix] + && PadnamePV(names[ix]) )) { pad1a[ix] = sv_dup_inc(oldpad[ix], param); } else { diff --git a/pp.c b/pp.c index fd40453..17e0f3b 100644 --- a/pp.c +++ b/pp.c @@ -4330,7 +4330,7 @@ PP(pp_aslice) svp = av_fetch(av, elem, lval); if (lval) { - if (!svp || *svp == &PL_sv_undef) + if (!svp || !*svp) DIE(aTHX_ PL_no_aelem, elem); if (localizing) { if (preeminent) @@ -5016,7 +5016,7 @@ PP(pp_splice) } i = -diff; while (i) - dst[--i] = &PL_sv_undef; + dst[--i] = NULL; if (newlen) { Copy( tmparyval, AvARRAY(ary) + offset, newlen, SV* ); diff --git a/pp_hot.c b/pp_hot.c index b08643f..58a3083 100644 --- a/pp_hot.c +++ b/pp_hot.c @@ -339,7 +339,11 @@ S_pushav(pTHX_ AV* const av) } } else { - Copy(AvARRAY(av), SP+1, maxarg, SV*); + U32 i; + for (i=0; i < (U32)maxarg; i++) { + SV * const sv = AvARRAY(av)[i]; + SP[i+1] = sv ? sv : &PL_sv_undef; + } } SP += maxarg; PUTBACK; @@ -1055,8 +1059,8 @@ PP(pp_aassign) i = 0; while (relem <= lastrelem) { /* gobble up all the rest */ SV **didstore; - assert(*relem); - SvGETMAGIC(*relem); /* before newSV, in case it dies */ + if (*relem) + SvGETMAGIC(*relem); /* before newSV, in case it dies */ sv = newSV(0); sv_setsv_nomg(sv, *relem); *(relem++) = sv; @@ -2830,7 +2834,7 @@ PP(pp_aelem) MEM_WRAP_CHECK_1(elem,SV*,oom_array_extend); } #endif - if (!svp || *svp == &PL_sv_undef) { + if (!svp || !*svp) { SV* lv; if (!defer) DIE(aTHX_ PL_no_aelem, elem); diff --git a/regexec.c b/regexec.c index 5f142a0..d207d0d 100644 --- a/regexec.c +++ b/regexec.c @@ -7318,7 +7318,7 @@ S_core_regclass_swash(pTHX_ const regexp *prog, const regnode* node, bool doinit /* Element [1] is reserved for the set-up swash. If already there, * return it; if not, create it and store it there */ - if (SvROK(ary[1])) { + if (ary[1] && SvROK(ary[1])) { sw = ary[1]; } else if (si && doinit) { -- 1.8.3.1