In perl.git, the branch blead has been updated

<https://perl5.git.perl.org/perl.git/commitdiff/e40cca748f05c81e1929ed625407afbe7c79d4dd?hp=6256cf2c2cee30277e34d38416070f9ec671c989>

- Log -----------------------------------------------------------------
commit e40cca748f05c81e1929ed625407afbe7c79d4dd
Author: David Mitchell <da...@iabyn.com>
Date:   Mon Mar 25 20:13:30 2019 +0000

    fix a leak with indented heredocs
    
    With something like
    
       |print <<~EOF;
       | some data
       |   EOF
    
    it croaks (as it should) with "Indentation ... doesn't match delimiter",
    but in that case it leaks the recently malloc()d 'indent' buffer.
    
    The fix is simple.  I've also fixed by code inspection where the code
    does 'goto interminable', although I didn't try to reproduce the conditions
    where the goto might occur.

commit 3c2fc529eb398c7f2f197abd633720bd6bb627fc
Author: David Mitchell <da...@iabyn.com>
Date:   Mon Mar 25 19:44:57 2019 +0000

    reformat S_scan_heredoc()
    
    The indentation was inconsistent and confusing.
    
    Reindent, add blank lines where appropriate, and change this code
    comment: "(Closing '}' here to balance"  to '<<}', since vim is far too
    clever for its own good these days in terms of using '%' to bounce
    between brace pairs.
    
    Should be no functional changes.

commit d44742f81c5295e9a7ce437cb55c1b56f4c7fc68
Author: David Mitchell <da...@iabyn.com>
Date:   Mon Mar 25 19:14:43 2019 +0000

    S_scan_heredoc(): add cosmetic braces
    
    add braces round a single-statement 'if' clause which contains a while
    loop and spans several lines.
    
    Should be functionally equivalent, but less visually confusing.

commit 1113f30d91f662c876a07b357666f02f04a30a75
Author: David Mitchell <da...@iabyn.com>
Date:   Mon Mar 25 17:18:58 2019 +0000

    fix leak with local ${^WARNING_BITS} = ...
    
    When restoring the old value, need to free the current value first.
    Can be reproduced with
    
        {
            local ${^WARNING_BITS} = 'swit';
        }
    
    when run under ASan or similar.
    An equivalent test already exists in t/op/leaky-magic.t.

-----------------------------------------------------------------------

Summary of changes:
 mg.c   |   2 +
 toke.c | 323 ++++++++++++++++++++++++++++++++++++-----------------------------
 2 files changed, 182 insertions(+), 143 deletions(-)

diff --git a/mg.c b/mg.c
index b022d63442..320e2d39bb 100644
--- a/mg.c
+++ b/mg.c
@@ -2916,6 +2916,8 @@ Perl_magic_set(pTHX_ SV *sv, MAGIC *mg)
        else if (strEQ(mg->mg_ptr+1, "ARNING_BITS")) {
            if ( ! (PL_dowarn & G_WARN_ALL_MASK)) {
                if (!SvPOK(sv)) {
+                    if (!specialWARN(PL_compiling.cop_warnings))
+                        PerlMemShared_free(PL_compiling.cop_warnings);
                    PL_compiling.cop_warnings = pWARN_STD;
                    break;
                }
diff --git a/toke.c b/toke.c
index 9bed338ecc..8b0c655893 100644
--- a/toke.c
+++ b/toke.c
@@ -10026,12 +10026,15 @@ S_scan_heredoc(pTHX_ char *s)
     e = PL_tokenbuf + sizeof PL_tokenbuf - 1;
     *PL_tokenbuf = '\n';
     peek = s;
+
     if (*peek == '~') {
        indented = TRUE;
        peek++; s++;
     }
+
     while (SPACE_OR_TAB(*peek))
        peek++;
+
     if (*peek == '`' || *peek == '\'' || *peek =='"') {
        s = peek;
        term = *s++;
@@ -10047,19 +10050,25 @@ S_scan_heredoc(pTHX_ char *s)
            s++, term = '\'';
        else
            term = '"';
+
        if (! isWORDCHAR_lazy_if_safe(s, PL_bufend, UTF))
            Perl_croak(aTHX_ "Use of bare << to mean <<\"\" is forbidden");
+
        peek = s;
+
         while (isWORDCHAR_lazy_if_safe(peek, PL_bufend, UTF)) {
            peek += UTF ? UTF8SKIP(peek) : 1;
        }
+
        len = (peek - s >= e - d) ? (e - d) : (peek - s);
        Copy(s, d, len, char);
        s += len;
        d += len;
     }
+
     if (d >= PL_tokenbuf + sizeof PL_tokenbuf - 1)
        Perl_croak(aTHX_ "Delimiter for here document is too long");
+
     *d++ = '\n';
     *d = '\0';
     len = d - PL_tokenbuf;
@@ -10102,6 +10111,7 @@ S_scan_heredoc(pTHX_ char *s)
 
     PL_multi_start = origline + 1 + PL_parser->herelines;
     PL_multi_open = PL_multi_close = '<';
+
     /* inside a string eval or quote-like operator */
     if (!infile || PL_lex_inwhat) {
        SV *linestr;
@@ -10112,43 +10122,47 @@ S_scan_heredoc(pTHX_ char *s)
           entered.  But we need them set here. */
        shared->ls_bufptr  = s;
        shared->ls_linestr = PL_linestr;
-       if (PL_lex_inwhat)
-         /* Look for a newline.  If the current buffer does not have one,
-            peek into the line buffer of the parent lexing scope, going
-            up as many levels as necessary to find one with a newline
-            after bufptr.
-          */
-         while (!(s = (char *)memchr(
-                   (void *)shared->ls_bufptr, '\n',
-                   SvEND(shared->ls_linestr)-shared->ls_bufptr
-               ))) {
-           shared = shared->ls_prev;
-           /* shared is only null if we have gone beyond the outermost
-              lexing scope.  In a file, we will have broken out of the
-              loop in the previous iteration.  In an eval, the string buf-
-              fer ends with "\n;", so the while condition above will have
-              evaluated to false.  So shared can never be null.  Or so you
-              might think.  Odd syntax errors like s;@{<<; can gobble up
-              the implicit semicolon at the end of a flie, causing the
-              file handle to be closed even when we are not in a string
-              eval.  So shared may be null in that case.
-               (Closing '}' here to balance the earlier open brace for
-               editors that look for matched pairs.) */
-           if (UNLIKELY(!shared))
-               goto interminable;
-           /* A LEXSHARED struct with a null ls_prev pointer is the outer-
-              most lexing scope.  In a file, shared->ls_linestr at that
-              level is just one line, so there is no body to steal. */
-           if (infile && !shared->ls_prev) {
-               s = olds;
-               goto streaming;
-           }
-         }
+
+        if (PL_lex_inwhat) {
+            /* Look for a newline.  If the current buffer does not have one,
+             peek into the line buffer of the parent lexing scope, going
+             up as many levels as necessary to find one with a newline
+             after bufptr.
+            */
+           while (!(s = (char *)memchr(
+                                (void *)shared->ls_bufptr, '\n',
+                                SvEND(shared->ls_linestr)-shared->ls_bufptr
+               )))
+            {
+                shared = shared->ls_prev;
+                /* shared is only null if we have gone beyond the outermost
+                   lexing scope.  In a file, we will have broken out of the
+                   loop in the previous iteration.  In an eval, the string buf-
+                   fer ends with "\n;", so the while condition above will have
+                   evaluated to false.  So shared can never be null.  Or so you
+                   might think.  Odd syntax errors like s;@{<<; can gobble up
+                   the implicit semicolon at the end of a flie, causing the
+                   file handle to be closed even when we are not in a string
+                   eval.  So shared may be null in that case.
+                   (Closing '>>}' here to balance the earlier open brace for
+                   editors that look for matched pairs.) */
+                if (UNLIKELY(!shared))
+                    goto interminable;
+                /* A LEXSHARED struct with a null ls_prev pointer is the outer-
+                   most lexing scope.  In a file, shared->ls_linestr at that
+                   level is just one line, so there is no body to steal. */
+                if (infile && !shared->ls_prev) {
+                    s = olds;
+                    goto streaming;
+                }
+            }
+        }
        else {  /* eval or we've already hit EOF */
            s = (char*)memchr((void*)s, '\n', PL_bufend - s);
            if (!s)
                 goto interminable;
        }
+
        linestr = shared->ls_linestr;
        bufend = SvEND(linestr);
        d = s;
@@ -10168,7 +10182,6 @@ S_scan_heredoc(pTHX_ char *s)
                        if (! SPACE_OR_TAB(*backup)) {
                            break;
                        }
-
                        indent_len++;
                    }
 
@@ -10183,7 +10196,8 @@ S_scan_heredoc(pTHX_ char *s)
                    }
                }
            }
-       } else {
+       }
+        else {
            while (s < bufend - len + 1
                   && memNE(s,PL_tokenbuf,len) )
            {
@@ -10195,6 +10209,7 @@ S_scan_heredoc(pTHX_ char *s)
        if (s >= bufend - len + 1) {
            goto interminable;
        }
+
        sv_setpvn(tmpstr,d+1,s-d);
        s += len - 1;
        /* the preceding stmt passes a newline */
@@ -10217,6 +10232,7 @@ S_scan_heredoc(pTHX_ char *s)
                                bufend - shared->re_eval_start);
            shared->re_eval_start -= s-d;
        }
+
        if (cxstack_ix >= 0
             && CxTYPE(cx) == CXt_EVAL
             && CxOLD_OP_TYPE(cx) == OP_ENTEREVAL
@@ -10225,126 +10241,139 @@ S_scan_heredoc(pTHX_ char *s)
            cx->blk_eval.cur_text = newSVsv(linestr);
            cx->blk_u16 |= 0x40; /* indicate cur_text is ref counted */
        }
+
        /* Copy everything from s onwards back to d. */
        Move(s,d,bufend-s + 1,char);
        SvCUR_set(linestr, SvCUR(linestr) - (s-d));
        /* Setting PL_bufend only applies when we have not dug deeper
           into other scopes, because sublex_done sets PL_bufend to
           SvEND(PL_linestr). */
-       if (shared == PL_parser->lex_shared) PL_bufend = SvEND(linestr);
+       if (shared == PL_parser->lex_shared)
+            PL_bufend = SvEND(linestr);
        s = olds;
     }
-    else
-    {
-      SV *linestr_save;
-      char *oldbufptr_save;
-      char *oldoldbufptr_save;
-     streaming:
-      SvPVCLEAR(tmpstr);   /* avoid "uninitialized" warning */
-      term = PL_tokenbuf[1];
-      len--;
-      linestr_save = PL_linestr; /* must restore this afterwards */
-      d = s;                    /* and this */
-      oldbufptr_save = PL_oldbufptr;
-      oldoldbufptr_save = PL_oldoldbufptr;
-      PL_linestr = newSVpvs("");
-      PL_bufend = SvPVX(PL_linestr);
-      while (1) {
-       PL_bufptr = PL_bufend;
-       CopLINE_set(PL_curcop,
-                   origline + 1 + PL_parser->herelines);
-       if (!lex_next_chunk(LEX_NO_TERM)
-        && (!SvCUR(tmpstr) || SvEND(tmpstr)[-1] != '\n')) {
-           /* Simply freeing linestr_save might seem simpler here, as it
-              does not matter what PL_linestr points to, since we are
-              about to croak; but in a quote-like op, linestr_save
-              will have been prospectively freed already, via
-              SAVEFREESV(PL_linestr) in sublex_push, so it’s easier to
-              restore PL_linestr. */
-           SvREFCNT_dec_NN(PL_linestr);
-           PL_linestr = linestr_save;
-            PL_oldbufptr = oldbufptr_save;
-            PL_oldoldbufptr = oldoldbufptr_save;
-           goto interminable;
-       }
-       CopLINE_set(PL_curcop, origline);
-       if (!SvCUR(PL_linestr) || PL_bufend[-1] != '\n') {
-            s = lex_grow_linestr(SvLEN(PL_linestr) + 3);
-            /* ^That should be enough to avoid this needing to grow:  */
-           sv_catpvs(PL_linestr, "\n\0");
-            assert(s == SvPVX(PL_linestr));
-            PL_bufend = SvEND(PL_linestr);
-       }
-       s = PL_bufptr;
-       PL_parser->herelines++;
-       PL_last_lop = PL_last_uni = NULL;
+    else {
+        SV *linestr_save;
+        char *oldbufptr_save;
+        char *oldoldbufptr_save;
+      streaming:
+        SvPVCLEAR(tmpstr);   /* avoid "uninitialized" warning */
+        term = PL_tokenbuf[1];
+        len--;
+        linestr_save = PL_linestr; /* must restore this afterwards */
+        d = s;                  /* and this */
+        oldbufptr_save = PL_oldbufptr;
+        oldoldbufptr_save = PL_oldoldbufptr;
+        PL_linestr = newSVpvs("");
+        PL_bufend = SvPVX(PL_linestr);
+
+        while (1) {
+            PL_bufptr = PL_bufend;
+            CopLINE_set(PL_curcop,
+                        origline + 1 + PL_parser->herelines);
+
+            if (   !lex_next_chunk(LEX_NO_TERM)
+                && (!SvCUR(tmpstr) || SvEND(tmpstr)[-1] != '\n'))
+            {
+                /* Simply freeing linestr_save might seem simpler here, as it
+                   does not matter what PL_linestr points to, since we are
+                   about to croak; but in a quote-like op, linestr_save
+                   will have been prospectively freed already, via
+                   SAVEFREESV(PL_linestr) in sublex_push, so it’s easier to
+                   restore PL_linestr. */
+                SvREFCNT_dec_NN(PL_linestr);
+                PL_linestr = linestr_save;
+                PL_oldbufptr = oldbufptr_save;
+                PL_oldoldbufptr = oldoldbufptr_save;
+                goto interminable;
+            }
+
+            CopLINE_set(PL_curcop, origline);
+
+            if (!SvCUR(PL_linestr) || PL_bufend[-1] != '\n') {
+                s = lex_grow_linestr(SvLEN(PL_linestr) + 3);
+                /* ^That should be enough to avoid this needing to grow:  */
+                sv_catpvs(PL_linestr, "\n\0");
+                assert(s == SvPVX(PL_linestr));
+                PL_bufend = SvEND(PL_linestr);
+            }
+
+            s = PL_bufptr;
+            PL_parser->herelines++;
+            PL_last_lop = PL_last_uni = NULL;
+
 #ifndef PERL_STRICT_CR
-       if (PL_bufend - PL_linestart >= 2) {
-           if (   (PL_bufend[-2] == '\r' && PL_bufend[-1] == '\n')
-                || (PL_bufend[-2] == '\n' && PL_bufend[-1] == '\r'))
-           {
-               PL_bufend[-2] = '\n';
-               PL_bufend--;
-               SvCUR_set(PL_linestr, PL_bufend - SvPVX_const(PL_linestr));
-           }
-           else if (PL_bufend[-1] == '\r')
-               PL_bufend[-1] = '\n';
-       }
-       else if (PL_bufend - PL_linestart == 1 && PL_bufend[-1] == '\r')
-           PL_bufend[-1] = '\n';
+            if (PL_bufend - PL_linestart >= 2) {
+                if (   (PL_bufend[-2] == '\r' && PL_bufend[-1] == '\n')
+                    || (PL_bufend[-2] == '\n' && PL_bufend[-1] == '\r'))
+                {
+                    PL_bufend[-2] = '\n';
+                    PL_bufend--;
+                    SvCUR_set(PL_linestr, PL_bufend - SvPVX_const(PL_linestr));
+                }
+                else if (PL_bufend[-1] == '\r')
+                    PL_bufend[-1] = '\n';
+            }
+            else if (PL_bufend - PL_linestart == 1 && PL_bufend[-1] == '\r')
+                PL_bufend[-1] = '\n';
 #endif
-       if (indented && (PL_bufend-s) >= len) {
-           char * found = ninstr(s, PL_bufend, (PL_tokenbuf + 1), (PL_tokenbuf 
+1 + len));
 
-           if (found) {
-               char *backup = found;
-               indent_len = 0;
+            if (indented && (PL_bufend-s) >= len) {
+                char * found = ninstr(s, PL_bufend, (PL_tokenbuf + 1), 
(PL_tokenbuf +1 + len));
 
-               /* Only valid if it's preceded by whitespace only */
-               while (backup != s && --backup >= s) {
-                   if (! SPACE_OR_TAB(*backup)) {
-                       break;
-                   }
-                   indent_len++;
-               }
+                if (found) {
+                    char *backup = found;
+                    indent_len = 0;
 
-               /* All whitespace or none! */
-               if (backup == found || SPACE_OR_TAB(*backup)) {
-                   Newx(indent, indent_len + 1, char);
-                   memcpy(indent, backup, indent_len);
-                   indent[indent_len] = 0;
-                   SvREFCNT_dec(PL_linestr);
-                   PL_linestr = linestr_save;
-                   PL_linestart = SvPVX(linestr_save);
-                   PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
-                   PL_oldbufptr = oldbufptr_save;
-                   PL_oldoldbufptr = oldoldbufptr_save;
-                   s = d;
-                   break;
-               }
-           }
+                    /* Only valid if it's preceded by whitespace only */
+                    while (backup != s && --backup >= s) {
+                        if (! SPACE_OR_TAB(*backup)) {
+                            break;
+                        }
+                        indent_len++;
+                    }
 
-           /* Didn't find it */
-           sv_catsv(tmpstr,PL_linestr);
-       } else {
-           if (*s == term && PL_bufend-s >= len
-               && memEQ(s,PL_tokenbuf + 1,len))
-           {
-               SvREFCNT_dec(PL_linestr);
-               PL_linestr = linestr_save;
-               PL_linestart = SvPVX(linestr_save);
-               PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
-               PL_oldbufptr = oldbufptr_save;
-               PL_oldoldbufptr = oldoldbufptr_save;
-               s = d;
-               break;
-           } else {
-               sv_catsv(tmpstr,PL_linestr);
-           }
-       }
-      }
+                    /* All whitespace or none! */
+                    if (backup == found || SPACE_OR_TAB(*backup)) {
+                        Newx(indent, indent_len + 1, char);
+                        memcpy(indent, backup, indent_len);
+                        indent[indent_len] = 0;
+                        SvREFCNT_dec(PL_linestr);
+                        PL_linestr = linestr_save;
+                        PL_linestart = SvPVX(linestr_save);
+                        PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
+                        PL_oldbufptr = oldbufptr_save;
+                        PL_oldoldbufptr = oldoldbufptr_save;
+                        s = d;
+                        break;
+                    }
+                }
+
+                /* Didn't find it */
+                sv_catsv(tmpstr,PL_linestr);
+            }
+            else {
+                if (*s == term && PL_bufend-s >= len
+                    && memEQ(s,PL_tokenbuf + 1,len))
+                {
+                    SvREFCNT_dec(PL_linestr);
+                    PL_linestr = linestr_save;
+                    PL_linestart = SvPVX(linestr_save);
+                    PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
+                    PL_oldbufptr = oldbufptr_save;
+                    PL_oldoldbufptr = oldoldbufptr_save;
+                    s = d;
+                    break;
+                }
+                else {
+                    sv_catsv(tmpstr,PL_linestr);
+                }
+            }
+        } /* while (1) */
     }
+
     PL_multi_end = origline + PL_parser->herelines;
+
     if (indented && indent) {
        STRLEN linecount = 1;
        STRLEN herelen = SvCUR(tmpstr);
@@ -10362,50 +10391,58 @@ S_scan_heredoc(pTHX_ char *s)
                linecount++;
 
            /* Found our indentation? Strip it */
-           } else if (se - ss >= indent_len
+           }
+            else if (se - ss >= indent_len
                       && memEQ(ss, indent, indent_len))
            {
                STRLEN le = 0;
-
                ss += indent_len;
 
                while ((ss + le) < se && *(ss + le) != '\n')
                    le++;
 
                sv_catpvn(newstr, ss, le);
-
                ss += le;
 
            /* Line doesn't begin with our indentation? Croak */
-           } else {
+           }
+            else {
+                Safefree(indent);
                Perl_croak(aTHX_
                    "Indentation on line %d of here-doc doesn't match 
delimiter",
                    (int)linecount
                );
            }
-       }
+       } /* while */
+
         /* avoid sv_setsv() as we dont wan't to COW here */
         sv_setpvn(tmpstr,SvPVX(newstr),SvCUR(newstr));
        Safefree(indent);
        SvREFCNT_dec_NN(newstr);
     }
+
     if (SvCUR(tmpstr) + 5 < SvLEN(tmpstr)) {
        SvPV_shrink_to_cur(tmpstr);
     }
+
     if (!IN_BYTES) {
        if (UTF && is_utf8_string((U8*)SvPVX_const(tmpstr), SvCUR(tmpstr)))
            SvUTF8_on(tmpstr);
     }
+
     PL_lex_stuff = tmpstr;
     pl_yylval.ival = op_type;
     return s;
 
   interminable:
+    if (indent)
+       Safefree(indent);
     SvREFCNT_dec(tmpstr);
     CopLINE_set(PL_curcop, origline);
     missingterm(PL_tokenbuf + 1, sizeof(PL_tokenbuf) - 1);
 }
 
+
 /* scan_inputsymbol
    takes: position of first '<' in input buffer
    returns: position of first char following the matching '>' in

-- 
Perl5 Master Repository

Reply via email to