[Issue 15056] [REG2.068.1] Unstored RAII struct return yields bogus error: "cannot mix core.std.stdlib.alloca() and exception handling"

via Digitalmars-d-bugs digitalmars-d-bugs at puremagic.com
Thu Sep 17 20:48:11 PDT 2015


https://issues.dlang.org/show_bug.cgi?id=15056

--- Comment #7 from Marco Leise <Marco.Leise at gmx.de> ---
(In reply to Kenji Hara from comment #5)
> Today, in Win64 and all Posix platforms, dmd uses exception handling table,
> and it doesn't support using alloca in a function that contains try-finally
> statement.

I don't know how exactly exception handling works in D and my mental image
currently is that as long as there is a dtor call pending that needs to run
when an Exception interrupts the function's execution, alloca() must not be in
effect.

Under the premise that my assumptions hold alloca() would work in following
cases:

A) No statement could throw while the dtor call is pending. In fact the
function is 'nothrow':

-------------------------------
import core.stdc.stdlib;

struct S { ~this() nothrow {} }

S foo() nothrow { return S(); }

void main() nothrow    // Worked in 2.067, regressed in 2.068
{
    void* p = alloca(1234);
    foo();
}
-------------------------------

B) The dtors have already been run, by the time alloca() is reached:

-------------------------------
import core.stdc.stdlib;

struct S { ~this() {} }

S foo() { return S(); }

void main()            // Worked in 2.067, regressed in 2.068
{
    {
        foo();
    }
    void* p = alloca(1234);
}
-------------------------------

(In reply to Walter Bright from comment #6)
> The fact that this was compiling on early compilers doesn't mean it was working.

No doubt there is a reason for this fix that introduced the regression. It's
just not my code :D. I still believe that for my use case 2.067 did the right
thing, otherwise I would have dealt with segfaults earlier, right? For example
take this line here that broke in 2.068:
https://github.com/mleise/fast/blob/v0.2.1/source/fast/internal.d#L136
`wcharPtr` has as a default parameter an alloca() call and returns a struct
with a dtor. From this struct I extract a character and return immediately. At
no time can an exception be thrown, so - I assume - no try-finally is ever
inserted and therefore no warning about mixing exception handling with
alloca().
You can run this code (tested on Linux/amd64) with dmd-2.067.1 and dub by
typing "dub fetch fast && dub run fast".

(In reply to Martin Nowak from comment #4)
> You could pass in a buffer to avoid alloca.
>  ...

Yes, but dynamic stack memory allocation is an entirely different thing. Sure
one could always return blocks of 1, 2 or 4 KiB, but then you quickly move into
cold cache and eat stack space faster than necessary. Now when working with
strings the requirement is often only a few bytes, but alloca may be feasible
for up to, say 1024. The way I use it is to set a limit for it and switch to
malloc like this (simplified):
`required > 1024 ? malloc(required) : alloca(required)`

With the changes in 2.068, alloca() can't easily be used in functions that use
RAII and return something, which is frequent in D.


P.S.:

I could fix the offending line in my code by changing it like this:

// BEFORE
benchmark ("cstring.wcharPtr", () { return
wcharPtr!pathname.ptr[pathnameWStringLength]; })
benchmark ("cstring.wcharPtr", () { wchar result; { auto buf =
wcharPtr!pathname; result = buf.ptr[pathnameWStringLength]; } return result; })
// AFTER

But this was supposed to be an concise/efficient way to provide 0-terminated
whcar* to external libraries, not an exercise in obfuscated coding!</rant>

--


More information about the Digitalmars-d-bugs mailing list