X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/fc16c3924bd6aa054f21ad5445fecf9b7f39dc36..aa0c5741dff171689a361a897f3581674f0d1922:/av.c diff --git a/av.c b/av.c index 401a61c..ba97fed 100644 --- a/av.c +++ b/av.c @@ -26,8 +26,7 @@ void Perl_av_reify(pTHX_ AV *av) { - dVAR; - I32 key; + SSize_t key; PERL_ARGS_ASSERT_AV_REIFY; assert(SvTYPE(av) == SVt_PVAV); @@ -65,7 +64,6 @@ extended. void Perl_av_extend(pTHX_ AV *av, SSize_t key) { - dVAR; MAGIC *mg; PERL_ARGS_ASSERT_AV_EXTEND; @@ -87,10 +85,12 @@ void Perl_av_extend_guts(pTHX_ AV *av, SSize_t key, SSize_t *maxp, SV ***allocp, SV ***arrayp) { - dVAR; - PERL_ARGS_ASSERT_AV_EXTEND_GUTS; + if (key < -1) /* -1 is legal */ + Perl_croak(aTHX_ + "panic: av_extend_guts() negative count (%" IVdf ")", (IV)key); + if (key > *maxp) { SV** ary; SSize_t tmp; @@ -112,11 +112,6 @@ Perl_av_extend_guts(pTHX_ AV *av, SSize_t key, SSize_t *maxp, SV ***allocp, } } else { -#ifdef PERL_MALLOC_WRAP - static const char oom_array_extend[] = - "Out of memory during array extend"; /* Duplicated in pp_hot.c */ -#endif - if (*allocp) { #ifdef Perl_safesysmalloc_size @@ -139,10 +134,34 @@ Perl_av_extend_guts(pTHX_ AV *av, SSize_t key, SSize_t *maxp, SV ***allocp, if (key <= newmax) goto resized; #endif - newmax = key + *maxp / 5; + /* overflow-safe version of newmax = key + *maxp/5 */ + newmax = *maxp / 5; + newmax = (key > SSize_t_MAX - newmax) + ? SSize_t_MAX : key + newmax; resize: - MEM_WRAP_CHECK_1(newmax+1, SV*, oom_array_extend); + { +#ifdef PERL_MALLOC_WRAP /* Duplicated in pp_hot.c */ + static const char oom_array_extend[] = + "Out of memory during array extend"; +#endif + /* it should really be newmax+1 here, but if newmax + * happens to equal SSize_t_MAX, then newmax+1 is + * undefined. This means technically we croak one + * index lower than we should in theory; in practice + * its unlikely the system has SSize_t_MAX/sizeof(SV*) + * bytes to spare! */ + MEM_WRAP_CHECK_1(newmax, SV*, oom_array_extend); + } +#ifdef STRESS_REALLOC + { + SV ** const old_alloc = *allocp; + Newx(*allocp, newmax+1, SV*); + Copy(old_alloc, *allocp, *maxp + 1, SV*); + Safefree(old_alloc); + } +#else Renew(*allocp,newmax+1, SV*); +#endif #ifdef Perl_safesysmalloc_size resized: #endif @@ -156,7 +175,14 @@ Perl_av_extend_guts(pTHX_ AV *av, SSize_t key, SSize_t *maxp, SV ***allocp, } else { newmax = key < 3 ? 3 : key; - MEM_WRAP_CHECK_1(newmax+1, SV*, oom_array_extend); + { +#ifdef PERL_MALLOC_WRAP /* Duplicated in pp_hot.c */ + static const char oom_array_extend[] = + "Out of memory during array extend"; +#endif + /* see comment above about newmax+1*/ + MEM_WRAP_CHECK_1(newmax, SV*, oom_array_extend); + } Newx(*allocp, newmax+1, SV*); ary = *allocp + 1; tmp = newmax; @@ -184,13 +210,13 @@ value is non-null before dereferencing it to a C. See L for more information on how to use this function on tied arrays. -The rough perl equivalent is C<$myarray[$idx]>. +The rough perl equivalent is C<$myarray[$key]>. =cut */ static bool -S_adjust_index(pTHX_ AV *av, const MAGIC *mg, I32 *keyp) +S_adjust_index(pTHX_ AV *av, const MAGIC *mg, SSize_t *keyp) { bool adjust_index = 1; if (mg) { @@ -201,7 +227,8 @@ S_adjust_index(pTHX_ AV *av, const MAGIC *mg, I32 *keyp) SV * const * const negative_indices_glob = hv_fetchs(SvSTASH(SvRV(ref)), NEGATIVE_INDICES_VAR, 0); - if (negative_indices_glob && SvTRUE(GvSV(*negative_indices_glob))) + if (negative_indices_glob && isGV(*negative_indices_glob) + && SvTRUE(GvSV(*negative_indices_glob))) adjust_index = 0; } } @@ -215,14 +242,15 @@ S_adjust_index(pTHX_ AV *av, const MAGIC *mg, I32 *keyp) } SV** -Perl_av_fetch(pTHX_ AV *av, I32 key, I32 lval) +Perl_av_fetch(pTHX_ AV *av, SSize_t key, I32 lval) { - dVAR; + SSize_t neg; + SSize_t size; PERL_ARGS_ASSERT_AV_FETCH; assert(SvTYPE(av) == SVt_PVAV); - if (SvRMAGICAL(av)) { + if (UNLIKELY(SvRMAGICAL(av))) { const MAGIC * const tied_magic = mg_find((const SV *)av, PERL_MAGIC_tied); if (tied_magic || mg_find((const SV *)av, PERL_MAGIC_regdata)) { @@ -243,23 +271,23 @@ Perl_av_fetch(pTHX_ AV *av, I32 key, I32 lval) } } - if (key < 0) { - key += AvFILL(av) + 1; - if (key < 0) + neg = (key < 0); + size = AvFILLp(av) + 1; + key += neg * size; /* handle negative index without using branch */ + + /* the cast from SSize_t to Size_t allows both (key < 0) and (key >= size) + * to be tested as a single condition */ + if ((Size_t)key >= (Size_t)size) { + if (UNLIKELY(neg)) return NULL; + goto emptyness; } - if (key > AvFILLp(av) || !AvARRAY(av)[key]) { + if (!AvARRAY(av)[key]) { emptyness: return lval ? av_store(av,key,newSV(0)) : NULL; } - if (AvREIFY(av) - && (!AvARRAY(av)[key] /* eg. @_ could have freed elts */ - || SvIS_FREED(AvARRAY(av)[key]))) { - AvARRAY(av)[key] = NULL; /* 1/2 reify */ - goto emptyness; - } return &AvARRAY(av)[key]; } @@ -267,17 +295,17 @@ Perl_av_fetch(pTHX_ AV *av, I32 key, I32 lval) =for apidoc av_store Stores an SV in an array. The array index is specified as C. The -return value will be NULL if the operation failed or if the value did not +return value will be C if the operation failed or if the value did not need to be actually stored within the array (as in the case of tied -arrays). Otherwise, it can be dereferenced +arrays). Otherwise, it can be dereferenced to get the C that was stored there (= C)). Note that the caller is responsible for suitably incrementing the reference count of C before the call, and decrementing it if the function -returned NULL. +returned C. -Approximate Perl equivalent: C<$myarray[$key] = $val;>. +Approximate Perl equivalent: C. See L for more information on how to use this function on tied arrays. @@ -286,9 +314,8 @@ more information on how to use this function on tied arrays. */ SV** -Perl_av_store(pTHX_ AV *av, I32 key, SV *val) +Perl_av_store(pTHX_ AV *av, SSize_t key, SV *val) { - dVAR; SV** ary; PERL_ARGS_ASSERT_AV_STORE; @@ -363,7 +390,7 @@ Perl_av_store(pTHX_ AV *av, I32 key, SV *val) =for apidoc av_make Creates a new AV and populates it with a list of SVs. The SVs are copied -into the array, so they may be freed after the call to av_make. The new AV +into the array, so they may be freed after the call to C. The new AV will have a reference count of 1. Perl equivalent: C @@ -372,7 +399,7 @@ Perl equivalent: C */ AV * -Perl_av_make(pTHX_ I32 size, SV **strp) +Perl_av_make(pTHX_ SSize_t size, SV **strp) { AV * const av = MUTABLE_AV(newSV_type(SVt_PVAV)); /* sv_upgrade does AvREAL_only() */ @@ -381,14 +408,19 @@ Perl_av_make(pTHX_ I32 size, SV **strp) if (size) { /* "defined" was returning undef for size==0 anyway. */ SV** ary; - I32 i; + SSize_t i; + SSize_t orig_ix; + Newx(ary,size,SV*); AvALLOC(av) = ary; AvARRAY(av) = ary; AvMAX(av) = size - 1; AvFILLp(av) = -1; - ENTER; - SAVEFREESV(av); + /* avoid av being leaked if croak when calling magic below */ + EXTEND_MORTAL(1); + PL_tmps_stack[++PL_tmps_ix] = (SV*)av; + orig_ix = PL_tmps_ix; + for (i = 0; i < size; i++) { assert (*strp); @@ -403,8 +435,11 @@ Perl_av_make(pTHX_ I32 size, SV **strp) SV_DO_COW_SVSETSV|SV_NOSTEAL); strp++; } - SvREFCNT_inc_simple_void_NN(av); - LEAVE; + /* disarm av's leak guard */ + if (LIKELY(PL_tmps_ix == orig_ix)) + PL_tmps_ix--; + else + PL_tmps_stack[orig_ix] = &PL_sv_undef; } return av; } @@ -412,11 +447,15 @@ Perl_av_make(pTHX_ I32 size, SV **strp) /* =for apidoc av_clear -Clears an array, making it empty. Does not free the memory the av uses to -store its list of scalars. If any destructors are triggered as a result, -the av itself may be freed when this function returns. +Frees the all the elements of an array, leaving it empty. +The XS equivalent of C<@array = ()>. See also L. -Perl equivalent: C<@myarray = ();>. +Note that it is possible that the actions of a destructor called directly +or indirectly by freeing an element of the array could cause the reference +count of the array itself to be reduced (e.g. by deleting an entry in the +symbol table). So it is a possibility that the AV could have been freed +(or even reallocated) on return from the call unless you hold a reference +to it. =cut */ @@ -424,9 +463,9 @@ Perl equivalent: C<@myarray = ();>. void Perl_av_clear(pTHX_ AV *av) { - dVAR; - I32 extra; + SSize_t extra; bool real; + SSize_t orig_ix = 0; PERL_ARGS_ASSERT_AV_CLEAR; assert(SvTYPE(av) == SVt_PVAV); @@ -452,11 +491,15 @@ Perl_av_clear(pTHX_ AV *av) if (AvMAX(av) < 0) return; - if ((real = !!AvREAL(av))) { + if ((real = cBOOL(AvREAL(av)))) { SV** const ary = AvARRAY(av); - I32 index = AvFILLp(av) + 1; - ENTER; - SAVEFREESV(SvREFCNT_inc_simple_NN(av)); + SSize_t index = AvFILLp(av) + 1; + + /* avoid av being freed when calling destructors below */ + EXTEND_MORTAL(1); + PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(av); + orig_ix = PL_tmps_ix; + while (index) { SV * const sv = ary[--index]; /* undef the slot before freeing the value, because a @@ -471,15 +514,26 @@ Perl_av_clear(pTHX_ AV *av) AvARRAY(av) = AvALLOC(av); } AvFILLp(av) = -1; - if (real) LEAVE; + if (real) { + /* disarm av's premature free guard */ + if (LIKELY(PL_tmps_ix == orig_ix)) + PL_tmps_ix--; + else + PL_tmps_stack[orig_ix] = &PL_sv_undef; + SvREFCNT_dec_NN(av); + } } /* =for apidoc av_undef -Undefines the array. Frees the memory used by the av to store its list of -scalars. If any destructors are triggered as a result, the av itself may -be freed. +Undefines the array. The XS equivalent of C. + +As well as freeing all the elements of the array (like C), this +also frees the memory used by the av to store its list of scalars. + +See L for a note about the array possibly being invalid on +return. =cut */ @@ -488,6 +542,7 @@ void Perl_av_undef(pTHX_ AV *av) { bool real; + SSize_t orig_ix = PL_tmps_ix; /* silence bogus warning about possible unitialized use */ PERL_ARGS_ASSERT_AV_UNDEF; assert(SvTYPE(av) == SVt_PVAV); @@ -496,10 +551,15 @@ Perl_av_undef(pTHX_ AV *av) if (SvTIED_mg((const SV *)av, PERL_MAGIC_tied)) av_fill(av, -1); - if ((real = !!AvREAL(av))) { - I32 key = AvFILLp(av) + 1; - ENTER; - SAVEFREESV(SvREFCNT_inc_simple_NN(av)); + real = cBOOL(AvREAL(av)); + if (real) { + SSize_t key = AvFILLp(av) + 1; + + /* avoid av being freed when calling destructors below */ + EXTEND_MORTAL(1); + PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(av); + orig_ix = PL_tmps_ix; + while (key) SvREFCNT_dec(AvARRAY(av)[--key]); } @@ -510,7 +570,14 @@ Perl_av_undef(pTHX_ AV *av) AvMAX(av) = AvFILLp(av) = -1; if(SvRMAGICAL(av)) mg_clear(MUTABLE_SV(av)); - if(real) LEAVE; + if (real) { + /* disarm av's premature free guard */ + if (LIKELY(PL_tmps_ix == orig_ix)) + PL_tmps_ix--; + else + PL_tmps_stack[orig_ix] = &PL_sv_undef; + SvREFCNT_dec_NN(av); + } } /* @@ -536,10 +603,10 @@ Perl_av_create_and_push(pTHX_ AV **const avp, SV *const val) /* =for apidoc av_push -Pushes an SV onto the end of the array. The array will grow automatically -to accommodate the addition. This takes ownership of one reference count. +Pushes an SV (transferring control of one reference count) onto the end of the +array. The array will grow automatically to accommodate the addition. -Perl equivalent: C. +Perl equivalent: C. =cut */ @@ -547,7 +614,6 @@ Perl equivalent: C. void Perl_av_push(pTHX_ AV *av, SV *val) { - dVAR; MAGIC *mg; PERL_ARGS_ASSERT_AV_PUSH; @@ -579,7 +645,6 @@ Perl equivalent: C SV * Perl_av_pop(pTHX_ AV *av) { - dVAR; SV *retval; MAGIC* mg; @@ -629,19 +694,17 @@ Perl_av_create_and_unshift_one(pTHX_ AV **const avp, SV *const val) =for apidoc av_unshift Unshift the given number of C values onto the beginning of the -array. The array will grow automatically to accommodate the addition. You -must then use C to assign values to these new elements. +array. The array will grow automatically to accommodate the addition. -Perl equivalent: C +Perl equivalent: S> =cut */ void -Perl_av_unshift(pTHX_ AV *av, I32 num) +Perl_av_unshift(pTHX_ AV *av, SSize_t num) { - dVAR; - I32 i; + SSize_t i; MAGIC* mg; PERL_ARGS_ASSERT_AV_UNSHIFT; @@ -672,9 +735,9 @@ Perl_av_unshift(pTHX_ AV *av, I32 num) } if (num) { SV **ary; - const I32 i = AvFILLp(av); + const SSize_t i = AvFILLp(av); /* Create extra elements */ - const I32 slide = i > 0 ? i : 0; + const SSize_t slide = i > 0 ? i : 0; num += slide; av_extend(av, i + num); AvFILLp(av) += num; @@ -705,7 +768,6 @@ Perl equivalent: C SV * Perl_av_shift(pTHX_ AV *av) { - dVAR; SV *retval; MAGIC* mg; @@ -737,7 +799,7 @@ Perl_av_shift(pTHX_ AV *av) =for apidoc av_top_index Returns the highest index in the array. The number of elements in the -array is C. Returns -1 if the array is empty. +array is S>. Returns -1 if the array is empty. The Perl equivalent for this is C<$#myarray>. @@ -745,14 +807,15 @@ The Perl equivalent for this is C<$#myarray>. =for apidoc av_len -Same as L. Returns the highest index in the array. Note that the -return value is +1 what its name implies it returns; and hence differs in -meaning from what the similarly named L returns. +Same as L. Note that, unlike what the name implies, it returns +the highest index in the array, so to get the size of the array you need to use +S>. This is unlike L, which returns what you would +expect. =cut */ -I32 +SSize_t Perl_av_len(pTHX_ AV *av) { PERL_ARGS_ASSERT_AV_LEN; @@ -764,20 +827,19 @@ Perl_av_len(pTHX_ AV *av) =for apidoc av_fill Set the highest index in the array to the given number, equivalent to -Perl's C<$#array = $fill;>. +Perl's S>. -The number of elements in the an array will be C after -av_fill() returns. If the array was previously shorter, then the +The number of elements in the array will be S> after +C returns. If the array was previously shorter, then the additional elements appended are set to NULL. If the array -was longer, then the excess elements are freed. C is +was longer, then the excess elements are freed. S> is the same as C. =cut */ void -Perl_av_fill(pTHX_ AV *av, I32 fill) +Perl_av_fill(pTHX_ AV *av, SSize_t fill) { - dVAR; MAGIC *mg; PERL_ARGS_ASSERT_AV_FILL; @@ -793,7 +855,7 @@ Perl_av_fill(pTHX_ AV *av, I32 fill) return; } if (fill <= AvMAX(av)) { - I32 key = AvFILLp(av); + SSize_t key = AvFILLp(av); SV** const ary = AvARRAY(av); if (AvREAL(av)) { @@ -818,18 +880,19 @@ Perl_av_fill(pTHX_ AV *av, I32 fill) /* =for apidoc av_delete -Deletes the element indexed by C from the array, makes the element mortal, -and returns it. If C equals C, the element is freed and null -is returned. Perl equivalent: C for the -non-C version and a void-context C for the -C version. +Deletes the element indexed by C from the array, makes the element +mortal, and returns it. If C equals C, the element is +freed and NULL is returned. NULL is also returned if C is out of +range. + +Perl equivalent: S> (with the +C in void context if C is present). =cut */ SV * -Perl_av_delete(pTHX_ AV *av, I32 key, I32 flags) +Perl_av_delete(pTHX_ AV *av, SSize_t key, I32 flags) { - dVAR; SV *sv; PERL_ARGS_ASSERT_AV_DELETE; @@ -872,23 +935,23 @@ Perl_av_delete(pTHX_ AV *av, I32 key, I32 flags) if (!AvREAL(av) && AvREIFY(av)) av_reify(av); sv = AvARRAY(av)[key]; + AvARRAY(av)[key] = NULL; if (key == AvFILLp(av)) { - AvARRAY(av)[key] = NULL; do { AvFILLp(av)--; } while (--key >= 0 && !AvARRAY(av)[key]); } - else - AvARRAY(av)[key] = NULL; if (SvSMAGICAL(av)) mg_set(MUTABLE_SV(av)); } - if (flags & G_DISCARD) { - SvREFCNT_dec(sv); - sv = NULL; + if(sv != NULL) { + if (flags & G_DISCARD) { + SvREFCNT_dec_NN(sv); + return NULL; + } + else if (AvREAL(av)) + sv_2mortal(sv); } - else if (AvREAL(av)) - sv = sv_2mortal(sv); return sv; } @@ -898,16 +961,15 @@ 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 -NULL. +C. Perl equivalent: C. =cut */ bool -Perl_av_exists(pTHX_ AV *av, I32 key) +Perl_av_exists(pTHX_ AV *av, SSize_t key) { - dVAR; PERL_ARGS_ASSERT_AV_EXISTS; assert(SvTYPE(av) == SVt_PVAV); @@ -961,7 +1023,6 @@ Perl_av_exists(pTHX_ AV *av, I32 key) static MAGIC * S_get_aux_mg(pTHX_ AV *av) { - dVAR; MAGIC *mg; PERL_ARGS_ASSERT_GET_AUX_MG; @@ -996,25 +1057,19 @@ Perl_av_iter_p(pTHX_ AV *av) { PERL_ARGS_ASSERT_AV_ITER_P; assert(SvTYPE(av) == SVt_PVAV); -#if IVSIZE == I32SIZE - return (IV *)&(mg->mg_len); -#else - if (!mg->mg_ptr) { - IV *temp; - mg->mg_len = IVSIZE; - Newxz(temp, 1, IV); - mg->mg_ptr = (char *) temp; + if (sizeof(IV) == sizeof(SSize_t)) { + return (IV *)&(mg->mg_len); + } else { + if (!mg->mg_ptr) { + IV *temp; + mg->mg_len = IVSIZE; + Newxz(temp, 1, IV); + mg->mg_ptr = (char *) temp; + } + return (IV *)mg->mg_ptr; } - return (IV *)mg->mg_ptr; -#endif } /* - * Local variables: - * c-indentation-style: bsd - * c-basic-offset: 4 - * indent-tabs-mode: nil - * End: - * * ex: set ts=8 sts=4 sw=4 et: */