From: Nicholas Clark <nick@ccl4.org>
Date: Sat, 27 Jan 2007 00:45:30 +0000 (+0000)
Subject: A test to exercise the smallbuf overflow code in S_incline, and a
X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=448670305e91e35ff5a396a7d764ec8b1844012e;p=p5sagit%2Fp5-mst-13.2.git

A test to exercise the smallbuf overflow code in S_incline, and a
refactoring of that code to use only one 128 char array, not two.

p4raw-id: //depot/perl@30024
---

diff --git a/t/comp/parser.t b/t/comp/parser.t
index 4895d06..95be22d 100644
--- a/t/comp/parser.t
+++ b/t/comp/parser.t
@@ -9,7 +9,7 @@ BEGIN {
 }
 
 BEGIN { require "./test.pl"; }
-plan( tests => 72 );
+plan( tests => 108 );
 
 eval '%@x=0;';
 like( $@, qr/^Can't modify hash dereference in repeat \(x\)/, '%@x=0' );
@@ -275,3 +275,83 @@ like($@, qr/BEGIN failed--compilation aborted/, 'BEGIN 6' );
 
 eval q[ BEGIN {\&foo4; die } ] for 1..10;
 like($@, qr/BEGIN failed--compilation aborted/, 'BEGIN 7' );
+
+# Add new tests HERE:
+
+# More awkward tests for #line. Keep these at the end, as they will screw
+# with sane line reporting for any other test failures
+
+sub check ($$$) {
+    my ($file, $line, $name) =  @_;
+    my (undef, $got_file, $got_line) = caller;
+    like ($got_file, $file, "file of $name");
+    local $TODO;
+    $TODO = "For some wrong reason PL_copline is 1" if $line == 51;
+    is ($got_line, $line, "line of $name");
+}
+
+#line 3
+check(qr/parser\.t$/, 3, "bare line");
+
+# line 5
+check(qr/parser\.t$/, 5, "bare line with leading space");
+
+#line 7 
+check(qr/parser\.t$/, 7, "trailing space still valid");
+
+# line 11 
+check(qr/parser\.t$/, 11, "leading and trailing");
+
+#	line 13
+check(qr/parser\.t$/, 13, "leading tab");
+
+#line	17
+check(qr/parser\.t$/, 17, "middle tab");
+
+#line                                                                        19
+check(qr/parser\.t$/, 19, "loadsaspaces");
+
+#line 23 KASHPRITZA
+check(qr/^KASHPRITZA$/, 23, "bare filename");
+
+#line 29 "KAHEEEE"
+check(qr/^KAHEEEE$/, 29, "filename in quotes");
+
+#line 31 "CLINK CLOINK BZZT"
+check(qr/^CLINK CLOINK BZZT$/, 31, "filename with spaces in quotes");
+
+#line 37 "THOOM	THOOM"
+check(qr/^THOOM	THOOM$/, 37, "filename with tabs in quotes");
+
+#line 41 "GLINK PLINK GLUNK DINK" 
+check(qr/^GLINK PLINK GLUNK DINK$/, 41, "a space after the quotes");
+
+#line 43 "BBFRPRAFPGHPP
+check(qr/^"BBFRPRAFPGHPP$/, 43, "actually missing a quote is still valid");
+
+#line 47 bang eth
+check(qr/^"BBFRPRAFPGHPP$/, 46, "but spaces aren't allowed without quotes");
+
+eval <<'EOSTANZA'; die $@ if $@;
+#line 51 "With wonderful deathless ditties|We build up the world's great cities,|And out of a fabulous story|We fashion an empire's glory:|One man with a dream, at pleasure,|Shall go forth and conquer a crown;|And three with a new song's measure|Can trample a kingdom down."
+check(qr/^With.*down\.$/, 51, "Overflow the second small buffer check");
+EOSTANZA
+
+# And now, turn on the debugger flag for long names
+$^P = 0x100;
+
+#line 53 "For we are afar with the dawning|And the suns that are not yet high,|And out of the infinite morning|Intrepid you hear us cry-|How, spite of your human scorning,|Once more God's future draws nigh,|And already goes forth the warning|That ye of the past must die."
+check(qr/^For we.*must die\.$/, 53, "Our long line is set up");
+
+eval <<'EOT'; die $@ if $@;
+#line 59 " "
+check(qr/^ $/, 59, "Overflow the first small buffer check only");
+EOT
+
+eval <<'EOSTANZA'; die $@ if $@;
+#line 61 "Great hail! we cry to the comers|From the dazzling unknown shore;|Bring us hither your sun and your summers;|And renew our world as of yore;|You shall teach us your song's new numbers,|And things that we dreamed not before:|Yea, in spite of a dreamer who slumbers,|And a singer who sings no more."
+check(qr/^Great hail!.*no more\.$/, 61, "Overflow both small buffer checks");
+EOSTANZA
+
+__END__
+# Don't add new tests HERE. See note above
diff --git a/toke.c b/toke.c
index 51c0cf7..8f6c5ce 100644
--- a/toke.c
+++ b/toke.c
@@ -788,25 +788,40 @@ S_incline(pTHX_ const char *s)
 	if (tmplen > 7 && strnEQ(cf, "(eval ", 6)) {
 	    /* must copy *{"::_<(eval N)[oldfilename:L]"}
 	     * to *{"::_<newfilename"} */
-	    char smallbuf[128], smallbuf2[128];
-	    char *tmpbuf, *tmpbuf2;
-	    GV **gvp, *gv2;
+	    /* However, the long form of evals is only turned on by the
+	       debugger - usually they're "(eval %lu)" */
+	    char smallbuf[128];
+	    char *tmpbuf;
+	    GV **gvp;
 	    STRLEN tmplen2 = len;
 	    if (tmplen + 2 <= sizeof smallbuf)
 		tmpbuf = smallbuf;
 	    else
 		Newx(tmpbuf, tmplen + 2, char);
-	    if (tmplen2 + 2 <= sizeof smallbuf2)
-		tmpbuf2 = smallbuf2;
-	    else
-		Newx(tmpbuf2, tmplen2 + 2, char);
-	    tmpbuf[0] = tmpbuf2[0] = '_';
-	    tmpbuf[1] = tmpbuf2[1] = '<';
+	    tmpbuf[0] = '_';
+	    tmpbuf[1] = '<';
 	    memcpy(tmpbuf + 2, cf, tmplen);
-	    memcpy(tmpbuf2 + 2, s, tmplen2);
-	    tmplen += 2; tmplen2 += 2;
+	    tmplen += 2;
 	    gvp = (GV**)hv_fetch(PL_defstash, tmpbuf, tmplen, FALSE);
 	    if (gvp) {
+		char *tmpbuf2;
+		GV *gv2;
+
+		if (tmplen2 + 2 <= sizeof smallbuf)
+		    tmpbuf2 = smallbuf;
+		else
+		    Newx(tmpbuf2, tmplen2 + 2, char);
+
+		if (tmpbuf2 != smallbuf || tmpbuf != smallbuf) {
+		    /* Either they malloc'd it, or we malloc'd it,
+		       so no prefix is present in ours.  */
+		    tmpbuf2[0] = '_';
+		    tmpbuf2[1] = '<';
+		}
+
+		memcpy(tmpbuf2 + 2, s, tmplen2);
+		tmplen2 += 2;
+
 		gv2 = *(GV**)hv_fetch(PL_defstash, tmpbuf2, tmplen2, TRUE);
 		if (!isGV(gv2)) {
 		    gv_init(gv2, PL_defstash, tmpbuf2, tmplen2, FALSE);
@@ -815,9 +830,10 @@ S_incline(pTHX_ const char *s)
 		    GvHV(gv2) = (HV*)SvREFCNT_inc(GvHV(*gvp));
 		    GvAV(gv2) = (AV*)SvREFCNT_inc(GvAV(*gvp));
 		}
+
+		if (tmpbuf2 != smallbuf) Safefree(tmpbuf2);
 	    }
 	    if (tmpbuf != smallbuf) Safefree(tmpbuf);
-	    if (tmpbuf2 != smallbuf2) Safefree(tmpbuf2);
 	}
 #endif
 	CopFILE_free(PL_curcop);