[perl #8262] //g loops infinitely on tainted data
[p5sagit/p5-mst-13.2.git] / toke.c
diff --git a/toke.c b/toke.c
index 0ec4e9f..1b07e56 100644 (file)
--- a/toke.c
+++ b/toke.c
 #define yychar (*PL_yycharp)
 #define yylval (*PL_yylvalp)
 
-static const char ident_too_long[] =
-  "Identifier too long";
-static const char c_without_g[] =
-  "Use of /c modifier is meaningless without /g";
-static const char c_in_subst[] =
-  "Use of /c modifier is meaningless in s///";
+static const char ident_too_long[] = "Identifier too long";
 
 static void restore_rsfp(pTHX_ void *f);
 #ifndef PERL_NO_UTF16_FILTER
@@ -224,6 +219,7 @@ static struct debug_tokens { const int token, type; const char *name; }
     { BITOROP,         TOKENTYPE_OPNUM,        "BITOROP" },
     { COLONATTR,       TOKENTYPE_NONE,         "COLONATTR" },
     { CONTINUE,                TOKENTYPE_NONE,         "CONTINUE" },
+    { DEFAULT,         TOKENTYPE_NONE,         "DEFAULT" },
     { DO,              TOKENTYPE_NONE,         "DO" },
     { DOLSHARP,                TOKENTYPE_NONE,         "DOLSHARP" },
     { DORDOR,          TOKENTYPE_NONE,         "DORDOR" },
@@ -239,6 +235,7 @@ static struct debug_tokens { const int token, type; const char *name; }
     { FUNC0SUB,                TOKENTYPE_OPVAL,        "FUNC0SUB" },
     { FUNC1,           TOKENTYPE_OPNUM,        "FUNC1" },
     { FUNCMETH,                TOKENTYPE_OPVAL,        "FUNCMETH" },
+    { GIVEN,           TOKENTYPE_IVAL,         "GIVEN" },
     { HASHBRACK,       TOKENTYPE_NONE,         "HASHBRACK" },
     { IF,              TOKENTYPE_IVAL,         "IF" },
     { LABEL,           TOKENTYPE_PVAL,         "LABEL" },
@@ -274,6 +271,7 @@ static struct debug_tokens { const int token, type; const char *name; }
     { UNLESS,          TOKENTYPE_IVAL,         "UNLESS" },
     { UNTIL,           TOKENTYPE_IVAL,         "UNTIL" },
     { USE,             TOKENTYPE_IVAL,         "USE" },
+    { WHEN,            TOKENTYPE_IVAL,         "WHEN" },
     { WHILE,           TOKENTYPE_IVAL,         "WHILE" },
     { WORD,            TOKENTYPE_OPVAL,        "WORD" },
     { 0,               TOKENTYPE_NONE,         0 }
@@ -459,6 +457,23 @@ S_missingterm(pTHX_ char *s)
     Perl_croak(aTHX_ "Can't find string terminator %c%s%c anywhere before EOF",q,s,q);
 }
 
+#define FEATURE_IS_ENABLED(name, namelen)                              \
+       ((0 != (PL_hints & HINT_LOCALIZE_HH))                           \
+       && feature_is_enabled(name, namelen))
+/*
+ * S_feature_is_enabled
+ * Check whether the named feature is enabled.
+ */
+STATIC bool
+S_feature_is_enabled(pTHX_ char *name, STRLEN namelen)
+{
+    HV * const hinthv = GvHV(PL_hintgv);
+    char he_name[32] = "feature_";
+    (void) strncpy(&he_name[8], name, 24);
+    
+    return (hinthv && hv_exists(hinthv, he_name, 8 + namelen));
+}
+
 /*
  * Perl_deprecate
  */
@@ -681,13 +696,13 @@ S_incline(pTHX_ char *s)
     if (t - s > 0) {
 #ifndef USE_ITHREADS
        const char * const cf = CopFILE(PL_curcop);
-       if (cf && strlen(cf) > 7 && strnEQ(cf, "(eval ", 6)) {
+       STRLEN tmplen = cf ? strlen(cf) : 0;
+       if (tmplen > 7 && strnEQ(cf, "(eval ", 6)) {
            /* must copy *{"::_<(eval N)[oldfilename:L]"}
             * to *{"::_<newfilename"} */
            char smallbuf[256], smallbuf2[256];
            char *tmpbuf, *tmpbuf2;
            GV **gvp, *gv2;
-           STRLEN tmplen = strlen(cf);
            STRLEN tmplen2 = strlen(s);
            if (tmplen + 3 < sizeof smallbuf)
                tmpbuf = smallbuf;
@@ -2651,10 +2666,9 @@ Perl_yylex(pTHX)
            PL_last_uni = 0;
            PL_last_lop = 0;
            if (PL_lex_brackets) {
-               if (PL_lex_formbrack)
-                   yyerror("Format not terminated");
-                else
-                   yyerror("Missing right curly or square bracket");
+               yyerror(PL_lex_formbrack
+                   ? "Format not terminated"
+                   : "Missing right curly or square bracket");
            }
             DEBUG_T( { PerlIO_printf(Perl_debug_log,
                         "### Tokener got EOF\n");
@@ -3201,6 +3215,13 @@ Perl_yylex(pTHX)
        PL_lex_brackets++;
        /* FALL THROUGH */
     case '~':
+       if (s[1] == '~'
+       && (PL_expect == XOPERATOR || PL_expect == XTERMORDORDOR)
+       && FEATURE_IS_ENABLED("~~", 2))
+       {
+           s += 2;
+           Eop(OP_SMARTMATCH);
+       }
     case ',':
        tmp = *s++;
        OPERATOR(tmp);
@@ -3319,11 +3340,9 @@ Perl_yylex(pTHX)
                   context messages from yyerror().
                 */
                PL_bufptr = s;
-               if (!*s)
-                   yyerror("Unterminated attribute list");
-               else
-                   yyerror(Perl_form(aTHX_ "Invalid separator character %c%c%c in attribute list",
-                                     q, *s, q));
+               yyerror( *s
+                   ? Perl_form(aTHX_ "Invalid separator character %c%c%c in attribute list", q, *s, q)
+                   : "Unterminated attribute list" );
                if (attrs)
                    op_free(attrs);
                OPERATOR(':');
@@ -4560,11 +4579,31 @@ Perl_yylex(pTHX)
        case KEY_bless:
            LOP(OP_BLESS,XTERM);
 
+       case KEY_break:
+           FUN0(OP_BREAK);
+
        case KEY_chop:
            UNI(OP_CHOP);
 
        case KEY_continue:
+           /* When 'use switch' is in effect, continue has a dual
+              life as a control operator. */
+           {
+               if (!FEATURE_IS_ENABLED("switch", 6))
+                   PREBLOCK(CONTINUE);
+               else {
+                   /* We have to disambiguate the two senses of
+                     "continue". If the next token is a '{' then
+                     treat it as the start of a continue block;
+                     otherwise treat it as a control operator.
+                    */
+                   s = skipspace(s);
+                   if (*s == '{')
            PREBLOCK(CONTINUE);
+                   else
+                       FUN0(OP_CONTINUE);
+               }
+           }
 
        case KEY_chdir:
            (void)gv_fetchpv("ENV",TRUE, SVt_PVHV);     /* may use HOME */
@@ -4609,6 +4648,9 @@ Perl_yylex(pTHX)
        case KEY_chroot:
            UNI(OP_CHROOT);
 
+       case KEY_default:
+           PREBLOCK(DEFAULT);
+
        case KEY_do:
            s = skipspace(s);
            if (*s == '{')
@@ -4831,6 +4873,10 @@ Perl_yylex(pTHX)
        case KEY_getlogin:
            FUN0(OP_GETLOGIN);
 
+       case KEY_given:
+           yylval.ival = CopLINE(PL_curcop);
+           OPERATOR(GIVEN);
+
        case KEY_glob:
            set_csh();
            LOP(OP_GLOB,XTERM);
@@ -5188,6 +5234,10 @@ Perl_yylex(pTHX)
            else
                TOKEN(1);       /* force error */
 
+       case KEY_say:
+           checkcomma(s,PL_tokenbuf,"filehandle");
+           LOP(OP_SAY,XREF);
+
        case KEY_chomp:
            UNI(OP_CHOMP);
        
@@ -5503,6 +5553,10 @@ Perl_yylex(pTHX)
        case KEY_vec:
            LOP(OP_VEC,XTERM);
 
+       case KEY_when:
+           yylval.ival = CopLINE(PL_curcop);
+           OPERATOR(WHEN);
+
        case KEY_while:
            yylval.ival = CopLINE(PL_curcop);
            OPERATOR(WHILE);
@@ -5669,10 +5723,26 @@ S_pending_ident(pTHX)
     /* build ops for a bareword */
     yylval.opval = (OP*)newSVOP(OP_CONST, 0, newSVpv(PL_tokenbuf+1, 0));
     yylval.opval->op_private = OPpCONST_ENTERED;
-    gv_fetchpv(PL_tokenbuf+1, PL_in_eval ? (GV_ADDMULTI | GV_ADDINEVAL) : TRUE,
-               ((PL_tokenbuf[0] == '$') ? SVt_PV
-                : (PL_tokenbuf[0] == '@') ? SVt_PVAV
-                : SVt_PVHV));
+    gv_fetchpv(
+           PL_tokenbuf+1,
+           PL_in_eval
+               ? (GV_ADDMULTI | GV_ADDINEVAL)
+               /* If the identifier refers to a stash, don't autovivify it.
+                * Change 24660 had the side effect of causing symbol table
+                * hashes to always be defined, even if they were freshly
+                * created and the only reference in the entire program was
+                * the single statement with the defined %foo::bar:: test.
+                * It appears that all code in the wild doing this actually
+                * wants to know whether sub-packages have been loaded, so
+                * by avoiding auto-vivifying symbol tables, we ensure that
+                * defined %foo::bar:: continues to be false, and the existing
+                * tests still give the expected answers, even though what
+                * they're actually testing has now changed subtly.
+                */
+               : !(*PL_tokenbuf == '%' && *(d = PL_tokenbuf + strlen(PL_tokenbuf) - 1) == ':' && d[-1] == ':'),
+           ((PL_tokenbuf[0] == '$') ? SVt_PV
+            : (PL_tokenbuf[0] == '@') ? SVt_PVAV
+            : SVt_PVHV));
     return WORD;
 }
 
@@ -5863,7 +5933,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 3: /* 28 tokens of length 3 */
+    case 3: /* 29 tokens of length 3 */
       switch (name[0])
       {
         case 'E':
@@ -6088,6 +6158,14 @@ Perl_keyword (pTHX_ const char *name, I32 len)
         case 's':
           switch (name[1])
           {
+            case 'a':
+              if (name[2] == 'y')
+              {                                   /* say        */
+                return (FEATURE_IS_ENABLED("say", 3) ? -KEY_say : 0);
+              }
+
+              goto unknown;
+
             case 'i':
               if (name[2] == 'n')
               {                                   /* sin        */
@@ -6148,7 +6226,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 4: /* 40 tokens of length 4 */
+    case 4: /* 41 tokens of length 4 */
       switch (name[0])
       {
         case 'C':
@@ -6578,8 +6656,9 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           }
 
         case 'w':
-          if (name[1] == 'a')
+          switch (name[1])
           {
+            case 'a':
             switch (name[2])
             {
               case 'i':
@@ -6601,6 +6680,12 @@ Perl_keyword (pTHX_ const char *name, I32 len)
               default:
                 goto unknown;
             }
+
+            case 'h':
+              if (name[2] == 'e' &&
+                  name[3] == 'n')
+              {                                   /* when       */
+                return (FEATURE_IS_ENABLED("switch", 6) ? KEY_when : 0);
           }
 
           goto unknown;
@@ -6609,7 +6694,11 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 5: /* 36 tokens of length 5 */
+        default:
+          goto unknown;
+      }
+
+    case 5: /* 38 tokens of length 5 */
       switch (name[0])
       {
         case 'B':
@@ -6662,8 +6751,10 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           }
 
         case 'b':
-          if (name[1] == 'l' &&
-              name[2] == 'e' &&
+          switch (name[1])
+          {
+            case 'l':
+              if (name[2] == 'e' &&
               name[3] == 's' &&
               name[4] == 's')
           {                                       /* bless      */
@@ -6672,6 +6763,20 @@ Perl_keyword (pTHX_ const char *name, I32 len)
 
           goto unknown;
 
+            case 'r':
+              if (name[2] == 'e' &&
+                  name[3] == 'a' &&
+                  name[4] == 'k')
+              {                                   /* break      */
+                return (FEATURE_IS_ENABLED("switch", 6) ? -KEY_break : 0);
+              }
+
+              goto unknown;
+
+            default:
+              goto unknown;
+          }
+
         case 'c':
           switch (name[1])
           {
@@ -6785,6 +6890,17 @@ Perl_keyword (pTHX_ const char *name, I32 len)
               goto unknown;
           }
 
+        case 'g':
+          if (name[1] == 'i' &&
+              name[2] == 'v' &&
+              name[3] == 'e' &&
+              name[4] == 'n')
+          {                                       /* given      */
+            return (FEATURE_IS_ENABLED("switch", 6) ? KEY_given : 0);
+          }
+
+          goto unknown;
+
         case 'i':
           switch (name[1])
           {
@@ -7521,7 +7637,7 @@ Perl_keyword (pTHX_ const char *name, I32 len)
           goto unknown;
       }
 
-    case 7: /* 28 tokens of length 7 */
+    case 7: /* 29 tokens of length 7 */
       switch (name[0])
       {
         case 'D':
@@ -7592,9 +7708,22 @@ Perl_keyword (pTHX_ const char *name, I32 len)
               goto unknown;
 
             case 'e':
-              if (name[2] == 'f' &&
-                  name[3] == 'i' &&
-                  name[4] == 'n' &&
+              if (name[2] == 'f')
+              {
+                switch (name[3])
+                {
+                  case 'a':
+                    if (name[4] == 'u' &&
+                        name[5] == 'l' &&
+                        name[6] == 't')
+                    {                             /* default    */
+                      return (FEATURE_IS_ENABLED("switch", 6) ? KEY_default : 0);
+                    }
+
+                    goto unknown;
+
+                  case 'i':
+                    if (name[4] == 'n' &&
                   name[5] == 'e' &&
                   name[6] == 'd')
               {                                   /* defined    */
@@ -7606,6 +7735,13 @@ Perl_keyword (pTHX_ const char *name, I32 len)
             default:
               goto unknown;
           }
+              }
+
+              goto unknown;
+
+            default:
+              goto unknown;
+          }
 
         case 'f':
           if (name[1] == 'o' &&
@@ -9012,7 +9148,7 @@ S_checkcomma(pTHX_ register char *s, const char *name, const char *what)
        while (s < PL_bufend && isSPACE(*s))
            s++;
        if (*s == ',') {
-           int kw;
+           I32 kw;
            *s = '\0'; /* XXX If we didn't do this, we could const a lot of toke.c */
            kw = keyword(w, s - w) || get_cv(w, FALSE) != 0;
            *s = ',';
@@ -9367,7 +9503,7 @@ S_scan_pat(pTHX_ char *start, I32 type)
     if ((pm->op_pmflags & PMf_CONTINUE) && !(pm->op_pmflags & PMf_GLOBAL)
            && ckWARN(WARN_REGEXP))
     {
-        Perl_warner(aTHX_ packWARN(WARN_REGEXP), c_without_g);
+        Perl_warner(aTHX_ packWARN(WARN_REGEXP), "Use of /c modifier is meaningless without /g" );
     }
 
     pm->op_pmpermflags = pm->op_pmflags;
@@ -9419,10 +9555,8 @@ S_scan_subst(pTHX_ char *start)
            break;
     }
 
-    /* /c is not meaningful with s/// */
-    if ((pm->op_pmflags & PMf_CONTINUE) && ckWARN(WARN_REGEXP))
-    {
-        Perl_warner(aTHX_ packWARN(WARN_REGEXP), c_in_subst);
+    if ((pm->op_pmflags & PMf_CONTINUE) && ckWARN(WARN_REGEXP)) {
+        Perl_warner(aTHX_ packWARN(WARN_REGEXP), "Use of /c modifier is meaningless in s///" );
     }
 
     if (es) {
@@ -10823,7 +10957,7 @@ Perl_yyerror(pTHX_ const char *s)
             OutCopFILE(PL_curcop));
     }
     PL_in_my = 0;
-    PL_in_my_stash = Nullhv;
+    PL_in_my_stash = NULL;
     return 0;
 }
 #ifdef __SC__
@@ -10932,7 +11066,7 @@ S_swallow_bom(pTHX_ U8 *s)
 static void
 restore_rsfp(pTHX_ void *f)
 {
-    PerlIO *fp = (PerlIO*)f;
+    PerlIO * const fp = (PerlIO*)f;
 
     if (PL_rsfp == PerlIO_stdin())
        PerlIO_clearerr(PL_rsfp);
@@ -11020,16 +11154,15 @@ Perl_scan_vstring(pTHX_ const char *s, SV *sv)
     }
 
     if (!isALPHA(*pos)) {
-       UV rev;
        U8 tmpbuf[UTF8_MAXBYTES+1];
-       U8 *tmpend;
 
        if (*s == 'v') s++;  /* get past 'v' */
 
        sv_setpvn(sv, "", 0);
 
        for (;;) {
-           rev = 0;
+           U8 *tmpend;
+           UV rev = 0;
            {
                /* this is atoi() that tolerates underscores */
                const char *end = pos;