2012/12/20 H. S. Teoh <hsteoh@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