develooper Front page | perl.perl5.porters | Postings from June 2013

SvGROW(+1) and svleak.t

Thread Next
From:
Dave Mitchell
Date:
June 8, 2013 18:19
Subject:
SvGROW(+1) and svleak.t
Message ID:
20130608181924.GK30134@iabyn.com
I've just pushed the following commit. Given the thread that's just broken
out about the number 79, I'm happy to revert this and fix svleak.t a
different way if people disagree with this approach ;-)


commit cbcb2a16c528e483a6c8804d2d2daefecc1a0d3e
Author:     David Mitchell <davem@iabyn.com>
AuthorDate: Sat Jun 8 18:24:51 2013 +0100
Commit:     David Mitchell <davem@iabyn.com>
CommitDate: Sat Jun 8 18:24:51 2013 +0100

    add 1 to SvGROW under COW (and fix svleak.t)
    
    the new COW scheme uses SvPVX(sv)[SvLEN(sv)-1] (if spare)
    to store the COW reference count. If this byte isn't spare, the string is
    copied rather than COWed.  So, when built under the new COW, allocate one
    more byte than asked for in sv_grow(), to make it likely this byte is
    always spare: and thus make more strings COW-able. If the new size is a
    big power of two, don't bother: we assume the caller wanted a nice 2^N
    sized block and will be annoyed at getting 2^N+1 or more.
    
    Note that sv_grow() already rounds up. For example: formerly, strings of
    length 1..15 were allocated 16 bytes, 16..31 allocated 32 bytes, etc
    (usually allowing +1 for trailing \0).
    
    Now its 1..14 => 16, 15..30 => 32 etc.
    
    As a side-effect, this should fix a bizarre occasionally failing svleak.t
    test under COW. This test,
    
        '"too many errors" from constant overloading returning undef'
    
    basically twice evals some code that is expected to fail. If over the
    course of the second eval the total number of allocated SVs grows, then
    the test fails. This particular eval uses overload::constant, and that
    module has this code:
    
        "$_[1]" !~ /(^|=)CODE\(0x[0-9a-f]+\)$/
    
    i.e. match against a stringified reference. Now, if it stringifies to a
    15-char string (e.g. "CODE(0x1234567)"), then SvCUR is 15 and SvLEN is 16,
    and there isn't a spare byte (after allowing for \0) for the COW ref
    count, so the string can't be COWed. Now, if during the first eval,
    addresses are in the range 0x1000000..0xfffffff, then COW doesn't kick in.
    If during the second eval they fall outside this range, COW kicks in, and
    a new SV (which is a COW copy of the string) is attached to the regex, for
    capture info. This new SV won't be released until the regex is released,
    and so appears to be a leak. If COW kicks in during the first eval then
    this isn't an issue, as it will just be reused during the second eval.
    
    This was exceedingly difficult to reliably reproduce, as it was heavily
    affected by kernel address randomisation (on linux); plus part of the test
    file used rand(); plus of course the hash randomisation and perturbation
    feature in 5.18.
    
    I eventually cracked it by: tweaking the hash randomisation; hacking the
    perl seed code to use an ENV var rather than /dev/urandom; hacking the
    perl startup to display the initial system brk(), then when it failed,
    hacked it again to set that particular brk().


-- 
Never do today what you can put off till tomorrow.

Thread Next


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