develooper Front page | perl.perl5.porters | Postings from May 2003

Re: [perl #22372] [PATCH] sv_chop() broken

From:
Enache Adrian
Date:
May 30, 2003 08:50
Subject:
Re: [perl #22372] [PATCH] sv_chop() broken
Message ID:
20030530155228.GA872@ratsnest.hole
On Fri, May 30, 2003 at 12:41:48AM +0200, Kjetil Torgrim Homme wrote:
> let's try again.  this crashes:
> 
> format STDOUT =
> ^<<<<<<<<<<<<<<~~
> $el
> .
> 
> %hash = ("k" => "v");
> for $el (keys %hash) {
>     write;
> }

Have a look at these snippets from sv_chop():

    register STRLEN delta;
...
    SV_CHECK_THINKFIRST(sv);
...
    if (!SvOOK(sv)) {
        if (!SvLEN(sv)) { /* make copy of shared string */
...
            SvGROW(sv, len + 1);
            Move(pvx,SvPVX(sv),len,char);
...
    delta = ptr - SvPVX(sv);
    SvLEN(sv) -= delta;
    SvCUR(sv) -= delta;
    SvPVX(sv) += delta;

Both SV_CHECK_THINKFIRST and SvGROW may reallocate SvPVX(sv) elsewhere;
So the "delta" will be set to some random value - and the consequences
are easy to guess.

Regards,
Adi

--- /arc/bleadperl/sv.c	2003-05-13 02:03:25.000000000 +0300
+++ ./sv.c	2003-05-30 17:21:22.000000000 +0300
@@ -4501,6 +4501,8 @@ Efficient removal of characters from the
 SvPOK(sv) must be true and the C<ptr> must be a pointer to somewhere inside
 the string buffer.  The C<ptr> becomes the first character of the adjusted
 string. Uses the "OOK hack".
+Beware: after this function returns, C<ptr> and SvPVX(sv) may no longer
+refer to the same chunk of data.
 
 =cut
 */
@@ -4509,9 +4511,9 @@ void
 Perl_sv_chop(pTHX_ register SV *sv, register char *ptr)
 {
     register STRLEN delta;
-
     if (!ptr || !SvPOKp(sv))
 	return;
+    delta = ptr - SvPVX(sv);
     SV_CHECK_THINKFIRST(sv);
     if (SvTYPE(sv) < SVt_PVIV)
 	sv_upgrade(sv,SVt_PVIV);
@@ -4531,7 +4533,6 @@ Perl_sv_chop(pTHX_ register SV *sv, regi
 	SvFLAGS(sv) |= SVf_OOK; 
     }
     SvNIOK_off(sv);
-    delta = ptr - SvPVX(sv);
     SvLEN(sv) -= delta;
     SvCUR(sv) -= delta;
     SvPVX(sv) += delta;
--- /arc/bleadperl/t/op/write.t	2002-04-29 00:31:14.000000000 +0300
+++ ./t/op/write.t	2003-05-30 18:39:45.000000000 +0300
@@ -5,7 +5,7 @@ BEGIN {
     @INC = '../lib';
 }
 
-print "1..47\n";
+print "1..48\n";
 
 my $CAT = ($^O eq 'MSWin32' || $^O eq 'NetWare' || $^O eq 'VMS') ? 'type'
 	: ($^O eq 'MacOS') ? 'catenate'
@@ -271,7 +271,19 @@ if (`$CAT Op_write.tmp` eq $right)
 else
     { print "not ok 11\n"; }
 
-# 12..47: scary format testing from Merijn H. Brand
+{
+    my $el;
+    format STDOUT =
+ok ^<<<<<<<<<<<<<<~~ # sv_chop() naze
+$el
+.
+    my %hash = (12 => 3);
+    for $el (keys %hash) {
+	write;
+    }
+}
+
+# 13..48: scary format testing from Merijn H. Brand
 
 if ($^O eq 'VMS' || $^O eq 'MSWin32' || $^O eq 'dos' || $^O eq 'MacOS' ||
     ($^O eq 'os2' and not eval '$OS2::can_fork')) {
@@ -281,7 +293,7 @@ if ($^O eq 'VMS' || $^O eq 'MSWin32' || 
 
 use strict;	# Amazed that this hackery can be made strict ...
 
-my $test = 12;
+my $test = 13;
 
 # Just a complete test for format, including top-, left- and bottom marging
 # and format detection through glob entries



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About