X-Git-Url: https://perl5.git.perl.org/perl5.git/blobdiff_plain/2c1c1caaefc9a6157e7d86987f121276e2115620..713cef20be507239588df9cdc5f99ce04b7e0b40:/util.c diff --git a/util.c b/util.c index b4ed7f2..c5f69ae 100644 --- a/util.c +++ b/util.c @@ -341,16 +341,15 @@ Perl_delimcpy(pTHX_ register char *to, register const char *toend, register cons { register I32 tolen; PERL_UNUSED_CONTEXT; + for (tolen = 0; from < fromend; from++, tolen++) { if (*from == '\\') { - if (from[1] == delim) - from++; - else { + if (from[1] != delim) { if (to < toend) *to++ = *from; tolen++; - from++; } + from++; } else if (*from == delim) break; @@ -455,8 +454,6 @@ Perl_rninstr(pTHX_ register const char *big, const char *bigend, const char *lit return NULL; } -#define FBM_TABLE_OFFSET 2 /* Number of bytes between EOS and table*/ - /* As a space optimization, we do not compile tables for strings of length 0 and 1, and for strings of length 2 unless FBMcf_TAIL. These are special-cased in fbm_instr(). @@ -491,19 +488,21 @@ Perl_fbm_compile(pTHX_ SV *sv, U32 flags) mg->mg_len++; } s = (U8*)SvPV_force_mutable(sv, len); - SvUPGRADE(sv, SVt_PVBM); if (len == 0) /* TAIL might be on a zero-length string. */ return; + SvUPGRADE(sv, SVt_PVGV); + SvIOK_off(sv); if (len > 2) { const unsigned char *sb; const U8 mlen = (len>255) ? 255 : (U8)len; register U8 *table; - Sv_Grow(sv, len + 256 + FBM_TABLE_OFFSET); - table = (unsigned char*)(SvPVX_mutable(sv) + len + FBM_TABLE_OFFSET); - s = table - 1 - FBM_TABLE_OFFSET; /* last char */ + Sv_Grow(sv, len + 256 + PERL_FBM_TABLE_OFFSET); + table + = (unsigned char*)(SvPVX_mutable(sv) + len + PERL_FBM_TABLE_OFFSET); + s = table - 1 - PERL_FBM_TABLE_OFFSET; /* last char */ memset((void*)table, mlen, 256); - table[-1] = (U8)flags; + table[PERL_FBM_FLAGS_OFFSET_FROM_TABLE] = (U8)flags; i = 0; sb = s - mlen + 1; /* first char (maybe) */ while (s >= sb) { @@ -511,6 +510,8 @@ Perl_fbm_compile(pTHX_ SV *sv, U32 flags) table[*s] = (U8)i; s--, i++; } + } else { + Sv_Grow(sv, len + PERL_FBM_TABLE_OFFSET); } sv_magic(sv, NULL, PERL_MAGIC_bm, NULL, 0); /* deep magic */ SvVALID_on(sv); @@ -523,7 +524,7 @@ Perl_fbm_compile(pTHX_ SV *sv, U32 flags) } } BmRARE(sv) = s[rarest]; - BmPREVIOUS(sv) = (U16)rarest; + BmPREVIOUS_set(sv, rarest); BmUSEFUL(sv) = 100; /* Initial value */ if (flags & FBMcf_TAIL) SvTAIL_on(sv); @@ -664,7 +665,7 @@ Perl_fbm_instr(pTHX_ unsigned char *big, register unsigned char *bigend, SV *lit } return NULL; } - if (SvTYPE(littlestr) != SVt_PVBM || !SvVALID(littlestr)) { + if (!SvVALID(littlestr)) { char * const b = ninstr((char*)big,(char*)bigend, (char*)little, (char*)little + littlelen); @@ -681,12 +682,15 @@ Perl_fbm_instr(pTHX_ unsigned char *big, register unsigned char *bigend, SV *lit return b; } - { /* Do actual FBM. */ - register const unsigned char * const table = little + littlelen + FBM_TABLE_OFFSET; + /* Do actual FBM. */ + if (littlelen > (STRLEN)(bigend - big)) + return NULL; + + { + register const unsigned char * const table + = little + littlelen + PERL_FBM_TABLE_OFFSET; register const unsigned char *oldlittle; - if (littlelen > (STRLEN)(bigend - big)) - return NULL; --littlelen; /* Last char found by table lookup */ s = big + littlelen; @@ -719,7 +723,8 @@ Perl_fbm_instr(pTHX_ unsigned char *big, register unsigned char *bigend, SV *lit } } check_end: - if ( s == bigend && (table[-1] & FBMcf_TAIL) + if ( s == bigend + && (table[PERL_FBM_FLAGS_OFFSET_FROM_TABLE] & FBMcf_TAIL) && memEQ((char *)(bigend - littlelen), (char *)(oldlittle - littlelen), littlelen) ) return (char*)bigend - littlelen; @@ -755,12 +760,15 @@ Perl_screaminstr(pTHX_ SV *bigstr, SV *littlestr, I32 start_shift, I32 end_shift register const unsigned char *littleend; I32 found = 0; + assert(SvTYPE(littlestr) == SVt_PVGV); + assert(SvVALID(littlestr)); + if (*old_posp == -1 ? (pos = PL_screamfirst[BmRARE(littlestr)]) < 0 : (((pos = *old_posp), pos += PL_screamnext[pos]) == 0)) { cant_find: if ( BmRARE(littlestr) == '\n' - && BmPREVIOUS(littlestr) == SvCUR(littlestr) - 1) { + && BmPREVIOUS(littlestr) == (U8)SvCUR(littlestr) - 1) { little = (const unsigned char *)(SvPVX_const(littlestr)); littleend = little + SvCUR(littlestr); first = *little++; @@ -883,8 +891,8 @@ Perl_savepv(pTHX_ const char *pv) else { char *newaddr; const STRLEN pvlen = strlen(pv)+1; - Newx(newaddr,pvlen,char); - return memcpy(newaddr,pv,pvlen); + Newx(newaddr, pvlen, char); + return (char*)memcpy(newaddr, pv, pvlen); } } @@ -895,8 +903,8 @@ Perl_savepv(pTHX_ const char *pv) Perl's version of what C would be if it existed. Returns a pointer to a newly allocated string which is a duplicate of the first -C bytes from C. The memory allocated for the new string can be -freed with the C function. +C bytes from C, plus a trailing NUL byte. The memory allocated for +the new string can be freed with the C function. =cut */ @@ -940,7 +948,7 @@ Perl_savesharedpv(pTHX_ const char *pv) if (!newaddr) { return write_no_mem(); } - return memcpy(newaddr,pv,pvlen); + return (char*)memcpy(newaddr, pv, pvlen); } /* @@ -1456,7 +1464,7 @@ void Perl_vwarner(pTHX_ U32 err, const char* pat, va_list* args) { dVAR; - if (ckDEAD(err)) { + if (PL_warnhook == PERL_WARNHOOK_FATAL || ckDEAD(err)) { SV * const msv = vmess(pat, args); STRLEN msglen; const char * const message = SvPV_const(msv, msglen); @@ -1531,7 +1539,21 @@ Perl_ckwarn_d(pTHX_ U32 w) ; } +/* Set buffer=NULL to get a new one. */ +STRLEN * +Perl_new_warnings_bitfield(pTHX_ STRLEN *buffer, const char *const bits, + STRLEN size) { + const MEM_SIZE len_wanted = sizeof(STRLEN) + size; + PERL_UNUSED_CONTEXT; + buffer = (STRLEN*) + (specialWARN(buffer) ? + PerlMemShared_malloc(len_wanted) : + PerlMemShared_realloc(buffer, len_wanted)); + buffer[0] = size; + Copy(bits, (buffer + 1), size, char); + return buffer; +} /* since we've already done strlen() for both nam and val * we can use that info to make things faster than @@ -1558,47 +1580,49 @@ Perl_my_setenv(pTHX_ const char *nam, const char *val) #ifndef PERL_USE_SAFE_PUTENV if (!PL_use_safe_putenv) { /* most putenv()s leak, so we manipulate environ directly */ - register I32 i=setenv_getix(nam); /* where does it go? */ + register I32 i=setenv_getix(nam); /* where does it go? */ int nlen, vlen; - if (environ == PL_origenviron) { /* need we copy environment? */ - I32 j; - I32 max; - char **tmpenv; - - for (max = i; environ[max]; max++) ; - tmpenv = (char**)safesysmalloc((max+2) * sizeof(char*)); - for (j=0; j= 0; i++) ; - return i ? 0 : -1; + while (PerlLIO_unlink(f) >= 0) + retries++; + return retries ? 0 : -1; } #endif @@ -1883,8 +1908,8 @@ Perl_my_ntohl(pTHX_ long l) type value; \ char c[sizeof(type)]; \ } u; \ - register I32 i; \ - register I32 s = 0; \ + register U32 i; \ + register U32 s = 0; \ for (i = 0; i < sizeof(u.c); i++, s += 8) { \ u.c[i] = (n >> s) & 0xFF; \ } \ @@ -1899,8 +1924,8 @@ Perl_my_ntohl(pTHX_ long l) type value; \ char c[sizeof(type)]; \ } u; \ - register I32 i; \ - register I32 s = 0; \ + register U32 i; \ + register U32 s = 0; \ u.value = n; \ n = 0; \ for (i = 0; i < sizeof(u.c); i++, s += 8) { \ @@ -1921,8 +1946,8 @@ Perl_my_ntohl(pTHX_ long l) type value; \ char c[sizeof(type)]; \ } u; \ - register I32 i; \ - register I32 s = 8*(sizeof(u.c)-1); \ + register U32 i; \ + register U32 s = 8*(sizeof(u.c)-1); \ for (i = 0; i < sizeof(u.c); i++, s -= 8) { \ u.c[i] = (n >> s) & 0xFF; \ } \ @@ -1937,8 +1962,8 @@ Perl_my_ntohl(pTHX_ long l) type value; \ char c[sizeof(type)]; \ } u; \ - register I32 i; \ - register I32 s = 8*(sizeof(u.c)-1); \ + register U32 i; \ + register U32 s = 8*(sizeof(u.c)-1); \ u.value = n; \ n = 0; \ for (i = 0; i < sizeof(u.c); i++, s -= 8) { \ @@ -2213,7 +2238,8 @@ Perl_my_popen_list(pTHX_ char *mode, int n, SV **args) /* If we managed to get status pipe check for exec fail */ if (did_pipes && pid > 0) { int errkid; - int n = 0, n1; + unsigned n = 0; + SSize_t n1; while (n < sizeof(int)) { n1 = PerlLIO_read(pp[0], @@ -2330,6 +2356,14 @@ Perl_my_popen(pTHX_ const char *cmd, const char *mode) PerlProc__exit(1); } #endif /* defined OS2 */ + +#ifdef PERLIO_USING_CRLF + /* Since we circumvent IO layers when we manipulate low-level + filedescriptors directly, need to manually switch to the + default, binary, low-level mode; see PerlIOBuf_open(). */ + PerlLIO_setmode((*mode == 'r'), O_BINARY); +#endif + if ((tmpgv = gv_fetchpvs("$", GV_ADD|GV_NOTQUAL, SVt_PV))) { SvREADONLY_off(GvSV(tmpgv)); sv_setiv(GvSV(tmpgv), PerlProc_getpid()); @@ -2365,7 +2399,8 @@ Perl_my_popen(pTHX_ const char *cmd, const char *mode) PL_forkprocess = pid; if (did_pipes && pid > 0) { int errkid; - int n = 0, n1; + unsigned n = 0; + SSize_t n1; while (n < sizeof(int)) { n1 = PerlLIO_read(pp[0], @@ -2397,7 +2432,7 @@ Perl_my_popen(pTHX_ const char *cmd, const char *mode) #if defined(atarist) || defined(EPOC) FILE *popen(); PerlIO * -Perl_my_popen(pTHX_ char *cmd, char *mode) +Perl_my_popen((pTHX_ const char *cmd, const char *mode) { PERL_FLUSHALL_FOR_CHILD; /* Call system's popen() to get a FILE *, then import it. @@ -2410,7 +2445,7 @@ Perl_my_popen(pTHX_ char *cmd, char *mode) #if defined(DJGPP) FILE *djgpp_popen(); PerlIO * -Perl_my_popen(pTHX_ char *cmd, char *mode) +Perl_my_popen((pTHX_ const char *cmd, const char *mode) { PERL_FLUSHALL_FOR_CHILD; /* Call system's popen() to get a FILE *, then import it. @@ -3006,7 +3041,7 @@ Perl_find_script(pTHX_ const char *scriptname, bool dosearch, if ((strlen(tmpbuf) + strlen(scriptname) + MAX_EXT_LEN) >= sizeof tmpbuf) continue; /* don't search dir with too-long name */ - strcat(tmpbuf, scriptname); + my_strlcat(tmpbuf, scriptname, sizeof(tmpbuf)); #else /* !VMS */ #ifdef DOSISH @@ -3038,11 +3073,11 @@ Perl_find_script(pTHX_ const char *scriptname, bool dosearch, len = strlen(scriptname); if (len+MAX_EXT_LEN+1 >= sizeof(tmpbuf)) break; - /* FIXME? Convert to memcpy */ - cur = strcpy(tmpbuf, scriptname); + my_strlcpy(tmpbuf, scriptname, sizeof(tmpbuf)); + cur = tmpbuf; } } while (extidx >= 0 && ext[extidx] /* try an extension? */ - && strcpy(tmpbuf+len, ext[extidx++])); + && my_strlcpy(tmpbuf+len, ext[extidx++], sizeof(tmpbuf) - len)); #endif } #endif @@ -3102,9 +3137,7 @@ Perl_find_script(pTHX_ const char *scriptname, bool dosearch, if (len == 2 && tmpbuf[0] == '.') seen_dot = 1; #endif - /* FIXME? Convert to memcpy by storing previous strlen(scriptname) - */ - (void)strcpy(tmpbuf + len, scriptname); + (void)my_strlcpy(tmpbuf + len, scriptname, sizeof(tmpbuf) - len); #endif /* !VMS */ #ifdef SEARCH_EXTS @@ -3121,7 +3154,7 @@ Perl_find_script(pTHX_ const char *scriptname, bool dosearch, #ifdef SEARCH_EXTS } while ( retval < 0 /* not there */ && extidx>=0 && ext[extidx] /* try an extension? */ - && strcpy(tmpbuf+len, ext[extidx++]) + && my_strlcpy(tmpbuf+len, ext[extidx++], sizeof(tmpbuf) - len) ); #endif if (retval < 0) @@ -3416,20 +3449,12 @@ Perl_my_fflush_all(pTHX) void Perl_report_evil_fh(pTHX_ const GV *gv, const IO *io, I32 op) { - const char * const func = - op == OP_READLINE ? "readline" : /* "" not nice */ - op == OP_LEAVEWRITE ? "write" : /* "write exit" not nice */ - op < 0 ? "" : /* handle phoney cases */ - PL_op_desc[op]; - const char * const pars = OP_IS_FILETEST(op) ? "" : "()"; - const char * const type = OP_IS_SOCKET(op) - || (gv && io && IoTYPE(io) == IoTYPE_SOCKET) - ? "socket" : "filehandle"; const char * const name = gv && isGV(gv) ? GvENAME(gv) : NULL; if (op == OP_phoney_OUTPUT_ONLY || op == OP_phoney_INPUT_ONLY) { if (ckWARN(WARN_IO)) { - const char * const direction = (op == OP_phoney_INPUT_ONLY) ? "in" : "out"; + const char * const direction = + (const char *)((op == OP_phoney_INPUT_ONLY) ? "in" : "out"); if (name && *name) Perl_warner(aTHX_ packWARN(WARN_IO), "Filehandle %s opened only for %sput", @@ -3453,6 +3478,19 @@ Perl_report_evil_fh(pTHX_ const GV *gv, const IO *io, I32 op) } if (ckWARN(warn_type)) { + const char * const pars = + (const char *)(OP_IS_FILETEST(op) ? "" : "()"); + const char * const func = + (const char *) + (op == OP_READLINE ? "readline" : /* "" not nice */ + op == OP_LEAVEWRITE ? "write" : /* "write exit" not nice */ + op < 0 ? "" : /* handle phoney cases */ + PL_op_desc[op]); + const char * const type = + (const char *) + (OP_IS_SOCKET(op) || + (gv && io && IoTYPE(io) == IoTYPE_SOCKET) ? + "socket" : "filehandle"); if (name && *name) { Perl_warner(aTHX_ packWARN(warn_type), "%s%s on %s %s %s", func, pars, vile, type, name); @@ -3808,7 +3846,7 @@ Perl_my_strftime(pTHX_ const char *fmt, int sec, int min, int hour, int mday, in else { /* Possibly buf overflowed - try again with a bigger buf */ const int fmtlen = strlen(fmt); - const int bufsize = fmtlen + buflen; + int bufsize = fmtlen + buflen; Newx(buf, bufsize, char); while (buf) { @@ -3821,7 +3859,8 @@ Perl_my_strftime(pTHX_ const char *fmt, int sec, int min, int hour, int mday, in buf = NULL; break; } - Renew(buf, bufsize*2, char); + bufsize *= 2; + Renew(buf, bufsize, char); } return buf; } @@ -4131,7 +4170,7 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) /* Append revision */ av_push(av, newSViv(rev)); - if ( *pos == '.' && isDIGIT(pos[1]) ) + if ( *pos == '.' ) s = ++pos; else if ( *pos == '_' && isDIGIT(pos[1]) ) s = ++pos; @@ -4172,6 +4211,11 @@ Perl_scan_version(pTHX_ const char *s, SV *rv, bool qv) if ( av_len(av) == -1 ) /* oops, someone forgot to pass a value */ av_push(av, newSViv(0)); + /* fix RT#19517 - special case 'undef' as string */ + if ( *s == 'u' && strEQ(s,"undef") ) { + s += 5; + } + /* And finally, store the AV in the hash */ hv_store((HV *)hv, "version", 7, newRV_noinc((SV *)av), 0); return s; @@ -4236,7 +4280,7 @@ Perl_new_version(pTHX_ SV *ver) } #ifdef SvVOK { - const MAGIC* const mg = SvVOK(ver); + const MAGIC* const mg = SvVSTRING_mg(ver); if ( mg ) { /* already a v-string */ const STRLEN len = mg->mg_len; char * const version = savepvn( (const char*)mg->mg_ptr, len); @@ -4277,11 +4321,18 @@ Perl_upg_version(pTHX_ SV *ver) if ( SvNOK(ver) ) /* may get too much accuracy */ { char tbuf[64]; - const STRLEN len = my_sprintf(tbuf,"%.9"NVgf, SvNVX(ver)); +#ifdef USE_LOCALE_NUMERIC + char *loc = setlocale(LC_NUMERIC, "C"); +#endif + STRLEN len = my_snprintf(tbuf, sizeof(tbuf), "%.9"NVff, SvNVX(ver)); +#ifdef USE_LOCALE_NUMERIC + setlocale(LC_NUMERIC, loc); +#endif + while (tbuf[len-1] == '0' && len > 0) len--; version = savepvn(tbuf, len); } #ifdef SvVOK - else if ( (mg = SvVOK(ver)) ) { /* already a v-string */ + else if ( (mg = SvVSTRING_mg(ver)) ) { /* already a v-string */ version = savepvn( (const char*)mg->mg_ptr,mg->mg_len ); qv = 1; } @@ -4290,12 +4341,13 @@ Perl_upg_version(pTHX_ SV *ver) { version = savepv(SvPV_nolen(ver)); } + s = scan_version(version, ver, qv); if ( *s != '\0' ) - if(ckWARN(WARN_MISC)) + if(ckWARN(WARN_MISC)) Perl_warner(aTHX_ packWARN(WARN_MISC), - "Version string '%s' contains invalid data; " - "ignoring: '%s'", version, s); + "Version string '%s' contains invalid data; " + "ignoring: '%s'", version, s); Safefree(version); return ver; } @@ -4888,7 +4940,8 @@ Perl_parse_unicode_opts(pTHX_ const char **popt) if (*p) { if (isDIGIT(*p)) { opt = (U32) atoi(p); - while (isDIGIT(*p)) p++; + while (isDIGIT(*p)) + p++; if (*p && *p != '\n' && *p != '\r') Perl_croak(aTHX_ "Unknown Unicode option letter '%c'", *p); } @@ -4913,6 +4966,8 @@ Perl_parse_unicode_opts(pTHX_ const char **popt) opt |= PERL_UNICODE_LOCALE_FLAG; break; case PERL_UNICODE_ARGV: opt |= PERL_UNICODE_ARGV_FLAG; break; + case PERL_UNICODE_UTF8CACHEASSERT: + opt |= PERL_UNICODE_UTF8CACHEASSERT_FLAG; break; default: if (*p != '\n' && *p != '\r') Perl_croak(aTHX_ @@ -5023,7 +5078,8 @@ Perl_get_hash_seed(pTHX) UV myseed = 0; if (s) - while (isSPACE(*s)) s++; + while (isSPACE(*s)) + s++; if (s && isDIGIT(*s)) myseed = (UV)Atoul(s); else @@ -5147,20 +5203,78 @@ Perl_free_global_struct(pTHX_ struct perl_vars *plvarsp) #ifdef PERL_MEM_LOG +/* + * PERL_MEM_LOG: the Perl_mem_log_..() will be compiled. + * + * PERL_MEM_LOG_ENV: if defined, during run time the environment + * variable PERL_MEM_LOG will be consulted, and if the integer value + * of that is true, the logging will happen. (The default is to + * always log if the PERL_MEM_LOG define was in effect.) + */ + +/* + * PERL_MEM_LOG_SPRINTF_BUF_SIZE: size of a (stack-allocated) buffer + * the Perl_mem_log_...() will use (either via sprintf or snprintf). + */ #define PERL_MEM_LOG_SPRINTF_BUF_SIZE 128 +/* + * PERL_MEM_LOG_FD: the file descriptor the Perl_mem_log_...() will + * log to. You can also define in compile time PERL_MEM_LOG_ENV_FD, + * in which case the environment variable PERL_MEM_LOG_FD will be + * consulted for the file descriptor number to use. + */ +#ifndef PERL_MEM_LOG_FD +# define PERL_MEM_LOG_FD 2 /* If STDERR is too boring for you. */ +#endif + Malloc_t Perl_mem_log_alloc(const UV n, const UV typesize, const char *typename, Malloc_t newalloc, const char *filename, const int linenumber, const char *funcname) { #ifdef PERL_MEM_LOG_STDERR - /* We can't use PerlIO for obvious reasons. */ - char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; - const STRLEN len = my_sprintf(buf, - "alloc: %s:%d:%s: %"IVdf" %"UVuf - " %s = %"IVdf": %"UVxf"\n", - filename, linenumber, funcname, n, typesize, - typename, n * typesize, PTR2UV(newalloc)); - PerlLIO_write(2, buf, len); +# if defined(PERL_MEM_LOG_ENV) || defined(PERL_MEM_LOG_ENV_FD) + char *s; +# endif +# ifdef PERL_MEM_LOG_ENV + s = getenv("PERL_MEM_LOG"); + if (s ? atoi(s) : 0) +# endif + { + /* We can't use SVs or PerlIO for obvious reasons, + * so we'll use stdio and low-level IO instead. */ + char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; +# ifdef PERL_MEM_LOG_TIMESTAMP + struct timeval tv; +# ifdef HAS_GETTIMEOFDAY + gettimeofday(&tv, 0); +# endif + /* If there are other OS specific ways of hires time than + * gettimeofday() (see ext/Time/HiRes), the easiest way is + * probably that they would be used to fill in the struct + * timeval. */ +# endif + { + const STRLEN len = + my_snprintf(buf, + sizeof(buf), +# ifdef PERL_MEM_LOG_TIMESTAMP + "%10d.%06d: " +# endif + "alloc: %s:%d:%s: %"IVdf" %"UVuf + " %s = %"IVdf": %"UVxf"\n", +# ifdef PERL_MEM_LOG_TIMESTAMP + (int)tv.tv_sec, (int)tv.tv_usec, +# endif + filename, linenumber, funcname, n, typesize, + typename, n * typesize, PTR2UV(newalloc)); +# ifdef PERL_MEM_LOG_ENV_FD + s = PerlEnv_getenv("PERL_MEM_LOG_FD"); + PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len); +# else + PerlLIO_write(PERL_MEM_LOG_FD, buf, len); +#endif + } + } #endif return newalloc; } @@ -5169,14 +5283,44 @@ Malloc_t Perl_mem_log_realloc(const UV n, const UV typesize, const char *typename, Malloc_t oldalloc, Malloc_t newalloc, const char *filename, const int linenumber, const char *funcname) { #ifdef PERL_MEM_LOG_STDERR - /* We can't use PerlIO for obvious reasons. */ - char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; - const STRLEN len = my_sprintf(buf, "realloc: %s:%d:%s: %"IVdf" %"UVuf - " %s = %"IVdf": %"UVxf" -> %"UVxf"\n", - filename, linenumber, funcname, n, typesize, - typename, n * typesize, PTR2UV(oldalloc), - PTR2UV(newalloc)); - PerlLIO_write(2, buf, len); +# if defined(PERL_MEM_LOG_ENV) || defined(PERL_MEM_LOG_ENV_FD) + char *s; +# endif +# ifdef PERL_MEM_LOG_ENV + s = PerlEnv_getenv("PERL_MEM_LOG"); + if (s ? atoi(s) : 0) +# endif + { + /* We can't use SVs or PerlIO for obvious reasons, + * so we'll use stdio and low-level IO instead. */ + char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; +# ifdef PERL_MEM_LOG_TIMESTAMP + struct timeval tv; + gettimeofday(&tv, 0); +# endif + { + const STRLEN len = + my_snprintf(buf, + sizeof(buf), +# ifdef PERL_MEM_LOG_TIMESTAMP + "%10d.%06d: " +# endif + "realloc: %s:%d:%s: %"IVdf" %"UVuf + " %s = %"IVdf": %"UVxf" -> %"UVxf"\n", +# ifdef PERL_MEM_LOG_TIMESTAMP + (int)tv.tv_sec, (int)tv.tv_usec, +# endif + filename, linenumber, funcname, n, typesize, + typename, n * typesize, PTR2UV(oldalloc), + PTR2UV(newalloc)); +# ifdef PERL_MEM_LOG_ENV_FD + s = PerlEnv_getenv("PERL_MEM_LOG_FD"); + PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len); +# else + PerlLIO_write(PERL_MEM_LOG_FD, buf, len); +# endif + } + } #endif return newalloc; } @@ -5185,12 +5329,42 @@ Malloc_t Perl_mem_log_free(Malloc_t oldalloc, const char *filename, const int linenumber, const char *funcname) { #ifdef PERL_MEM_LOG_STDERR - /* We can't use PerlIO for obvious reasons. */ - char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; - const STRLEN len = my_sprintf(buf, "free: %s:%d:%s: %"UVxf"\n", - filename, linenumber, funcname, - PTR2UV(oldalloc)); - PerlLIO_write(2, buf, len); +# if defined(PERL_MEM_LOG_ENV) || defined(PERL_MEM_LOG_ENV_FD) + char *s; +# endif +# ifdef PERL_MEM_LOG_ENV + s = PerlEnv_getenv("PERL_MEM_LOG"); + if (s ? atoi(s) : 0) +# endif + { + /* We can't use SVs or PerlIO for obvious reasons, + * so we'll use stdio and low-level IO instead. */ + char buf[PERL_MEM_LOG_SPRINTF_BUF_SIZE]; +# ifdef PERL_MEM_LOG_TIMESTAMP + struct timeval tv; + gettimeofday(&tv, 0); +# endif + { + const STRLEN len = + my_snprintf(buf, + sizeof(buf), +# ifdef PERL_MEM_LOG_TIMESTAMP + "%10d.%06d: " +# endif + "free: %s:%d:%s: %"UVxf"\n", +# ifdef PERL_MEM_LOG_TIMESTAMP + (int)tv.tv_sec, (int)tv.tv_usec, +# endif + filename, linenumber, funcname, + PTR2UV(oldalloc)); +# ifdef PERL_MEM_LOG_ENV_FD + s = PerlEnv_getenv("PERL_MEM_LOG_FD"); + PerlLIO_write(s ? atoi(s) : PERL_MEM_LOG_FD, buf, len); +# else + PerlLIO_write(PERL_MEM_LOG_FD, buf, len); +# endif + } + } #endif return oldalloc; } @@ -5218,6 +5392,74 @@ Perl_my_sprintf(char *buffer, const char* pat, ...) } #endif +/* +=for apidoc my_snprintf + +The C library C functionality, if available and +standards-compliant (uses C, actually). However, if the +C is not available, will unfortunately use the unsafe +C which can overrun the buffer (there is an overrun check, +but that may be too late). Consider using C instead, or +getting C. + +=cut +*/ +int +Perl_my_snprintf(char *buffer, const Size_t len, const char *format, ...) +{ + dTHX; + int retval; + va_list ap; + va_start(ap, format); +#ifdef HAS_VSNPRINTF + retval = vsnprintf(buffer, len, format, ap); +#else + retval = vsprintf(buffer, format, ap); +#endif + va_end(ap); + /* vsnprintf() shows failure with >= len, vsprintf() with < 0 */ + if (retval < 0 || (len > 0 && (Size_t)retval >= len)) + Perl_croak(aTHX_ "panic: my_snprintf buffer overflow"); + return retval; +} + +/* +=for apidoc my_vsnprintf + +The C library C if available and standards-compliant. +However, if if the C is not available, will unfortunately +use the unsafe C which can overrun the buffer (there is an +overrun check, but that may be too late). Consider using +C instead, or getting C. + +=cut +*/ +int +Perl_my_vsnprintf(char *buffer, const Size_t len, const char *format, va_list ap) +{ + dTHX; + int retval; +#ifdef NEED_VA_COPY + va_list apc; + Perl_va_copy(ap, apc); +# ifdef HAS_VSNPRINTF + retval = vsnprintf(buffer, len, format, apc); +# else + retval = vsprintf(buffer, format, apc); +# endif +#else +# ifdef HAS_VSNPRINTF + retval = vsnprintf(buffer, len, format, ap); +# else + retval = vsprintf(buffer, format, ap); +# endif +#endif /* #ifdef NEED_VA_COPY */ + /* vsnprintf() shows failure with >= len, vsprintf() with < 0 */ + if (retval < 0 || (len > 0 && (Size_t)retval >= len)) + Perl_croak(aTHX_ "panic: my_vsnprintf buffer overflow"); + return retval; +} + void Perl_my_clearenv(pTHX) { @@ -5247,17 +5489,17 @@ Perl_my_clearenv(pTHX) (void)clearenv(); # elif defined(HAS_UNSETENV) int bsiz = 80; /* Most envvar names will be shorter than this. */ - char *buf = (char*)safesysmalloc(bsiz * sizeof(char)); + int bufsiz = bsiz * sizeof(char); /* sizeof(char) paranoid? */ + char *buf = (char*)safesysmalloc(bufsiz); while (*environ != NULL) { char *e = strchr(*environ, '='); - int l = e ? e - *environ : strlen(*environ); + int l = e ? e - *environ : (int)strlen(*environ); if (bsiz < l + 1) { (void)safesysfree(buf); - bsiz = l + 1; - buf = (char*)safesysmalloc(bsiz * sizeof(char)); + bsiz = l + 1; /* + 1 for the \0. */ + buf = (char*)safesysmalloc(bufsiz); } - strncpy(buf, *environ, l); - *(buf + l) = '\0'; + my_strlcpy(buf, *environ, l + 1); (void)unsetenv(buf); } (void)safesysfree(buf); @@ -5313,6 +5555,75 @@ Perl_my_cxt_init(pTHX_ int *index, size_t size) } #endif +#ifndef HAS_STRLCAT +Size_t +Perl_my_strlcat(char *dst, const char *src, Size_t size) +{ + Size_t used, length, copy; + + used = strlen(dst); + length = strlen(src); + if (size > 0 && used < size - 1) { + copy = (length >= size - used) ? size - used - 1 : length; + memcpy(dst + used, src, copy); + dst[used + copy] = '\0'; + } + return used + length; +} +#endif + +#ifndef HAS_STRLCPY +Size_t +Perl_my_strlcpy(char *dst, const char *src, Size_t size) +{ + Size_t length, copy; + + length = strlen(src); + if (size > 0) { + copy = (length >= size) ? size - 1 : length; + memcpy(dst, src, copy); + dst[copy] = '\0'; + } + return length; +} +#endif + +void +Perl_get_db_sub(pTHX_ SV **svp, CV *cv) +{ + dVAR; + SV * const dbsv = GvSVn(PL_DBsub); + /* We do not care about using sv to call CV; + * it's for informational purposes only. + */ + + save_item(dbsv); + if (!PERLDB_SUB_NN) { + GV * const gv = CvGV(cv); + + if ( svp && ((CvFLAGS(cv) & (CVf_ANON | CVf_CLONED)) + || strEQ(GvNAME(gv), "END") + || ((GvCV(gv) != cv) && /* Could be imported, and old sub redefined. */ + !( (SvTYPE(*svp) == SVt_PVGV) && (GvCV((GV*)*svp) == cv) )))) { + /* Use GV from the stack as a fallback. */ + /* GV is potentially non-unique, or contain different CV. */ + SV * const tmp = newRV((SV*)cv); + sv_setsv(dbsv, tmp); + SvREFCNT_dec(tmp); + } + else { + gv_efullname3(dbsv, gv, NULL); + } + } + else { + const int type = SvTYPE(dbsv); + if (type < SVt_PVIV && type != SVt_IV) + sv_upgrade(dbsv, SVt_PVIV); + (void)SvIOK_on(dbsv); + SvIV_set(dbsv, PTR2IV(cv)); /* Do it the quickest way */ + } +} + /* * Local variables: * c-indentation-style: bsd