Heap corruption in reading struct fields in ctor

kenji hara k.hara.pg at gmail.com
Wed Dec 19 22:04:19 PST 2012


2012/12/20 H. S. Teoh <hsteoh at quickfur.ath.cx>

> On Thu, Dec 20, 2012 at 05:45:51AM +0100, deadalnix wrote:
> > On Thursday, 20 December 2012 at 04:15:31 UTC, H. S. Teoh wrote:
> > >On Thu, Dec 20, 2012 at 04:37:25AM +0100, deadalnix wrote:
> > >>Can you tell more about what is the corruption ?
> > >>
> > >>Are you getting garbage elements from front ? Can you use a debugger
> > >>or add some writeln to show some pointer addresses ?
> > >
> > >Yeah it's garbage elements from front. I'll try a debugger, but this
> > >problem only happens in git dmd, not in gdc, and dmd executables are
> > >a bit of a pain to deal with in gdb.
> > >
> >
> > Can you try to check if the pointer of the returned string is the
> > right one (IE, buff) but happen to contain garbage or the pointer
> > itself is garbage ?
>
> I did some digging, and found that the pointer is correct but the target
> is garbage.
>
>
Also, I may have found the cause: if buf is changed from a static array
> to a dynamic one (with .length set to 256 in the ctor) then the
> corruption goes away. I'm wondering if maybe the size of the struct is
> causing it to overflow the stack?


This is a self-specific pointer (==slice) problem.

        auto makeTransientString() {
            auto tsa = TransientStringArray([ "ab", "cd", "ef" ]);
            //return joiner(tsa);
            auto x = joiner(tsa); return x; // jsut same as above by RVO
            // In here, x._current points tsa.buf,
            // but tsa.buf is allocated in the stack and
            // will be corrupted after returning makeTransientString()
        }

It would explain why the corruption starts to happen at the 4th level of
> nested function calls, since on Linux the default stack size is approx.
> 4 KB, and the size of dchar[256] plus 1 or 2 other struct members makes
> the size of the struct a little over 1 KB, so 4 copies of them on the
> stack would cause an overflow.


Calling func2(result); is accidentally works IMO.

The root cause is saving _items.front in joiner.Result.ctor, and using it
later.
If you calculate joiner.Result.front every time, problem will disappear.

        @property auto ref front()
        {
            //return _current.front;
            return _items.front.front;
        }

Kenji Hara
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20121220/7ecc693b/attachment.html>


More information about the Digitalmars-d mailing list