summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJarkko Hietaniemi <jhi@iki.fi>2003-06-20 07:31:11 +0000
committerJarkko Hietaniemi <jhi@iki.fi>2003-06-20 07:31:11 +0000
commit22f7c9c9717fe07b508ba0e9958ef0592cdbbeef (patch)
tree242e338c2ed54d78f98bb01642efd8eda56268fa
parentdda12f46c06c4294f4f764c1854204b0608b68e4 (diff)
downloadperl-22f7c9c9717fe07b508ba0e9958ef0592cdbbeef.tar.gz
More Perl malloc debugging magic from Ilya. Seems to work in
Linux, Solaris, AIX. Had to do #ifdef OS2 for the <io.h> in malloc.c, found in AIX since there is no such header. In Tru64 miniperl fails an assert: "free()ed/realloc()ed-away memory was overwritten?" (In IRIX compiles but that doesn't prove much since in IRIX Perl's malloc is simply not used.) p4raw-id: //depot/perl@19831
-rw-r--r--MANIFEST1
-rw-r--r--dosish.h8
-rw-r--r--epoc/epocish.h2
-rw-r--r--malloc.c506
-rw-r--r--malloc_ctl.h54
-rw-r--r--os2/os2ish.h1
-rw-r--r--perl.c35
-rw-r--r--perl.h57
-rw-r--r--plan9/plan9ish.h2
-rw-r--r--sv.c4
-rw-r--r--unixish.h2
-rw-r--r--vms/vmsish.h2
12 files changed, 586 insertions, 88 deletions
diff --git a/MANIFEST b/MANIFEST
index f477a4d2f3..d084d31435 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -2085,6 +2085,7 @@ makedir.SH Precursor to makedir
Makefile.micro microperl Makefile
Makefile.SH A script that generates Makefile
malloc.c A version of malloc you might not want
+malloc_ctl.h A version of malloc you might not want
MANIFEST This list of files
mg.c Magic code
mg.h Magic header
diff --git a/dosish.h b/dosish.h
index 6828bafe06..e606bebc66 100644
--- a/dosish.h
+++ b/dosish.h
@@ -16,7 +16,7 @@
#ifdef DJGPP
# define BIT_BUCKET "nul"
# define OP_BINARY O_BINARY
-# define PERL_SYS_INIT(c,v) Perl_DJGPP_init(c,v)
+# define PERL_SYS_INIT(c,v) MALLOC_CHECK_TAINT2(*c,*v) Perl_DJGPP_init(c,v)
# define init_os_extras Perl_init_os_extras
# include <signal.h>
# define HAS_UTIME
@@ -29,15 +29,15 @@
# define PERL_FS_VER_FMT "%d_%d_%d"
#else /* DJGPP */
# ifdef WIN32
-# define PERL_SYS_INIT(c,v) Perl_win32_init(c,v)
+# define PERL_SYS_INIT(c,v) MALLOC_CHECK_TAINT2(*c,*v) Perl_win32_init(c,v)
# define PERL_SYS_TERM() Perl_win32_term()
# define BIT_BUCKET "nul"
# else
# ifdef NETWARE
-# define PERL_SYS_INIT(c,v) Perl_nw5_init(c,v)
+# define PERL_SYS_INIT(c,v) MALLOC_CHECK_TAINT2(*c,*v) Perl_nw5_init(c,v)
# define BIT_BUCKET "nwnul"
# else
-# define PERL_SYS_INIT(c,v)
+# define PERL_SYS_INIT(c,v) MALLOC_CHECK_TAINT2(*c,*v)
# define BIT_BUCKET "\\dev\\nul" /* "wanna be like, umm, Newlined, or somethin?" */
# endif /* NETWARE */
# endif
diff --git a/epoc/epocish.h b/epoc/epocish.h
index a7ef41871c..a971a8e6c7 100644
--- a/epoc/epocish.h
+++ b/epoc/epocish.h
@@ -108,7 +108,7 @@
/* epocemx setenv bug workaround */
#ifndef PERL_SYS_INIT
-# define PERL_SYS_INIT(c,v) putenv(".dummy=foo"); putenv(".dummy"); MALLOC_INIT
+# define PERL_SYS_INIT(c,v) MALLOC_CHECK_TAINT2(*c,*v) putenv(".dummy=foo"); putenv(".dummy"); MALLOC_INIT
#endif
#ifndef PERL_SYS_TERM
diff --git a/malloc.c b/malloc.c
index e648401617..d39927add0 100644
--- a/malloc.c
+++ b/malloc.c
@@ -27,9 +27,12 @@
options take a precise value, while the others are just boolean.
The boolean ones are listed first.
+ # Read configuration settings from malloc_cfg.h
+ HAVE_MALLOC_CFG_H undef
+
# Enable code for an emergency memory pool in $^M. See perlvar.pod
# for a description of $^M.
- PERL_EMERGENCY_SBRK (!PLAIN_MALLOC && PERL_CORE)
+ PERL_EMERGENCY_SBRK (!PLAIN_MALLOC && (PERL_CORE || !NO_MALLOC_DYNAMIC_CFG))
# Enable code for printing memory statistics.
DEBUGGING_MSTATS (!PLAIN_MALLOC && PERL_CORE)
@@ -78,6 +81,22 @@
# pessimization, error reporting optimization
RCHECK (DEBUGGING && !NO_RCHECK)
+ # Do not overwrite uninit areas with DEBUGGING. Speed
+ # optimization, error reporting pessimization
+ NO_MFILL undef
+
+ # Overwrite uninit areas with DEBUGGING. Speed
+ # pessimization, error reporting optimization
+ MALLOC_FILL (DEBUGGING && !NO_RCHECK && !NO_MFILL)
+
+ # Do not check overwritten uninit areas with DEBUGGING. Speed
+ # optimization, error reporting pessimization
+ NO_FILL_CHECK undef
+
+ # Check overwritten uninit areas with DEBUGGING. Speed
+ # pessimization, error reporting optimization
+ MALLOC_FILL_CHECK (DEBUGGING && !NO_RCHECK && !NO_FILL_CHECK)
+
# Failed allocations bigger than this size croak (if
# PERL_EMERGENCY_SBRK is enabled) without touching $^M. See
# perlvar.pod for a description of $^M.
@@ -98,6 +117,9 @@
# Round up sbrk()s to multiples of this percent of footprint.
MIN_SBRK_FRAC 3
+ # Round up sbrk()s to multiples of this multiple of 1/1000 of footprint.
+ MIN_SBRK_FRAC1000 (10 * MIN_SBRK_FRAC)
+
# Add this much memory to big powers of two to get the bucket size.
PERL_PAGESIZE 4096
@@ -114,6 +136,20 @@
# define this to disable 12-byte bucket (will increase memory footprint)
STRICT_ALIGNMENT undef
+ # Do not allow configuration of runtime options at runtime
+ NO_MALLOC_DYNAMIC_CFG undef
+
+ # Do not allow configuration of runtime options via $ENV{PERL_MALLOC_OPT}
+ NO_PERL_MALLOC_ENV undef
+
+ [The variable consists of ;-separated parts of the form CODE=VALUE
+ with 1-character codes F, M, f, A, P, G, d, a, c for runtime
+ configuration of FIRST_SBRK, MIN_SBRK, MIN_SBRK_FRAC1000,
+ SBRK_ALLOW_FAILURES, SBRK_FAILURE_PRICE, sbrk_goodness,
+ filldead, fillalive, fillcheck. The last 3 are for DEBUGGING
+ build, and allow switching the tests for free()ed memory read,
+ uninit memory reads, and free()ed memory write.]
+
This implementation assumes that calling PerlIO_printf() does not
result in any memory allocation calls (used during a panic).
@@ -138,12 +174,30 @@
# Unsigned integer type big enough to keep a pointer
UV unsigned long
+ # Signed integer of the same sizeof() as UV
+ IV long
+
# Type of pointer with 1-byte granularity
caddr_t char *
# Type returned by free()
Free_t void
+ # Conversion of pointer to integer
+ PTR2UV(ptr) ((UV)(ptr))
+
+ # Conversion of integer to pointer
+ INT2PTR(type, i) ((type)(i))
+
+ # printf()-%-Conversion of UV to pointer
+ UVuf "lu"
+
+ # printf()-%-Conversion of UV to hex pointer
+ UVxf "lx"
+
+ # Alignment to use
+ MEM_ALIGNBYTES 4
+
# Very fatal condition reporting function (cannot call any )
fatalcroak(arg) write(2,arg,strlen(arg)) + exit(2)
@@ -168,6 +222,10 @@
MUTEX_UNLOCK(l) void
*/
+#ifdef HAVE_MALLOC_CFG_H
+# include "malloc_cfg.h"
+#endif
+
#ifndef NO_FANCY_MALLOC
# ifndef SMALL_BUCKET_VIA_TABLE
# define SMALL_BUCKET_VIA_TABLE
@@ -187,7 +245,7 @@
# ifndef TWO_POT_OPTIMIZE
# define TWO_POT_OPTIMIZE
# endif
-# if defined(PERL_CORE) && !defined(PERL_EMERGENCY_SBRK)
+# if (defined(PERL_CORE) || !defined(NO_MALLOC_DYNAMIC_CFG)) && !defined(PERL_EMERGENCY_SBRK)
# define PERL_EMERGENCY_SBRK
# endif
# if defined(PERL_CORE) && !defined(DEBUGGING_MSTATS)
@@ -211,6 +269,12 @@
# if defined(DEBUGGING) && !defined(NO_RCHECK)
# define RCHECK
# endif
+# if defined(DEBUGGING) && !defined(NO_RCHECK) && !defined(NO_MFILL) && !defined(MALLOC_FILL)
+# define MALLOC_FILL
+# endif
+# if defined(DEBUGGING) && !defined(NO_RCHECK) && !defined(NO_FILL_CHECK) && !defined(MALLOC_FILL_CHECK)
+# define MALLOC_FILL_CHECK
+# endif
# if defined(RCHECK) && defined(IGNORE_SMALL_BAD_FREE)
# undef IGNORE_SMALL_BAD_FREE
# endif
@@ -251,6 +315,11 @@
# define croak2 croak
# define warn2 warn
# endif
+# if defined(USE_5005THREADS) || defined(USE_ITHREADS)
+# define PERL_MAYBE_ALIVE PL_thr_key
+# else
+# define PERL_MAYBE_ALIVE 1
+# endif
#else
# ifdef PERL_FOR_X2P
# include "../EXTERN.h"
@@ -259,6 +328,10 @@
# include <stdlib.h>
# include <stdio.h>
# include <memory.h>
+# ifdef OS2
+# include <io.h>
+# endif
+# include <string.h>
# ifndef Malloc_t
# define Malloc_t void *
# endif
@@ -274,6 +347,9 @@
# ifndef UV
# define UV unsigned long
# endif
+# ifndef IV
+# define IV long
+# endif
# ifndef caddr_t
# define caddr_t char *
# endif
@@ -284,6 +360,25 @@
# define PerlEnv_getenv getenv
# define PerlIO_printf fprintf
# define PerlIO_stderr() stderr
+# define PerlIO_puts(f,s) fputs(s,f)
+# ifndef INT2PTR
+# define INT2PTR(t,i) ((t)(i))
+# endif
+# ifndef PTR2UV
+# define PTR2UV(p) ((UV)(p))
+# endif
+# ifndef UVuf
+# define UVuf "lu"
+# endif
+# ifndef UVxf
+# define UVxf "lx"
+# endif
+# ifndef Nullch
+# define Nullch NULL
+# endif
+# ifndef MEM_ALIGNBYTES
+# define MEM_ALIGNBYTES 4
+# endif
# endif
# ifndef croak /* make depend */
# define croak(mess, arg) (warn((mess), (arg)), exit(1))
@@ -295,7 +390,7 @@
# define warn(mess, arg) fprintf(stderr, (mess), (arg))
# endif
# ifndef warn2
-# define warn2(mess, arg1) fprintf(stderr, (mess), (arg1), (arg2))
+# define warn2(mess, arg1, arg2) fprintf(stderr, (mess), (arg1), (arg2))
# endif
# ifdef DEBUG_m
# undef DEBUG_m
@@ -317,6 +412,7 @@
# ifndef PERL_GET_INTERP
# define PERL_GET_INTERP PL_curinterp
# endif
+# define PERL_MAYBE_ALIVE 1
# ifndef Perl_malloc
# define Perl_malloc malloc
# endif
@@ -332,7 +428,7 @@
# ifndef Perl_strdup
# define Perl_strdup strdup
# endif
-#endif
+#endif /* defined PERL_CORE */
#ifndef MUTEX_LOCK
# define MUTEX_LOCK(l)
@@ -358,7 +454,7 @@
# undef DEBUG_m
# define DEBUG_m(a) \
STMT_START { \
- if (PERL_GET_INTERP) { \
+ if (PERL_MAYBE_ALIVE && PERL_GET_THX) { \
dTHX; \
if (DEBUG_m_TEST) { \
PL_debug &= ~DEBUG_m_FLAG; \
@@ -480,7 +576,7 @@ union overhead {
u_char ovu_index; /* bucket # */
u_char ovu_magic; /* magic number */
#ifdef RCHECK
- u_short ovu_size; /* actual block size */
+ u_short ovu_size; /* block size (requested + overhead - 1) */
u_int ovu_rmagic; /* range magic number */
#endif
} ovu;
@@ -497,7 +593,7 @@ union overhead {
#ifdef RCHECK
# define RSLOP sizeof (u_int)
# ifdef TWO_POT_OPTIMIZE
-# define MAX_SHORT_BUCKET (12 * BUCKETS_PER_POW2)
+# define MAX_SHORT_BUCKET (12 * BUCKETS_PER_POW2) /* size-1 fits in short */
# else
# define MAX_SHORT_BUCKET (13 * BUCKETS_PER_POW2)
# endif
@@ -883,6 +979,12 @@ static int getpages_adjacent(MEM_SIZE require);
# define MUTEX_UNLOCK(m) STMT_START { if (*m) mutex_unlock(*m); } STMT_END
#endif
+#endif /* defined PERL_CORE */
+
+#ifndef PTRSIZE
+# define PTRSIZE sizeof(void*)
+#endif
+
#ifndef BITS_IN_PTR
# define BITS_IN_PTR (8*PTRSIZE)
#endif
@@ -908,6 +1010,82 @@ extern Malloc_t sbrk(int);
# endif
#endif
+#ifndef MIN_SBRK_FRAC1000 /* Backward compatibility */
+# define MIN_SBRK_FRAC1000 (MIN_SBRK_FRAC * 10)
+#endif
+
+#ifndef START_EXTERN_C
+# ifdef __cplusplus
+# define START_EXTERN_C extern "C" {
+# else
+# define START_EXTERN_C
+# endif
+#endif
+
+#ifndef END_EXTERN_C
+# ifdef __cplusplus
+# define END_EXTERN_C };
+# else
+# define END_EXTERN_C
+# endif
+#endif
+
+#include "malloc_ctl.h"
+
+#ifndef NO_MALLOC_DYNAMIC_CFG
+# define PERL_MALLOC_OPT_CHARS "FMfAPGdac"
+
+static IV MallocCfg[MallocCfg_last] = {
+ FIRST_SBRK,
+ MIN_SBRK,
+ MIN_SBRK_FRAC,
+ SBRK_ALLOW_FAILURES,
+ SBRK_FAILURE_PRICE,
+ SBRK_ALLOW_FAILURES * SBRK_FAILURE_PRICE, /* sbrk_goodness */
+ 1, /* FILL_DEAD */
+ 1, /* FILL_ALIVE */
+ 1, /* FILL_CHECK */
+ 0, /* MallocCfg_skip_cfg_env */
+ 0, /* MallocCfg_cfg_env_read */
+ 0, /* MallocCfg_emergency_buffer_size */
+ 0, /* MallocCfg_emergency_buffer_prepared_size */
+ 0 /* MallocCfg_emergency_buffer_last_req */
+};
+IV *MallocCfg_ptr = MallocCfg;
+
+# undef MIN_SBRK
+# undef FIRST_SBRK
+# undef MIN_SBRK_FRAC1000
+# undef SBRK_ALLOW_FAILURES
+# undef SBRK_FAILURE_PRICE
+
+# define MIN_SBRK MallocCfg[MallocCfg_MIN_SBRK]
+# define FIRST_SBRK MallocCfg[MallocCfg_FIRST_SBRK]
+# define MIN_SBRK_FRAC1000 MallocCfg[MallocCfg_MIN_SBRK_FRAC1000]
+# define SBRK_ALLOW_FAILURES MallocCfg[MallocCfg_SBRK_ALLOW_FAILURES]
+# define SBRK_FAILURE_PRICE MallocCfg[MallocCfg_SBRK_FAILURE_PRICE]
+
+# define sbrk_goodness MallocCfg[MallocCfg_sbrk_goodness]
+
+# define emergency_buffer_size MallocCfg[MallocCfg_emergency_buffer_size]
+# define emergency_buffer_last_req MallocCfg[MallocCfg_emergency_buffer_last_req]
+
+# define FILL_DEAD MallocCfg[MallocCfg_filldead]
+# define FILL_ALIVE MallocCfg[MallocCfg_fillalive]
+# define FILL_CHECK_CFG MallocCfg[MallocCfg_fillcheck]
+# define FILL_CHECK (FILL_DEAD && FILL_CHECK_CFG)
+
+#else /* defined(NO_MALLOC_DYNAMIC_CFG) */
+
+# define FILL_DEAD 1
+# define FILL_ALIVE 1
+# define FILL_CHECK 1
+static int sbrk_goodness = SBRK_ALLOW_FAILURES * SBRK_FAILURE_PRICE;
+
+# define NO_PERL_MALLOC_ENV
+
+#endif
+
#ifdef DEBUGGING_MSTATS
/*
* nmalloc[i] is the difference between the number of mallocs and frees
@@ -922,27 +1100,107 @@ static u_int start_slack;
static u_int goodsbrk;
-# ifdef PERL_EMERGENCY_SBRK
+#ifdef PERL_EMERGENCY_SBRK
# ifndef BIG_SIZE
# define BIG_SIZE (1<<16) /* 64K */
# endif
static char *emergency_buffer;
+static char *emergency_buffer_prepared;
+
+# ifdef NO_MALLOC_DYNAMIC_CFG
static MEM_SIZE emergency_buffer_size;
-static MEM_SIZE no_mem; /* 0 if the last request for more memory succeeded.
- Otherwise the size of the failing request. */
+ /* 0 if the last request for more memory succeeded.
+ Otherwise the size of the failing request. */
+static MEM_SIZE emergency_buffer_last_req;
+# endif
+
+# ifndef emergency_sbrk_croak
+# define emergency_sbrk_croak croak2
+# endif
+
+# ifdef PERL_CORE
+static char *
+perl_get_emergency_buffer(IV *size)
+{
+ dTHX;
+ /* First offense, give a possibility to recover by dieing. */
+ /* No malloc involved here: */
+ GV **gvp = (GV**)hv_fetch(PL_defstash, "^M", 2, 0);
+ SV *sv;
+ char *pv;
+ STRLEN n_a;
+
+ if (!gvp) gvp = (GV**)hv_fetch(PL_defstash, "\015", 1, 0);
+ if (!gvp || !(sv = GvSV(*gvp)) || !SvPOK(sv)
+ || (SvLEN(sv) < (1<<LOG_OF_MIN_ARENA) - M_OVERHEAD))
+ return NULL; /* Now die die die... */
+ /* Got it, now detach SvPV: */
+ pv = SvPV(sv, n_a);
+ /* Check alignment: */
+ if ((PTR2UV(pv) - sizeof(union overhead)) & (NEEDED_ALIGNMENT - 1)) {
+ PerlIO_puts(PerlIO_stderr(),"Bad alignment of $^M!\n");
+ return NULL; /* die die die */
+ }
+
+ SvPOK_off(sv);
+ SvPVX(sv) = Nullch;
+ SvCUR(sv) = SvLEN(sv) = 0;
+ *size = malloced_size(pv) + M_OVERHEAD;
+ return pv - sizeof(union overhead);
+}
+# define PERL_GET_EMERGENCY_BUFFER(p) perl_get_emergency_buffer(p)
+# else
+# define PERL_GET_EMERGENCY_BUFFER(p) NULL
+# endif /* defined PERL_CORE */
+
+# ifndef NO_MALLOC_DYNAMIC_CFG
+static char *
+get_emergency_buffer(IV *size)
+{
+ char *pv = emergency_buffer_prepared;
+
+ *size = MallocCfg[MallocCfg_emergency_buffer_prepared_size];
+ emergency_buffer_prepared = 0;
+ MallocCfg[MallocCfg_emergency_buffer_prepared_size] = 0;
+ return pv;
+}
+
+/* Returns 0 on success, -1 on bad alignment, -2 if not implemented */
+int
+set_emergency_buffer(char *b, IV size)
+{
+ if (PTR2UV(b) & (NEEDED_ALIGNMENT - 1))
+ return -1;
+ if (MallocCfg[MallocCfg_emergency_buffer_prepared_size])
+ add_to_chain((void*)emergency_buffer_prepared,
+ MallocCfg[MallocCfg_emergency_buffer_prepared_size], 0);
+ emergency_buffer_prepared = b;
+ MallocCfg[MallocCfg_emergency_buffer_prepared_size] = size;
+ return 0;
+}
+# define GET_EMERGENCY_BUFFER(p) get_emergency_buffer(p)
+# else /* NO_MALLOC_DYNAMIC_CFG */
+# define GET_EMERGENCY_BUFFER(p) NULL
+int
+set_emergency_buffer(char *b, IV size)
+{
+ return -1;
+}
+# endif
static Malloc_t
emergency_sbrk(MEM_SIZE size)
{
MEM_SIZE rsize = (((size - 1)>>LOG_OF_MIN_ARENA) + 1)<<LOG_OF_MIN_ARENA;
- if (size >= BIG_SIZE && (!no_mem || (size < no_mem))) {
+ if (size >= BIG_SIZE
+ && (!emergency_buffer_last_req || (size < emergency_buffer_last_req))) {
/* Give the possibility to recover, but avoid an infinite cycle. */
MALLOC_UNLOCK;
- no_mem = size;
- croak2("Out of memory during \"large\" request for %"UVuf" bytes, total sbrk() is %"UVuf" bytes", (UV)size, (UV)(goodsbrk + sbrk_slack));
+ emergency_buffer_last_req = size;
+ emergency_sbrk_croak("Out of memory during \"large\" request for %"UVuf" bytes, total sbrk() is %"UVuf" bytes", (UV)size, (UV)(goodsbrk + sbrk_slack));
}
if (emergency_buffer_size >= rsize) {
@@ -952,14 +1210,11 @@ emergency_sbrk(MEM_SIZE size)
emergency_buffer += rsize;
return old;
} else {
- dTHX;
/* First offense, give a possibility to recover by dieing. */
/* No malloc involved here: */
- GV **gvp = (GV**)hv_fetch(PL_defstash, "^M", 2, 0);
- SV *sv;
- char *pv;
+ IV Size;
+ char *pv = GET_EMERGENCY_BUFFER(&Size);
int have = 0;
- STRLEN n_a;
if (emergency_buffer_size) {
add_to_chain(emergency_buffer, emergency_buffer_size, 0);
@@ -967,38 +1222,42 @@ emergency_sbrk(MEM_SIZE size)
emergency_buffer = Nullch;
have = 1;
}
- if (!gvp) gvp = (GV**)hv_fetch(PL_defstash, "\015", 1, 0);
- if (!gvp || !(sv = GvSV(*gvp)) || !SvPOK(sv)
- || (SvLEN(sv) < (1<<LOG_OF_MIN_ARENA) - M_OVERHEAD)) {
+
+ if (!pv)
+ pv = PERL_GET_EMERGENCY_BUFFER(&Size);
+ if (!pv) {
if (have)
goto do_croak;
return (char *)-1; /* Now die die die... */
}
- /* Got it, now detach SvPV: */
- pv = SvPV(sv, n_a);
+
/* Check alignment: */
- if ((PTR2UV(pv) - sizeof(union overhead)) & (NEEDED_ALIGNMENT - 1)) {
+ if (PTR2UV(pv) & (NEEDED_ALIGNMENT - 1)) {
+ dTHX;
+
PerlIO_puts(PerlIO_stderr(),"Bad alignment of $^M!\n");
return (char *)-1; /* die die die */
}
- emergency_buffer = pv - sizeof(union overhead);
- emergency_buffer_size = malloced_size(pv) + M_OVERHEAD;
- SvPOK_off(sv);
- SvPVX(sv) = Nullch;
- SvCUR(sv) = SvLEN(sv) = 0;
+ emergency_buffer = pv;
+ emergency_buffer_size = Size;
}
do_croak:
MALLOC_UNLOCK;
- croak("Out of memory during request for %"UVuf" bytes, total sbrk() is %"UVuf" bytes", (UV)size, (UV)(goodsbrk + sbrk_slack));
+ emergency_sbrk_croak("Out of memory during request for %"UVuf" bytes, total sbrk() is %"UVuf" bytes", (UV)size, (UV)(goodsbrk + sbrk_slack));
/* NOTREACHED */
return Nullch;
}
-# else /* !defined(PERL_EMERGENCY_SBRK) */
+#else /* !defined(PERL_EMERGENCY_SBRK) */
# define emergency_sbrk(size) -1
-# endif
-#endif /* ifdef PERL_CORE */
+#endif /* defined PERL_EMERGENCY_SBRK */
+
+static void
+write2(char *mess)
+{
+ write(2, mess, strlen(mess));
+}
#ifdef DEBUGGING
#undef ASSERT
@@ -1006,14 +1265,103 @@ emergency_sbrk(MEM_SIZE size)
static void
botch(char *diag, char *s)
{
+ if (!(PERL_MAYBE_ALIVE && PERL_GET_THX))
+ goto do_write;
+ else {
dTHX;
- PerlIO_printf(PerlIO_stderr(), "assertion botched (%s?): %s\n", diag, s);
+
+ if (PerlIO_printf(PerlIO_stderr(),
+ "assertion botched (%s?): %s\n", diag, s) != 0) {
+ do_write: /* Can be initializing interpreter */
+ write2("assertion botched (");
+ write2(diag);
+ write2("?): ");
+ write2(s);
+ write2("\n");
+ }
PerlProc_abort();
+ }
}
#else
#define ASSERT(p, diag)
#endif
+#ifdef MALLOC_FILL
+/* Fill should be long enough to cover long */
+static void
+fill_pat_4bytes(unsigned char *s, size_t nbytes, const unsigned char *fill)
+{
+ unsigned char *e = s + nbytes;
+ long *lp;
+ long lfill = *(long*)fill;
+
+ if (PTR2UV(s) & (sizeof(long)-1)) { /* Align the pattern */
+ int shift = sizeof(long) - (PTR2UV(s) & (sizeof(long)-1));
+ unsigned const char *f = fill + sizeof(long) - shift;
+ unsigned char *e1 = s + shift;
+
+ while (s < e1)
+ *s++ = *f++;
+ }
+ lp = (long*)s;
+ while ((unsigned char*)(lp + 1) <= e)
+ *lp++ = lfill;
+ s = (unsigned char*)lp;
+ while (s < e)
+ *s++ = *fill++;
+}
+/* Just malloc()ed */
+static const unsigned char fill_feedadad[] =
+ {0xFE, 0xED, 0xAD, 0xAD, 0xFE, 0xED, 0xAD, 0xAD,
+ 0xFE, 0xED, 0xAD, 0xAD, 0xFE, 0xED, 0xAD, 0xAD};
+/* Just free()ed */
+static const unsigned char fill_deadbeef[] =
+ {0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF,
+ 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF};
+# define FILL_DEADBEEF(s, n) \
+ (void)(FILL_DEAD? (fill_pat_4bytes((s), (n), fill_deadbeef), 0) : 0)
+# define FILL_FEEDADAD(s, n) \
+ (void)(FILL_ALIVE? (fill_pat_4bytes((s), (n), fill_feedadad), 0) : 0)
+#else
+# define FILL_DEADBEEF(s, n) ((void)0)
+# define FILL_FEEDADAD(s, n) ((void)0)
+# undef MALLOC_FILL_CHECK
+#endif
+
+#ifdef MALLOC_FILL_CHECK
+static int
+cmp_pat_4bytes(unsigned char *s, size_t nbytes, const unsigned char *fill)
+{
+ unsigned char *e = s + nbytes;
+ long *lp;
+ long lfill = *(long*)fill;
+
+ if (PTR2UV(s) & (sizeof(long)-1)) { /* Align the pattern */
+ int shift = sizeof(long) - (PTR2UV(s) & (sizeof(long)-1));
+ unsigned const char *f = fill + sizeof(long) - shift;
+ unsigned char *e1 = s + shift;
+
+ while (s < e1)
+ if (*s++ != *f++)
+ return 1;
+ }
+ lp = (long*)s;
+ while ((unsigned char*)(lp + 1) <= e)
+ if (*lp++ != lfill)
+ return 1;
+ s = (unsigned char*)lp;
+ while (s < e)
+ if (*s++ != *fill++)
+ return 1;
+ return 0;
+}
+# define FILLCHECK_DEADBEEF(s, n) \
+ ASSERT(!FILL_CHECK || !cmp_pat_4bytes(s, n, fill_deadbeef), \
+ "free()ed/realloc()ed-away memory was overwritten")
+#else
+# define FILLCHECK_DEADBEEF(s, n) ((void)0)
+#endif
+
Malloc_t
Perl_malloc(register size_t nbytes)
{
@@ -1111,14 +1459,17 @@ Perl_malloc(register size_t nbytes)
}
/* remove from linked list */
-#if defined(RCHECK)
- if ((PTR2UV(p)) & (MEM_ALIGNBYTES - 1)) {
+#ifdef DEBUGGING
+ if ( (PTR2UV(p) & (MEM_ALIGNBYTES - 1))
+ /* Can't get this low */
+ || (p && PTR2UV(p) < (1<<LOG_OF_MIN_ARENA)) ) {
dTHX;
PerlIO_printf(PerlIO_stderr(),
"Unaligned pointer in the free chain 0x%"UVxf"\n",
PTR2UV(p));
}
- if ((PTR2UV(p->ov_next)) & (MEM_ALIGNBYTES - 1)) {
+ if ( (PTR2UV(p->ov_next) & (MEM_ALIGNBYTES - 1))
+ || (p->ov_next && PTR2UV(p->ov_next) < (1<<LOG_OF_MIN_ARENA)) ) {
dTHX;
PerlIO_printf(PerlIO_stderr(),
"Unaligned `next' pointer in the free "
@@ -1135,6 +1486,9 @@ Perl_malloc(register size_t nbytes)
PTR2UV((Malloc_t)(p + CHUNK_SHIFT)), (unsigned long)(PL_an++),
(long)size));
+ FILLCHECK_DEADBEEF((unsigned char*)(p + CHUNK_SHIFT),
+ BUCKET_SIZE_REAL(bucket));
+
#ifdef IGNORE_SMALL_BAD_FREE
if (bucket >= FIRST_BUCKET_WITH_CHECK)
#endif
@@ -1161,6 +1515,7 @@ Perl_malloc(register size_t nbytes)
nbytes = (nbytes + 3) &~ 3;
*((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
}
+ FILL_FEEDADAD((unsigned char *)(p + CHUNK_SHIFT), size);
#endif
return ((Malloc_t)(p + CHUNK_SHIFT));
}
@@ -1168,7 +1523,6 @@ Perl_malloc(register size_t nbytes)
static char *last_sbrk_top;
static char *last_op; /* This arena can be easily extended. */
static MEM_SIZE sbrked_remains;
-static int sbrk_good = SBRK_ALLOW_FAILURES * SBRK_FAILURE_PRICE;
#ifdef DEBUGGING_MSTATS
static int sbrks;
@@ -1274,13 +1628,13 @@ getpages(MEM_SIZE needed, int *nblksp, int bucket)
union overhead *ovp;
MEM_SIZE slack = 0;
- if (sbrk_good > 0) {
+ if (sbrk_goodness > 0) {
if (!last_sbrk_top && require < FIRST_SBRK)
require = FIRST_SBRK;
else if (require < MIN_SBRK) require = MIN_SBRK;
- if (require < goodsbrk * MIN_SBRK_FRAC / 100)
- require = goodsbrk * MIN_SBRK_FRAC / 100;
+ if (require < goodsbrk * MIN_SBRK_FRAC1000 / 1000)
+ require = goodsbrk * MIN_SBRK_FRAC1000 / 1000;
require = ((require - 1 + MIN_SBRK) / MIN_SBRK) * MIN_SBRK;
} else {
require = needed;
@@ -1297,7 +1651,7 @@ getpages(MEM_SIZE needed, int *nblksp, int bucket)
#endif
if (cp == last_sbrk_top) {
/* Common case, anything is fine. */
- sbrk_good++;
+ sbrk_goodness++;
ovp = (union overhead *) (cp - sbrked_remains);
last_op = cp - sbrked_remains;
sbrked_remains = require - (needed - sbrked_remains);
@@ -1369,7 +1723,7 @@ getpages(MEM_SIZE needed, int *nblksp, int bucket)
if (cp == (char *)-1)
return 0;
}
- sbrk_good = -1; /* Disable optimization!
+ sbrk_goodness = -1; /* Disable optimization!
Continue with not-aligned... */
} else {
cp += slack;
@@ -1378,7 +1732,7 @@ getpages(MEM_SIZE needed, int *nblksp, int bucket)
}
if (last_sbrk_top) {
- sbrk_good -= SBRK_FAILURE_PRICE;
+ sbrk_goodness -= SBRK_FAILURE_PRICE;
}
ovp = (union overhead *) cp;
@@ -1411,7 +1765,7 @@ getpages(MEM_SIZE needed, int *nblksp, int bucket)
last_op = cp;
}
#if !defined(PLAIN_MALLOC) && !defined(NO_FANCY_MALLOC)
- no_mem = 0;
+ emergency_buffer_last_req = 0;
#endif
last_sbrk_top = cp + require;
#ifdef DEBUGGING_MSTATS
@@ -1450,7 +1804,7 @@ getpages_adjacent(MEM_SIZE require)
add_to_chain((void*)(last_sbrk_top - sbrked_remains),
sbrked_remains, 0);
add_to_chain((void*)cp, require, 0);
- sbrk_good -= SBRK_FAILURE_PRICE;
+ sbrk_goodness -= SBRK_FAILURE_PRICE;
sbrked_remains = 0;
last_sbrk_top = 0;
last_op = 0;
@@ -1471,9 +1825,44 @@ morecore(register int bucket)
register int rnu; /* 2^rnu bytes will be requested */
int nblks; /* become nblks blocks of the desired size */
register MEM_SIZE siz, needed;
+ static int were_called = 0;
if (nextf[bucket])
return;
+#ifndef NO_PERL_MALLOC_ENV
+ if (!were_called) {
+ /* It's the our first time. Initialize ourselves */
+ were_called = 1; /* Avoid a loop */
+ if (!MallocCfg[MallocCfg_skip_cfg_env]) {
+ char *s = getenv("PERL_MALLOC_OPT"), *t = s, *off;
+ const char *opts = PERL_MALLOC_OPT_CHARS;
+ int changed = 0;
+
+ while ( t && t[0] && t[1] == '='
+ && ((off = strchr(opts, *t))) ) {
+ IV val = 0;
+
+ t += 2;
+ while (*t <= '9' && *t >= '0')
+ val = 10*val + *t++ - '0';
+ if (!*t || *t == ';') {
+ if (MallocCfg[off - opts] != val)
+ changed = 1;
+ MallocCfg[off - opts] = val;
+ if (*t)
+ t++;
+ }
+ }
+ if (t && *t) {
+ write2("Unrecognized part of PERL_MALLOC_OPT: `");
+ write2(t);
+ write2("'\n");
+ }
+ if (changed)
+ MallocCfg[MallocCfg_cfg_env_read] = 1;
+ }
+ }
+#endif
if (bucket == sizeof(MEM_SIZE)*8*BUCKETS_PER_POW2) {
MALLOC_UNLOCK;
croak("%s", "Out of memory during ridiculously large request");
@@ -1518,6 +1907,7 @@ morecore(register int bucket)
if (!ovp)
return;
+ FILL_DEADBEEF((unsigned char*)ovp, needed);
/*
* Add new memory allocated to that on
@@ -1544,6 +1934,7 @@ morecore(register int bucket)
start_slack += M_OVERHEAD * nblks;
}
#endif
+
while (--nblks > 0) {
ovp->ov_next = (union overhead *)((caddr_t)ovp + siz);
ovp = (union overhead *)((caddr_t)ovp + siz);
@@ -1577,6 +1968,10 @@ Perl_mfree(void *mp)
if (cp == NULL)
return;
+#ifdef DEBUGGING
+ if (PTR2UV(cp) & (MEM_ALIGNBYTES - 1))
+ croak("%s", "wrong alignment in free()");
+#endif
ovp = (union overhead *)((caddr_t)cp
- sizeof (union overhead) * CHUNK_SHIFT);
#ifdef PACK_MALLOC
@@ -1638,7 +2033,10 @@ Perl_mfree(void *mp)
}
nbytes = (nbytes + 3) &~ 3;
ASSERT(*(u_int *)((caddr_t)ovp + nbytes - RSLOP) == RMAGIC, "chunk's tail overwrite");
+ FILLCHECK_DEADBEEF((unsigned char*)((caddr_t)ovp + nbytes - RSLOP + sizeof(u_int)),
+ BUCKET_SIZE_REAL(OV_INDEX(ovp)) - (nbytes - RSLOP + sizeof(u_int)));
}
+ FILL_DEADBEEF((unsigned char*)(ovp+1), BUCKET_SIZE_REAL(OV_INDEX(ovp)));
ovp->ov_rmagic = RMAGIC - 1;
#endif
ASSERT(OV_INDEX(ovp) < NBUCKETS, "chunk's head overwrite");
@@ -1708,9 +2106,9 @@ Perl_realloc(void *mp, size_t nbytes)
? "of freed memory " : "");
}
#else
- warn("%srealloc() %signored",
- (ovp->ov_rmagic == RMAGIC - 1 ? "" : "Bad "),
- ovp->ov_rmagic == RMAGIC - 1 ? "of freed memory " : "");
+ warn2("%srealloc() %signored",
+ (ovp->ov_rmagic == RMAGIC - 1 ? "" : "Bad "),
+ ovp->ov_rmagic == RMAGIC - 1 ? "of freed memory " : "");
#endif
#else
#ifdef PERL_CORE
@@ -1776,6 +2174,14 @@ Perl_realloc(void *mp, size_t nbytes)
}
nb = (nb + 3) &~ 3;
ASSERT(*(u_int *)((caddr_t)ovp + nb - RSLOP) == RMAGIC, "chunk's tail overwrite");
+ FILLCHECK_DEADBEEF((unsigned char*)((caddr_t)ovp + nb - RSLOP + sizeof(u_int)),
+ BUCKET_SIZE_REAL(OV_INDEX(ovp)) - (nb - RSLOP + sizeof(u_int)));
+ if (nbytes > ovp->ov_size + 1 - M_OVERHEAD)
+ FILL_FEEDADAD((unsigned char*)cp + ovp->ov_size + 1 - M_OVERHEAD,
+ nbytes - (ovp->ov_size + 1 - M_OVERHEAD));
+ else
+ FILL_DEADBEEF((unsigned char*)cp + nbytes,
+ nb - M_OVERHEAD + RSLOP - nbytes);
/*
* Convert amount of memory requested into
* closest block size stored in hash buckets
@@ -1954,7 +2360,7 @@ Perl_get_mstats(pTHX_ perl_mstats_t *buf, int buflen, int level)
}
buf->total_sbrk = goodsbrk + sbrk_slack;
buf->sbrks = sbrks;
- buf->sbrk_good = sbrk_good;
+ buf->sbrk_good = sbrk_goodness;
buf->sbrk_slack = sbrk_slack;
buf->start_slack = start_slack;
buf->sbrked_remains = sbrked_remains;
diff --git a/malloc_ctl.h b/malloc_ctl.h
new file mode 100644
index 0000000000..e0bee00ea3
--- /dev/null
+++ b/malloc_ctl.h
@@ -0,0 +1,54 @@
+#ifndef MALLOC_CTL_H
+# define MALLOC_CTL_H
+
+struct perl_mstats {
+ UV *nfree;
+ UV *ntotal;
+ IV topbucket, topbucket_ev, topbucket_odd, totfree, total, total_chain;
+ IV total_sbrk, sbrks, sbrk_good, sbrk_slack, start_slack, sbrked_remains;
+ IV minbucket;
+ /* Level 1 info */
+ UV *bucket_mem_size;
+ UV *bucket_available_size;
+ UV nbuckets;
+};
+typedef struct perl_mstats perl_mstats_t;
+
+START_EXTERN_C
+Malloc_t Perl_malloc (MEM_SIZE nbytes);
+Malloc_t Perl_calloc (MEM_SIZE elements, MEM_SIZE size);
+Malloc_t Perl_realloc (Malloc_t where, MEM_SIZE nbytes);
+/* 'mfree' rather than 'free', since there is already a 'perl_free'
+ * that causes clashes with case-insensitive linkers */
+Free_t Perl_mfree (Malloc_t where);
+END_EXTERN_C
+
+#ifndef NO_MALLOC_DYNAMIC_CFG
+
+enum {
+ MallocCfg_FIRST_SBRK,
+ MallocCfg_MIN_SBRK,
+ MallocCfg_MIN_SBRK_FRAC1000,
+ MallocCfg_SBRK_ALLOW_FAILURES,
+ MallocCfg_SBRK_FAILURE_PRICE,
+ MallocCfg_sbrk_goodness,
+
+ MallocCfg_filldead,
+ MallocCfg_fillalive,
+ MallocCfg_fillcheck,
+
+ MallocCfg_skip_cfg_env,
+ MallocCfg_cfg_env_read,
+
+ MallocCfg_emergency_buffer_size,
+ MallocCfg_emergency_buffer_last_req,
+
+ MallocCfg_emergency_buffer_prepared_size,
+
+ MallocCfg_last
+};
+extern IV *MallocCfg_ptr;
+
+#endif
+
+#endif
diff --git a/os2/os2ish.h b/os2/os2ish.h
index b612683602..225d271236 100644
--- a/os2/os2ish.h
+++ b/os2/os2ish.h
@@ -218,6 +218,7 @@ void Perl_OS2_term(void **excH, int exitstatus, int flags);
# define PERL_SYS_INIT3(argcp, argvp, envp) \
{ void *xreg[2]; \
+ MALLOC_CHECK_TAINT(*argcp, *argvp, *envp) \
_response(argcp, argvp); \
_wildcard(argcp, argvp); \
Perl_OS2_init3(*envp, xreg, 0)
diff --git a/perl.c b/perl.c
index 9914935203..f85b010e58 100644
--- a/perl.c
+++ b/perl.c
@@ -1033,6 +1033,7 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit)
break;
case 't':
+ CHECK_MALLOC_TOO_LATE_FOR('t');
if( !PL_tainting ) {
PL_taint_warn = TRUE;
PL_tainting = TRUE;
@@ -1040,6 +1041,7 @@ S_parse_body(pTHX_ char **env, XSINIT_t xsinit)
s++;
goto reswitch;
case 'T':
+ CHECK_MALLOC_TOO_LATE_FOR('T');
PL_tainting = TRUE;
PL_taint_warn = FALSE;
s++;
@@ -1222,6 +1224,7 @@ print \" \\@INC:\\n @INC\\n\";");
while (isSPACE(*s))
s++;
if (*s == '-' && *(s+1) == 'T') {
+ CHECK_MALLOC_TOO_LATE_FOR('T');
PL_tainting = TRUE;
PL_taint_warn = FALSE;
}
@@ -2424,12 +2427,12 @@ Perl_moreswitches(pTHX_ char *s)
return s;
case 't':
if (!PL_tainting)
- Perl_croak(aTHX_ "Too late for \"-t\" option");
+ TOO_LATE_FOR('t');
s++;
return s;
case 'T':
if (!PL_tainting)
- Perl_croak(aTHX_ "Too late for \"-T\" option");
+ TOO_LATE_FOR('T');
s++;
return s;
case 'u':
@@ -3286,9 +3289,37 @@ S_init_ids(pTHX)
PL_uid |= PL_gid << 16;
PL_euid |= PL_egid << 16;
#endif
+ /* Should not happen: */
+ CHECK_MALLOC_TAINT(PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid));
PL_tainting |= (PL_uid && (PL_euid != PL_uid || PL_egid != PL_gid));
}
+#ifdef MYMALLOC
+/* This is used very early in the lifetime of the program. */
+int
+Perl_doing_taint(int argc, char *argv[], char *envp[])
+{
+ int uid = PerlProc_getuid();
+ int euid = PerlProc_geteuid();
+ int gid = PerlProc_getgid();
+ int egid = PerlProc_getegid();
+
+#ifdef VMS
+ uid |= gid << 16;
+ euid |= egid << 16;
+#endif
+ if (uid && (euid != uid || egid != gid))
+ return 1;
+ /* This is a really primitive check; $ENV{PERL_MALLOC_OPT} is
+ ignored only if -T are the first chars together; otherwise one
+ gets "Too late" message. */
+ if ( argc > 1 && argv[1][0] == '-'
+ && (argv[1][1] == 't' || argv[1][1] == 'T') )
+ return 1;
+ return 0;
+}
+#endif
+
STATIC void
S_forbid_setid(pTHX_ char *s)
{
diff --git a/perl.h b/perl.h
index 70a88d8103..9dbc248924 100644
--- a/perl.h
+++ b/perl.h
@@ -481,28 +481,43 @@ int usleep(unsigned int);
# else
# define EMBEDMYMALLOC /* for compatibility */
# endif
-START_EXTERN_C
-Malloc_t Perl_malloc (MEM_SIZE nbytes);
-Malloc_t Perl_calloc (MEM_SIZE elements, MEM_SIZE size);
-Malloc_t Perl_realloc (Malloc_t where, MEM_SIZE nbytes);
-/* 'mfree' rather than 'free', since there is already a 'perl_free'
- * that causes clashes with case-insensitive linkers */
-Free_t Perl_mfree (Malloc_t where);
-END_EXTERN_C
-
-typedef struct perl_mstats perl_mstats_t;
# define safemalloc Perl_malloc
# define safecalloc Perl_calloc
# define saferealloc Perl_realloc
# define safefree Perl_mfree
+# define CHECK_MALLOC_TOO_LATE_FOR_(code) STMT_START { \
+ if (!PL_tainting && MallocCfg_ptr[MallocCfg_cfg_env_read]) \
+ code; \
+ } STMT_END
+# define CHECK_MALLOC_TOO_LATE_FOR(ch) \
+ CHECK_MALLOC_TOO_LATE_FOR_(MALLOC_TOO_LATE_FOR(ch))
+# define panic_write2(s) write(2, s, strlen(s))
+# define CHECK_MALLOC_TAINT(newval) \
+ CHECK_MALLOC_TOO_LATE_FOR_( \
+ if (newval) { \
+ panic_write2("panic: tainting with $ENV{PERL_MALLOC_OPT}\n");\
+ exit(1); })
+extern int Perl_doing_taint(int argc, char *argv[], char *envp[]);
+# define MALLOC_CHECK_TAINT(argc,argv,env) STMT_START { \
+ if (Perl_doing_taint(argc, argv, env)) { \
+ MallocCfg_ptr[MallocCfg_skip_cfg_env] = 1; \
+ }} STMT_END;
#else /* MYMALLOC */
# define safemalloc safesysmalloc
# define safecalloc safesyscalloc
# define saferealloc safesysrealloc
# define safefree safesysfree
+# define CHECK_MALLOC_TOO_LATE_FOR(ch) ((void)0)
+# define CHECK_MALLOC_TAINT(newval) ((void)0)
+# define MALLOC_CHECK_TAINT(argc,argv,env)
#endif /* MYMALLOC */
+#define TOO_LATE_FOR_(ch,s) Perl_croak(aTHX_ "Too late for \"-%c\" option%s", (char)(ch), s)
+#define TOO_LATE_FOR(ch) TOO_LATE_FOR_(ch, "")
+#define MALLOC_TOO_LATE_FOR(ch) TOO_LATE_FOR_(ch, " with $ENV{PERL_MALLOC_OPT}")
+#define MALLOC_CHECK_TAINT2(argc,argv) MALLOC_CHECK_TAINT(argc,argv,NULL)
+
#if !defined(HAS_STRCHR) && defined(HAS_INDEX) && !defined(strchr)
#define strchr index
#define strrchr rindex
@@ -1676,17 +1691,10 @@ int isnan(double d);
#endif
-struct perl_mstats {
- UV *nfree;
- UV *ntotal;
- IV topbucket, topbucket_ev, topbucket_odd, totfree, total, total_chain;
- IV total_sbrk, sbrks, sbrk_good, sbrk_slack, start_slack, sbrked_remains;
- IV minbucket;
- /* Level 1 info */
- UV *bucket_mem_size;
- UV *bucket_available_size;
- UV nbuckets;
-};
+#ifdef MYMALLOC
+# include "malloc_ctl.h"
+#endif
+
struct RExC_state_t;
typedef MEM_SIZE STRLEN;
@@ -1935,13 +1943,6 @@ typedef struct clone_params CLONE_PARAMS;
# endif
#endif
-#ifdef JPL
- /* E.g. JPL needs to operate on a copy of the real environment.
- * JDK 1.2 and 1.3 seem to get upset if the original environment
- * is diddled with. */
-# define NEED_ENVIRON_DUP_FOR_MODIFY
-#endif
-
#ifndef PERL_SYS_INIT3
# define PERL_SYS_INIT3(argvp,argcp,envp) PERL_SYS_INIT(argvp,argcp)
#endif
diff --git a/plan9/plan9ish.h b/plan9/plan9ish.h
index 9b32a7dd80..5c922cf0ba 100644
--- a/plan9/plan9ish.h
+++ b/plan9/plan9ish.h
@@ -106,7 +106,7 @@
#define ABORT() kill(PerlProc_getpid(),SIGABRT);
#define BIT_BUCKET "/dev/null"
-#define PERL_SYS_INIT(c,v) MALLOC_INIT
+#define PERL_SYS_INIT(c,v) MALLOC_CHECK_TAINT2(*c,*v) MALLOC_INIT
#define dXSUB_SYS
#define PERL_SYS_TERM() MALLOC_TERM
diff --git a/sv.c b/sv.c
index 4e6d930ed2..7be1585c46 100644
--- a/sv.c
+++ b/sv.c
@@ -10747,6 +10747,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
PL_markstack = 0;
PL_scopestack = 0;
PL_savestack = 0;
+ PL_savestack_ix = 0;
+ PL_savestack_max = -1;
PL_retstack = 0;
PL_sig_pending = 0;
Zero(&PL_debug_pad, 1, struct perl_debug_pad);
@@ -10778,6 +10780,8 @@ perl_clone_using(PerlInterpreter *proto_perl, UV flags,
PL_markstack = 0;
PL_scopestack = 0;
PL_savestack = 0;
+ PL_savestack_ix = 0;
+ PL_savestack_max = -1;
PL_retstack = 0;
PL_sig_pending = 0;
Zero(&PL_debug_pad, 1, struct perl_debug_pad);
diff --git a/unixish.h b/unixish.h
index 5c95a7b0d4..4bf37095a0 100644
--- a/unixish.h
+++ b/unixish.h
@@ -129,7 +129,7 @@
#define Mkdir(path,mode) mkdir((path),(mode))
#ifndef PERL_SYS_INIT
-# define PERL_SYS_INIT(c,v) PERL_FPU_INIT MALLOC_INIT
+# define PERL_SYS_INIT(c,v) MALLOC_CHECK_TAINT2(*c,*v) PERL_FPU_INIT MALLOC_INIT
#endif
#ifndef PERL_SYS_TERM
diff --git a/vms/vmsish.h b/vms/vmsish.h
index 1a29aa6b59..076a6967f6 100644
--- a/vms/vmsish.h
+++ b/vms/vmsish.h
@@ -331,7 +331,7 @@ struct interp_intern {
#endif
#define BIT_BUCKET "_NLA0:"
-#define PERL_SYS_INIT(c,v) vms_image_init((c),(v)); MALLOC_INIT
+#define PERL_SYS_INIT(c,v) MALLOC_CHECK_TAINT2(*c,*v) vms_image_init((c),(v)); MALLOC_INIT
#define PERL_SYS_TERM() OP_REFCNT_TERM; MALLOC_TERM
#define dXSUB_SYS
#define HAS_KILL