This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
back out change #22167 "freeing a CV reference that was currently
[perl5.git] / perl.c
diff --git a/perl.c b/perl.c
index 9914935..f32e346 100644 (file)
--- a/perl.c
+++ b/perl.c
@@ -154,7 +154,6 @@ perl_construct(pTHXx)
    if (PL_perl_destruct_level > 0)
        init_interp();
 #endif
-
    /* Init the real globals (and main thread)? */
     if (!PL_linestr) {
 #ifdef PERL_FLEXIBLE_EXCEPTIONS
@@ -182,6 +181,9 @@ perl_construct(pTHXx)
            SvNV(&PL_sv_yes);
            SvREADONLY_on(&PL_sv_yes);
            SvREFCNT(&PL_sv_yes) = (~(U32)0)/2;
+
+           SvREADONLY_on(&PL_sv_placeholder);
+           SvREFCNT(&PL_sv_placeholder) = (~(U32)0)/2;
        }
 
        PL_sighandlerp = Perl_sighandler;
@@ -261,8 +263,10 @@ perl_construct(pTHXx)
        ("__environ", (unsigned long *) &environ_pointer, NULL);
 #endif /* environ */
 
-#ifdef  USE_ENVIRON_ARRAY
+#ifndef PERL_MICRO
+#   ifdef  USE_ENVIRON_ARRAY
     PL_origenviron = environ;
+#   endif
 #endif
 
     /* Use sysconf(_SC_CLK_TCK) if available, if not
@@ -350,6 +354,10 @@ perl_destruct(pTHXx)
 
     /* Destroy the main CV and syntax tree */
     if (PL_main_root) {
+       /* ensure comppad/curpad to refer to main's pad */
+       if (CvPADLIST(PL_main_cv)) {
+           PAD_SET_CUR_NOSAVE(CvPADLIST(PL_main_cv), 1);
+       }
        op_free(PL_main_root);
        PL_main_root = Nullop;
     }
@@ -373,6 +381,7 @@ perl_destruct(pTHXx)
         * Non-referenced objects are on their own.
         */
        sv_clean_objs();
+       PL_sv_objcount = 0;
     }
 
     /* unhook hooks which will soon be, or use, destroyed data */
@@ -407,6 +416,7 @@ perl_destruct(pTHXx)
     /* if PERL_USE_SAFE_PUTENV is defined environ will not have been copied
      * so we certainly shouldn't free it here
      */
+#ifndef PERL_MICRO
 #if defined(USE_ENVIRON_ARRAY) && !defined(PERL_USE_SAFE_PUTENV)
     if (environ != PL_origenviron
 #ifdef USE_ITHREADS
@@ -426,6 +436,7 @@ perl_destruct(pTHXx)
        environ = PL_origenviron;
     }
 #endif
+#endif /* !PERL_MICRO */
 
 #ifdef USE_ITHREADS
     /* the syntax tree is shared between clones
@@ -496,6 +507,8 @@ perl_destruct(pTHXx)
        PL_e_script = Nullsv;
     }
 
+    PL_perldb = 0;
+
     /* magical thingies */
 
     SvREFCNT_dec(PL_ofs_sv);   /* $, */
@@ -555,6 +568,15 @@ perl_destruct(pTHXx)
     PL_stderrgv = Nullgv;
     PL_last_in_gv = Nullgv;
     PL_replgv = Nullgv;
+    PL_DBgv = Nullgv;
+    PL_DBline = Nullgv;
+    PL_DBsub = Nullgv;
+    PL_DBsingle = Nullsv;
+    PL_DBtrace = Nullsv;
+    PL_DBsignal = Nullsv;
+    PL_DBassertion = Nullsv;
+    PL_DBcv = Nullcv;
+    PL_dbargs = Nullav;
     PL_debstash = Nullhv;
 
     /* reset so print() ends up where we expect */
@@ -589,6 +611,7 @@ perl_destruct(pTHXx)
     Safefree(PL_numeric_name);
     PL_numeric_name = Nullch;
     SvREFCNT_dec(PL_numeric_radix_sv);
+    PL_numeric_radix_sv = Nullsv;
 #endif
 
     /* clear utf8 character classes */
@@ -727,6 +750,7 @@ perl_destruct(pTHXx)
 #ifdef USE_ITHREADS
     /* free the pointer table used for cloning */
     ptr_table_free(PL_ptr_table);
+    PL_ptr_table = (PTR_TBL_t*)NULL;
 #endif
 
     /* free special SVs */
@@ -770,6 +794,7 @@ perl_destruct(pTHXx)
        }
     }
 #endif
+    PL_sv_count = 0;
 
 
 #if defined(PERLIO_LAYERS)
@@ -785,18 +810,31 @@ perl_destruct(pTHXx)
     SvREADONLY_off(&PL_sv_undef);
 
     Safefree(PL_origfilename);
+    PL_origfilename = Nullch;
     Safefree(PL_reg_start_tmp);
+    PL_reg_start_tmp = (char**)NULL;
+    PL_reg_start_tmpl = 0;
     if (PL_reg_curpm)
        Safefree(PL_reg_curpm);
     Safefree(PL_reg_poscache);
     free_tied_hv_pool();
     Safefree(PL_op_mask);
     Safefree(PL_psig_ptr);
+    PL_psig_ptr = (SV**)NULL;
     Safefree(PL_psig_name);
+    PL_psig_name = (SV**)NULL;
     Safefree(PL_bitcount);
+    PL_bitcount = Nullch;
     Safefree(PL_psig_pend);
+    PL_psig_pend = (int*)NULL;
+    PL_formfeed = Nullsv;
+    Safefree(PL_ofmt);
+    PL_ofmt = Nullch;
     nuke_stacks();
+    PL_tainting = FALSE;
+    PL_taint_warn = FALSE;
     PL_hints = 0;              /* Reset hints. Should hints be per-interpreter ? */
+    PL_debug = 0;
 
     DEBUG_P(debprofdump());
 
@@ -898,9 +936,117 @@ setuid perl scripts securely.\n");
 #endif
 #endif
 
+#if defined(USE_HASH_SEED) || defined(USE_HASH_SEED_EXPLICIT)
+    /* [perl #22371] Algorimic Complexity Attack on Perl 5.6.1, 5.8.0
+     * This MUST be done before any hash stores or fetches take place.
+     * If you set PL_rehash_seed (and assumedly also PL_rehash_seed_set)
+     * yourself, it is your responsibility to provide a good random seed!
+     * You can also define PERL_HASH_SEED in compile time, see hv.h. */
+    if (!PL_rehash_seed_set)
+        PL_rehash_seed = get_hash_seed();
+    {
+        char *s = PerlEnv_getenv("PERL_HASH_SEED_DEBUG");
+
+        if (s) {
+             int i = atoi(s);
+
+             if (i == 1)
+                  PerlIO_printf(Perl_debug_log, "HASH_SEED = %"UVuf"\n",
+                                PL_rehash_seed);
+        }
+    }
+#endif /* #if defined(USE_HASH_SEED) || defined(USE_HASH_SEED_EXPLICIT) */
+
     PL_origargc = argc;
     PL_origargv = argv;
 
+    {
+       /* Set PL_origalen be the sum of the contiguous argv[]
+        * elements plus the size of the env in case that it is
+        * contiguous with the argv[].  This is used in mg.c:mg_set()
+        * as the maximum modifiable length of $0.  In the worst case
+        * the area we are able to modify is limited to the size of
+        * the original argv[0].  (See below for 'contiguous', though.)
+        * --jhi */
+        char *s = NULL;
+        int i;
+        UV mask =
+          ~(UV)(PTRSIZE == 4 ? 3 : PTRSIZE == 8 ? 7 : PTRSIZE == 16 ? 15 : 0);
+         /* Do the mask check only if the args seem like aligned. */
+        UV aligned =
+          (mask < ~(UV)0) && ((PTR2UV(argv[0]) & mask) == PTR2UV(argv[0]));
+
+        /* See if all the arguments are contiguous in memory.  Note
+         * that 'contiguous' is a loose term because some platforms
+         * align the argv[] and the envp[].  If the arguments look
+         * like non-aligned, assume that they are 'strictly' or
+         * 'traditionally' contiguous.  If the arguments look like
+         * aligned, we just check that they are within aligned
+         * PTRSIZE bytes.  As long as no system has something bizarre
+         * like the argv[] interleaved with some other data, we are
+         * fine.  (Did I just evoke Murphy's Law?)  --jhi */
+        if (PL_origargv && PL_origargc >= 1 && (s = PL_origargv[0])) {
+             while (*s) s++;
+             for (i = 1; i < PL_origargc; i++) {
+                  if ((PL_origargv[i] == s + 1
+#ifdef OS2
+                       || PL_origargv[i] == s + 2
+#endif 
+                           )
+                      ||
+                      (aligned &&
+                       (PL_origargv[i] >  s &&
+                        PL_origargv[i] <=
+                        INT2PTR(char *, PTR2UV(s + PTRSIZE) & mask)))
+                       )
+                  {
+                       s = PL_origargv[i];
+                       while (*s) s++;
+                  }
+                  else
+                       break;
+             }
+        }
+        /* Can we grab env area too to be used as the area for $0? */
+        if (PL_origenviron) {
+             if ((PL_origenviron[0] == s + 1
+#ifdef OS2
+                  || (PL_origenviron[0] == s + 9 && (s += 8))
+#endif 
+                 )
+                 ||
+                 (aligned &&
+                  (PL_origenviron[0] >  s &&
+                   PL_origenviron[0] <=
+                   INT2PTR(char *, PTR2UV(s + PTRSIZE) & mask)))
+                )
+             {
+#ifndef OS2
+                  s = PL_origenviron[0];
+                  while (*s) s++;
+#endif
+                  my_setenv("NoNe  SuCh", Nullch);
+                  /* Force copy of environment. */
+                  for (i = 1; PL_origenviron[i]; i++) {
+                       if (PL_origenviron[i] == s + 1
+                           ||
+                           (aligned &&
+                            (PL_origenviron[i] >  s &&
+                             PL_origenviron[i] <=
+                             INT2PTR(char *, PTR2UV(s + PTRSIZE) & mask)))
+                          )
+                       {
+                            s = PL_origenviron[i];
+                            while (*s) s++;
+                       }
+                       else
+                            break;
+                  }
+             }
+        }
+        PL_origalen = s - PL_origargv[0] + 1;
+    }
+
     if (PL_do_undump) {
 
        /* Come here if running an undumped a.out. */
@@ -1033,6 +1179,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 +1187,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++;
@@ -1210,7 +1358,6 @@ print \"  \\@INC:\\n    @INC\\n\";");
        }
     }
   switch_end:
-    sv_setsv(get_sv("/", TRUE), PL_rs);
 
     if (
 #ifndef SECURE_INTERNAL_GETENV
@@ -1222,6 +1369,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;
        }
@@ -1329,9 +1477,7 @@ print \"  \\@INC:\\n    @INC\\n\";");
 
     boot_core_PerlIO();
     boot_core_UNIVERSAL();
-#ifndef PERL_MICRO
     boot_core_xsutils();
-#endif
 
     if (xsinit)
        (*xsinit)(aTHX);        /* in case linked C routines want magical variables */
@@ -1549,7 +1695,8 @@ S_run_body(pTHX_ I32 oldscope)
 
     if (!PL_restartop) {
        DEBUG_x(dump_all());
-       DEBUG(PerlIO_printf(Perl_debug_log, "\nEXECUTING...\n\n"));
+       if (!DEBUG_q_TEST)
+         PERL_DEBUG(PerlIO_printf(Perl_debug_log, "\nEXECUTING...\n\n"));
        DEBUG_S(PerlIO_printf(Perl_debug_log, "main thread is 0x%"UVxf"\n",
                              PTR2UV(thr)));
 
@@ -2124,11 +2271,11 @@ S_usage(pTHX_ char *name)               /* XXX move this out into a module ? */
     static char *usage_msg[] = {
 "-0[octal]       specify record separator (\\0, if no argument)",
 "-a              autosplit mode with -n or -p (splits $_ into @F)",
-"-C              enable native wide character system interfaces",
+"-C[number/list] enables the listed Unicode features",
 "-c              check syntax only (runs BEGIN and CHECK blocks)",
 "-d[:debugger]   run program under debugger",
 "-D[number/list] set debugging flags (argument is a bit mask or alphabets)",
-"-e 'command'    one line of program (several -e's allowed, omit programfile)",
+"-e program      one line of program (several -e's allowed, omit programfile)",
 "-F/pattern/     split() pattern for -a switch (//'s are optional)",
 "-i[extension]   edit <> files in place (makes backup if extension supplied)",
 "-Idirectory     specify @INC/#include directory (several -I's allowed)",
@@ -2139,16 +2286,16 @@ S_usage(pTHX_ char *name)               /* XXX move this out into a module ? */
 "-P              run program through C preprocessor before compilation",
 "-s              enable rudimentary parsing for switches after programfile",
 "-S              look for programfile using PATH environment variable",
-"-T              enable tainting checks",
 "-t              enable tainting warnings",
+"-T              enable tainting checks",
 "-u              dump core after parsing program",
 "-U              allow unsafe operations",
 "-v              print version, subversion (includes VERY IMPORTANT perl info)",
 "-V[:variable]   print configuration summary (or a single Config.pm variable)",
 "-w              enable many useful warnings (RECOMMENDED)",
 "-W              enable all warnings",
-"-X              disable all warnings",
 "-x[directory]   strip off text before #!perl line and perhaps cd to directory",
+"-X              disable all warnings",
 "\n",
 NULL
 };
@@ -2161,6 +2308,40 @@ NULL
        PerlIO_printf(PerlIO_stdout(), "\n  %s", *p++);
 }
 
+/* convert a string of -D options (or digits) into an int.
+ * sets *s to point to the char after the options */
+
+#ifdef DEBUGGING
+int
+Perl_get_debug_opts(pTHX_ char **s)
+{
+    int i = 0;
+    if (isALPHA(**s)) {
+       /* if adding extra options, remember to update DEBUG_MASK */
+       static char debopts[] = "psltocPmfrxu HXDSTRJvCAq";
+
+       for (; isALNUM(**s); (*s)++) {
+           char *d = strchr(debopts,**s);
+           if (d)
+               i |= 1 << (d - debopts);
+           else if (ckWARN_d(WARN_DEBUGGING))
+               Perl_warner(aTHX_ packWARN(WARN_DEBUGGING),
+                   "invalid option -D%c\n", **s);
+       }
+    }
+    else {
+       i = atoi(*s);
+       for (; isALNUM(**s); (*s)++) ;
+    }
+#  ifdef EBCDIC
+    if ((i & DEBUG_p_FLAG) && ckWARN_d(WARN_DEBUGGING))
+       Perl_warner(aTHX_ packWARN(WARN_DEBUGGING),
+               "-Dp not implemented on this platform\n");
+#  endif
+    return i;
+}
+#endif
+
 /* This routine handles any switches that can be given during run */
 
 char *
@@ -2207,6 +2388,7 @@ Perl_moreswitches(pTHX_ char *s)
                   PL_rs = newSVpvn(&ch, 1);
              }
         }
+        sv_setsv(get_sv("/", TRUE), PL_rs);
         return s + numlen;
     }
     case 'C':
@@ -2246,7 +2428,7 @@ Perl_moreswitches(pTHX_ char *s)
                sv_catpvn(sv, start, s-start);
                sv_catpv(sv, " split(/,/,q{");
                sv_catpv(sv, ++s);
-               sv_catpv(sv,    "})");
+               sv_catpv(sv, "})");
            }
            s += strlen(s);
            my_setenv("PERL5DB", SvPV(sv, PL_na));
@@ -2260,24 +2442,8 @@ Perl_moreswitches(pTHX_ char *s)
     {  
 #ifdef DEBUGGING
        forbid_setid("-D");
-       if (isALPHA(s[1])) {
-           /* if adding extra options, remember to update DEBUG_MASK */
-           static char debopts[] = "psltocPmfrxu HXDSTRJvC";
-           char *d;
-
-           for (s++; *s && (d = strchr(debopts,*s)); s++)
-               PL_debug |= 1 << (d - debopts);
-       }
-       else {
-           PL_debug = atoi(s+1);
-           for (s++; isDIGIT(*s); s++) ;
-       }
-#ifdef EBCDIC
-       if (DEBUG_p_TEST_ && ckWARN_d(WARN_DEBUGGING))
-           Perl_warner(aTHX_ packWARN(WARN_DEBUGGING),
-                   "-Dp not implemented on this platform\n");
-#endif
-       PL_debug |= DEBUG_TOP_FLAG;
+       s++;
+       PL_debug = get_debug_opts(&s) | DEBUG_TOP_FLAG;
 #else /* !DEBUGGING */
        if (ckWARN_d(WARN_DEBUGGING))
            Perl_warner(aTHX_ packWARN(WARN_DEBUGGING),
@@ -2361,9 +2527,10 @@ Perl_moreswitches(pTHX_ char *s)
        if (!PL_preambleav)
            PL_preambleav = newAV();
        if (*++s) {
-           SV *sv = newSVpvn("use assertions::activate split(/,/,q{",37);
+           SV *sv = newSVpv("use assertions::activate split(/,/,q", 0);
+           sv_catpvn(sv, "\0", 1);     /* Use NUL as q//-delimiter. */
            sv_catpv(sv,s);
-           sv_catpv(sv,"})");
+           sv_catpvn(sv, "\0)", 2);
            s+=strlen(s);
            av_push(PL_preambleav, sv);
        }
@@ -2397,9 +2564,10 @@ Perl_moreswitches(pTHX_ char *s)
                     Perl_croak(aTHX_ "Module name required with -%c option",
                               s[-1]);
                sv_catpvn(sv, start, s-start);
-               sv_catpv(sv, " split(/,/,q{");
+               sv_catpv(sv, " split(/,/,q");
+               sv_catpvn(sv, "\0)", 1);        /* Use NUL as q//-delimiter. */
                sv_catpv(sv, ++s);
-               sv_catpv(sv,    "})");
+               sv_catpvn(sv,  "\0)", 2);
            }
            s += strlen(s);
            if (!PL_preambleav)
@@ -2424,12 +2592,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':
@@ -2500,7 +2668,7 @@ Perl_moreswitches(pTHX_ char *s)
 #endif
 #ifdef MPE
        PerlIO_printf(PerlIO_stdout(),
-                     "MPE/iX port Copyright by Mark Klein and Mark Bixby, 1996-2002\n");
+                     "MPE/iX port Copyright by Mark Klein and Mark Bixby, 1996-2003\n");
 #endif
 #ifdef OEMVS
        PerlIO_printf(PerlIO_stdout(),
@@ -2744,6 +2912,8 @@ S_open_script(pTHX_ char *scriptname, bool dosearch, SV *sv, int *fdscript)
        SV *cpp = newSVpvn("",0);
        SV *cmd = NEWSV(0,0);
 
+       if (cpp_cfg[0] == 0) /* PERL_MICRO? */
+            Perl_croak(aTHX_ "Can't run with cpp -P with CPPSTDIN undefined");
        if (strEQ(cpp_cfg, "cppstdin"))
            Perl_sv_catpvf(aTHX_ cpp, "%s/", BIN_EXP);
        sv_catpv(cpp, cpp_cfg);
@@ -2841,18 +3011,19 @@ S_open_script(pTHX_ char *scriptname, bool dosearch, SV *sv, int *fdscript)
                 PL_statbuf.st_mode & (S_ISUID|S_ISGID))
             {
                 /* try again */
+                PERL_FPU_PRE_EXEC
                 PerlProc_execv(Perl_form(aTHX_ "%s/sperl"PERL_FS_VER_FMT,
                                          BIN_EXP, (int)PERL_REVISION,
                                          (int)PERL_VERSION,
                                          (int)PERL_SUBVERSION), PL_origargv);
+                PERL_FPU_POST_EXEC
                 Perl_croak(aTHX_ "Can't do setuid\n");
             }
 #       endif
 #       endif
 #       ifdef IAMSUID
             errno = EPERM;
-            Perl_croak(aTHX_ "Can't open perl script: %s\n",
-                       Strerror(errno));
+            Perl_croak(aTHX_ "Permission denied\n");
 #       else
             Perl_croak(aTHX_ "Can't open perl script \"%s\": %s\n",
                        CopFILE(PL_curcop), Strerror(errno));
@@ -3014,8 +3185,10 @@ S_validate_suid(pTHX_ char *validarg, char *scriptname, int fdscript)
         * But I don't think it's too important.  The manual lies when
         * it says access() is useful in setuid programs.
         */
-       if (PerlLIO_access(CopFILE(PL_curcop),1)) /*double check*/
-           Perl_croak(aTHX_ "Permission denied");
+       if (PerlLIO_access(CopFILE(PL_curcop),1)) { /*double check*/
+            errno = EPERM;
+           Perl_croak(aTHX_ "Permission denied\n");
+       }
 #else
        /* If we can swap euid and uid, then we can determine access rights
         * with a simple stat of the file, and then compare device and
@@ -3035,15 +3208,20 @@ S_validate_suid(pTHX_ char *validarg, char *scriptname, int fdscript)
 #endif
                || PerlProc_getuid() != PL_euid || PerlProc_geteuid() != PL_uid)
                Perl_croak(aTHX_ "Can't swap uid and euid");    /* really paranoid */
-           if (PerlLIO_stat(CopFILE(PL_curcop),&tmpstatbuf) < 0)
-               Perl_croak(aTHX_ "Permission denied");  /* testing full pathname here */
+           if (PerlLIO_stat(CopFILE(PL_curcop),&tmpstatbuf) < 0) {
+               errno = EPERM;
+               Perl_croak(aTHX_ "Permission denied\n");        /* testing full pathname here */
+           }
 #if defined(IAMSUID) && !defined(NO_NOSUID_CHECK)
-           if (fd_on_nosuid_fs(PerlIO_fileno(PL_rsfp)))
-               Perl_croak(aTHX_ "Permission denied");
+           if (fd_on_nosuid_fs(PerlIO_fileno(PL_rsfp))) {
+               errno = EPERM;
+               Perl_croak(aTHX_ "Permission denied\n");
+           }
 #endif
            if (tmpstatbuf.st_dev != PL_statbuf.st_dev ||
                tmpstatbuf.st_ino != PL_statbuf.st_ino) {
                (void)PerlIO_close(PL_rsfp);
+               errno = EPERM;
                Perl_croak(aTHX_ "Permission denied\n");
            }
            if (
@@ -3062,8 +3240,10 @@ S_validate_suid(pTHX_ char *validarg, char *scriptname, int fdscript)
 #endif /* HAS_SETREUID */
 #endif /* IAMSUID */
 
-       if (!S_ISREG(PL_statbuf.st_mode))
-           Perl_croak(aTHX_ "Permission denied");
+       if (!S_ISREG(PL_statbuf.st_mode)) {
+            errno = EPERM;
+           Perl_croak(aTHX_ "Permission denied\n");
+       }
        if (PL_statbuf.st_mode & S_IWOTH)
            Perl_croak(aTHX_ "Setuid/gid script is writable by world");
        PL_doswitches = FALSE;          /* -s is insecure in suid */
@@ -3094,16 +3274,18 @@ S_validate_suid(pTHX_ char *validarg, char *scriptname, int fdscript)
            PL_euid == PL_statbuf.st_uid)
            if (!PL_do_undump)
                Perl_croak(aTHX_ "YOU HAVEN'T DISABLED SET-ID SCRIPTS IN THE KERNEL YET!\n\
-FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
+FIX YOUR KERNEL, OR PUT A C WRAPPER AROUND THIS SCRIPT!\n");
 #endif /* IAMSUID */
 
        if (PL_euid) {  /* oops, we're not the setuid root perl */
            (void)PerlIO_close(PL_rsfp);
 #ifndef IAMSUID
            /* try again */
+           PERL_FPU_PRE_EXEC
            PerlProc_execv(Perl_form(aTHX_ "%s/sperl"PERL_FS_VER_FMT, BIN_EXP,
                                     (int)PERL_REVISION, (int)PERL_VERSION,
                                     (int)PERL_SUBVERSION), PL_origargv);
+           PERL_FPU_POST_EXEC
 #endif
            Perl_croak(aTHX_ "Can't do setuid\n");
        }
@@ -3169,8 +3351,10 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
        Perl_croak(aTHX_ "-P not allowed for setuid/setgid script\n");
     else if (fdscript >= 0)
        Perl_croak(aTHX_ "fd script not allowed in suidperl\n");
-    else
-       Perl_croak(aTHX_ "Script is not setuid/setgid in suidperl\n");
+    else {
+       errno = EPERM;
+       Perl_croak(aTHX_ "Permission denied\n");
+    }
 
     /* We absolutely must clear out any saved ids here, so we */
     /* exec the real perl, substituting fd script for scriptname. */
@@ -3178,16 +3362,20 @@ FIX YOUR KERNEL, PUT A C WRAPPER AROUND THIS SCRIPT, OR USE -u AND UNDUMP!\n");
     PerlIO_rewind(PL_rsfp);
     PerlLIO_lseek(PerlIO_fileno(PL_rsfp),(Off_t)0,0);  /* just in case rewind didn't */
     for (which = 1; PL_origargv[which] && PL_origargv[which] != scriptname; which++) ;
-    if (!PL_origargv[which])
-       Perl_croak(aTHX_ "Permission denied");
+    if (!PL_origargv[which]) {
+       errno = EPERM;
+       Perl_croak(aTHX_ "Permission denied\n");
+    }
     PL_origargv[which] = savepv(Perl_form(aTHX_ "/dev/fd/%d/%s",
                                  PerlIO_fileno(PL_rsfp), PL_origargv[which]));
 #if defined(HAS_FCNTL) && defined(F_SETFD)
     fcntl(PerlIO_fileno(PL_rsfp),F_SETFD,0);   /* ensure no close-on-exec */
 #endif
+    PERL_FPU_PRE_EXEC
     PerlProc_execv(Perl_form(aTHX_ "%s/perl"PERL_FS_VER_FMT, BIN_EXP,
                             (int)PERL_REVISION, (int)PERL_VERSION,
                             (int)PERL_SUBVERSION), PL_origargv);/* try again */
+    PERL_FPU_POST_EXEC
     Perl_croak(aTHX_ "Can't do setuid\n");
 #endif /* IAMSUID */
 #else /* !DOSUID */
@@ -3286,9 +3474,47 @@ 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));
 }
 
+/* This is used very early in the lifetime of the program,
+ * before even the options are parsed, so PL_tainting has
+ * not been initialized properly.  */
+bool
+Perl_doing_taint(int argc, char *argv[], char *envp[])
+{
+#ifndef PERL_IMPLICIT_SYS
+    /* If we have PERL_IMPLICIT_SYS we can't call getuid() et alia
+     * before we have an interpreter-- and the whole point of this
+     * function is to be called at such an early stage.  If you are on
+     * a system with PERL_IMPLICIT_SYS but you do have a concept of
+     * "tainted because running with altered effective ids', you'll
+     * have to add your own checks somewhere in here.  The two most
+     * known samples of 'implicitness' are Win32 and NetWare, neither
+     * of which has much of concept of 'uids'. */
+    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;
+#endif /* !PERL_IMPLICIT_SYS */
+    /* This is a really primitive check; environment gets 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;
+}
+
 STATIC void
 S_forbid_setid(pTHX_ char *s)
 {
@@ -3304,19 +3530,19 @@ Perl_init_debugger(pTHX)
     HV *ostash = PL_curstash;
 
     PL_curstash = PL_debstash;
-    PL_dbargs = GvAV(gv_AVadd((gv_fetchpv("args", GV_ADDMULTI, SVt_PVAV))));
+    PL_dbargs = GvAV(gv_AVadd((gv_fetchpv("DB::args", GV_ADDMULTI, SVt_PVAV))));
     AvREAL_off(PL_dbargs);
-    PL_DBgv = gv_fetchpv("DB", GV_ADDMULTI, SVt_PVGV);
-    PL_DBline = gv_fetchpv("dbline", GV_ADDMULTI, SVt_PVAV);
-    PL_DBsub = gv_HVadd(gv_fetchpv("sub", GV_ADDMULTI, SVt_PVHV));
+    PL_DBgv = gv_fetchpv("DB::DB", GV_ADDMULTI, SVt_PVGV);
+    PL_DBline = gv_fetchpv("DB::dbline", GV_ADDMULTI, SVt_PVAV);
+    PL_DBsub = gv_HVadd(gv_fetchpv("DB::sub", GV_ADDMULTI, SVt_PVHV));
     sv_upgrade(GvSV(PL_DBsub), SVt_IV);        /* IVX accessed if PERLDB_SUB_NN */
-    PL_DBsingle = GvSV((gv_fetchpv("single", GV_ADDMULTI, SVt_PV)));
+    PL_DBsingle = GvSV((gv_fetchpv("DB::single", GV_ADDMULTI, SVt_PV)));
     sv_setiv(PL_DBsingle, 0);
-    PL_DBtrace = GvSV((gv_fetchpv("trace", GV_ADDMULTI, SVt_PV)));
+    PL_DBtrace = GvSV((gv_fetchpv("DB::trace", GV_ADDMULTI, SVt_PV)));
     sv_setiv(PL_DBtrace, 0);
-    PL_DBsignal = GvSV((gv_fetchpv("signal", GV_ADDMULTI, SVt_PV)));
+    PL_DBsignal = GvSV((gv_fetchpv("DB::signal", GV_ADDMULTI, SVt_PV)));
     sv_setiv(PL_DBsignal, 0);
-    PL_DBassertion = GvSV((gv_fetchpv("assertion", GV_ADDMULTI, SVt_PV)));
+    PL_DBassertion = GvSV((gv_fetchpv("DB::assertion", GV_ADDMULTI, SVt_PV)));
     sv_setiv(PL_DBassertion, 0);
     PL_curstash = ostash;
 }
@@ -3556,6 +3782,7 @@ S_init_postdump_symbols(pTHX_ register int argc, register char **argv, register
        GvMULTI_on(PL_envgv);
        hv = GvHVn(PL_envgv);
        hv_magic(hv, Nullgv, PERL_MAGIC_env);
+#ifndef PERL_MICRO
 #ifdef USE_ENVIRON_ARRAY
        /* Note that if the supplied env parameter is actually a copy
           of the global environ then it may now point to free'd memory
@@ -3576,7 +3803,7 @@ S_init_postdump_symbols(pTHX_ register int argc, register char **argv, register
          for (; *env; env++) {
            if (!(s = strchr(*env,'=')))
                continue;
-#if defined(MSDOS)
+#if defined(MSDOS) && !defined(DJGPP)
            *s = '\0';
            (void)strupr(*env);
            *s = '=';
@@ -3587,6 +3814,7 @@ S_init_postdump_symbols(pTHX_ register int argc, register char **argv, register
                mg_set(sv);
          }
 #endif /* USE_ENVIRON_ARRAY */
+#endif /* !PERL_MICRO */
     }
     TAINT_NOT;
     if ((tmpgv = gv_fetchpv("$",TRUE, SVt_PV))) {