FAQ
Hi Nick,

The following program causes a panic the second time the readline op is
called:
my $sv = "one\ntwo\nthree\n";
open my $fh, "<", \$sv or die $!;
while (<$fh>) {
$sv = "";
}

The reason is that PerlIOScalar_get_cnt() starts to return negative values
after the C<$sv = ""> and this confuses PerlIOBase_read(). The patch
below has PerlIOScalar_get_cnt() test against SvCUR before returning.

I'm not sure if this is the right fix, but if it is let me know and I'll
add a test case.

Cheers,
-Ben

--
signer: can't create ~/.sig: Operation not permitted

--- ext/PerlIO/Scalar/Scalar.xs.orig Tue May 8 15:16:48 2001
+++ ext/PerlIO/Scalar/Scalar.xs Tue May 8 16:55:37 2001
@@ -198,7 +198,10 @@ PerlIOScalar_get_cnt(PerlIO *f)
if (PerlIOBase(f)->flags & PERLIO_F_CANREAD)
{
PerlIOScalar *s = PerlIOSelf(f,PerlIOScalar);
- return SvCUR(s->var) - s->posn;
+ if (SvCUR(s->var) > s->posn)
+ return SvCUR(s->var) - s->posn;
+ else
+ return 0;
}
return 0;
}

Search Discussions

  • Nick at May 9, 2001 at 2:36 pm

    Benjamin Sugars writes:
    Hi Nick,

    The following program causes a panic the second time the readline op is
    called:
    my $sv = "one\ntwo\nthree\n";
    open my $fh, "<", \$sv or die $!;
    while (<$fh>) {
    $sv = "";
    }

    The reason is that PerlIOScalar_get_cnt() starts to return negative values
    after the C<$sv = ""> and this confuses PerlIOBase_read(). The patch
    below has PerlIOScalar_get_cnt() test against SvCUR before returning.
    The patch below looks safe enough, I would be equally happy with one
    that made PerlIOBase_read() do the right thing (i.e. treat < 0 as 0).
    I'm not sure if this is the right fix, but if it is let me know and I'll
    add a test case.

    Cheers,
    -Ben

    --
    signer: can't create ~/.sig: Operation not permitted

    --- ext/PerlIO/Scalar/Scalar.xs.orig Tue May 8 15:16:48 2001
    +++ ext/PerlIO/Scalar/Scalar.xs Tue May 8 16:55:37 2001
    @@ -198,7 +198,10 @@ PerlIOScalar_get_cnt(PerlIO *f)
    if (PerlIOBase(f)->flags & PERLIO_F_CANREAD)
    {
    PerlIOScalar *s = PerlIOSelf(f,PerlIOScalar);
    - return SvCUR(s->var) - s->posn;
    + if (SvCUR(s->var) > s->posn)
    + return SvCUR(s->var) - s->posn;
    + else
    + return 0;
    }
    return 0;
    }
    --
    Nick Ing-Simmons
    who is looking for a new job see http://www.ni-s.u-net.com/
  • Benjamin Sugars at May 9, 2001 at 3:43 pm

    On Wed, 9 May 2001 nick@ing-simmons.net wrote:

    The patch below looks safe enough, I would be equally happy with one
    that made PerlIOBase_read() do the right thing (i.e. treat < 0 as 0).
    Yes, I was surprised it didn't already account for that: quick perusal of
    the code made me think it should work, but it doesn't.

    Looking closer reveals that there's obviously something about the SSize_t
    type that I don't understand: can you explain why the following patch
    fixes things?

    --- perlio.c.orig Wed May 9 12:06:51 2001
    +++ perlio.c Wed May 9 12:38:33 2001
    @@ -1646,7 +1646,7 @@ PerlIOBase_read(PerlIO *f, void *vbuf, S
    while (count > 0)
    {
    SSize_t avail = PerlIO_get_cnt(f);
    - SSize_t take = (count < avail) ? count : avail;
    + SSize_t take = ((int)count < (int)avail) ? count : avail;
    if (take > 0)
    {
    STDCHAR *ptr = PerlIO_get_ptr(f);

    Cheers,
    -Ben

    --
    signer: can't create ~/.sig: File name too long
  • Andy Dougherty at May 9, 2001 at 4:17 pm

    On Wed, 9 May 2001, Benjamin Sugars wrote:

    On Wed, 9 May 2001 nick@ing-simmons.net wrote:
    Looking closer reveals that there's obviously something about the SSize_t
    type that I don't understand: can you explain why the following patch
    fixes things?

    --- perlio.c.orig Wed May 9 12:06:51 2001
    +++ perlio.c Wed May 9 12:38:33 2001
    @@ -1646,7 +1646,7 @@ PerlIOBase_read(PerlIO *f, void *vbuf, S
    while (count > 0)
    {
    SSize_t avail = PerlIO_get_cnt(f);
    - SSize_t take = (count < avail) ? count : avail;
    + SSize_t take = ((int)count < (int)avail) ? count : avail;
    SSize_t is the signed variant of Size_t. Size_t can be either signed or
    unsigned. In this function, count is a Size_t. Depending on the
    platform, casting Size_t to int might do nothing, might try to truncate a
    64-bit quantity down to 32 bits, or may do something terribly odd with the
    signedness. To say something more, I'd have to understand what values
    each of these fellows is supposed to have.

    --
    Andy Dougherty doughera@lafayette.edu
    Dept. of Physics
    Lafayette College, Easton PA 18042
  • Benjamin Sugars at May 9, 2001 at 4:38 pm

    On Wed, 9 May 2001, Andy Dougherty wrote:
    On Wed, 9 May 2001, Benjamin Sugars wrote:

    Looking closer reveals that there's obviously something about the SSize_t
    type that I don't understand: can you explain why the following patch
    fixes things?

    --- perlio.c.orig Wed May 9 12:06:51 2001
    +++ perlio.c Wed May 9 12:38:33 2001
    @@ -1646,7 +1646,7 @@ PerlIOBase_read(PerlIO *f, void *vbuf, S
    while (count > 0)
    {
    SSize_t avail = PerlIO_get_cnt(f);
    - SSize_t take = (count < avail) ? count : avail;
    + SSize_t take = ((int)count < (int)avail) ? count : avail;
    SSize_t is the signed variant of Size_t. Size_t can be either signed or
    unsigned. In this function, count is a Size_t. Depending on the
    platform, casting Size_t to int might do nothing, might try to truncate a
    64-bit quantity down to 32 bits, or may do something terribly odd with the
    signedness. To say something more, I'd have to understand what values
    each of these fellows is supposed to have.
    count is the number of bytes wanted; it should be positive. avail is the
    number of bytes the layer says are actually available to read; normally
    it's 0 or positive, but can be negative.

    The behaviour that I was seeing was that the comparison (count < avail)
    was comparing the absolute values if avail < 0, which is not right. Or,
    it may be right, but it's not what the function expects. I'm guessing the
    compiler casts avail to Size_t in this case, and my Size_t is unsigned?

    Since the casting seems prone to being platform-specifc, perhaps we should
    explicitly test if avail < 0 rather than relying on the cast. Something
    like:

    --- perlio.c.orig Wed May 9 12:06:51 2001
    +++ perlio.c Wed May 9 13:29:24 2001
    @@ -1646,7 +1646,9 @@ PerlIOBase_read(PerlIO *f, void *vbuf, S
    while (count > 0)
    {
    SSize_t avail = PerlIO_get_cnt(f);
    - SSize_t take = (count < avail) ? count : avail;
    + SSize_t take = 0;
    + if (avail > 0)
    + take = (count < avail) ? count : avail;
    if (take > 0)
    {
    STDCHAR *ptr = PerlIO_get_ptr(f);

    Cheers,
    -Ben

    --
    signer: can't create ~/.sig: Numerical result out of range
  • Nick at May 9, 2001 at 5:51 pm

    Andy Dougherty writes:
    On Wed, 9 May 2001, Benjamin Sugars wrote:

    On Wed, 9 May 2001 nick@ing-simmons.net wrote:
    Looking closer reveals that there's obviously something about the SSize_t
    type that I don't understand: can you explain why the following patch
    fixes things?

    --- perlio.c.orig Wed May 9 12:06:51 2001
    +++ perlio.c Wed May 9 12:38:33 2001
    @@ -1646,7 +1646,7 @@ PerlIOBase_read(PerlIO *f, void *vbuf, S
    while (count > 0)
    {
    SSize_t avail = PerlIO_get_cnt(f);
    - SSize_t take = (count < avail) ? count : avail;
    + SSize_t take = ((int)count < (int)avail) ? count : avail;
    SSize_t is the signed variant of Size_t. Size_t can be either signed or
    unsigned. In this function, count is a Size_t.
    Drat. You note I made avail SSize_t, but forgot that it will be "upgraded"
    to "unsigned" Size_t when the compare happens.
    Depending on the
    platform, casting Size_t to int might do nothing, might try to truncate a
    64-bit quantity down to 32 bits, or may do something terribly odd with the
    signedness. To say something more, I'd have to understand what values
    each of these fellows is supposed to have.
    SSize_t take = ((SSize_t)count < avail) ? (SSize_t) count : avail;

    should get them all signed.



    --
    Nick Ing-Simmons
    who is looking for a new job see http://www.ni-s.u-net.com/
  • Jarkko Hietaniemi at May 9, 2001 at 11:58 pm

    SSize_t avail = PerlIO_get_cnt(f);
    - SSize_t take = (count < avail) ? count : avail;
    + SSize_t take = ((int)count < (int)avail) ? count : avail;
    SSize_t is the signed variant of Size_t. Size_t can be either signed or
    unsigned. In this function, count is a Size_t.
    Drat. You note I made avail SSize_t, but forgot that it will be "upgraded"
    to "unsigned" Size_t when the compare happens.
    Depending on the
    platform, casting Size_t to int might do nothing, might try to truncate a
    64-bit quantity down to 32 bits, or may do something terribly odd with the
    signedness. To say something more, I'd have to understand what values
    each of these fellows is supposed to have.
    SSize_t take = ((SSize_t)count < avail) ? (SSize_t) count : avail;

    should get them all signed.
    Well, 10054 is now in. Patch as appropriate.

    --
    $jhi++; # http://www.iki.fi/jhi/
    # There is this special biologist word we use for 'stable'.
    # It is 'dead'. -- Jack Cohen

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupperl5-porters @
categoriesperl
postedMay 8, '01 at 9:08p
activeMay 9, '01 at 11:58p
posts7
users4
websiteperl.org

People

Translate

site design / logo © 2022 Grokbase