[Issue 24798] std.algorithm.substitute appears to be destroying an already destroyed value

d-bugmail at puremagic.com d-bugmail at puremagic.com
Thu Oct 10 10:02:43 UTC 2024


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

Jonathan M Davis <issues.dlang at jmdavisProg.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
          Component|phobos                      |dmd
           Severity|normal                      |regression

--- Comment #1 from Jonathan M Davis <issues.dlang at jmdavisProg.com> ---
After dustmiting, I've reduced it to

---
import std.range;

void main()
{
    static struct S
    {
        int val;
        ~this()
        {
            assert(val != 99, "Double Destroy");
            val = 99;
        }
    }

    auto arr = [S(0), S(1), S(2), S(3)];
    auto result = arr.mySubstitute(S(1), S(42));
    auto front = result.front;
}

auto mySubstitute(R, Substs...)(R r, Substs)
{
    struct MySubstituteElement
    {
        Substs substs;

        auto opCall(E)(E )
        {
            return substs[0];
        }
    }

    auto er = MySubstituteElement.init;

    return r.myMap!er;
}

template myMap(fun...)
{
    auto myMap(Range)(Range r)
    {
        return MyMapResult!(fun, Range)(r);
    }
}

struct MyMapResult(alias fun, Range)
{
    Range _input;

    @property empty()
    {
        return _input.empty;
    }

    void popFront()
    {
    }

    @property front()
    {
        return fun(_input);
    }
}
---

I could probably reduce it further if I understood the issue better, but any
further transformations that I've tried have made the problem go away.

In any case, given that all of the Phobos code was removed aside from import
std.range to get the range primitives for arrays, it looks to me like this is a
compiler bug.

Also, trying it on run.dlang.org, it looks like it broke with dmd 2.068.2.
Looking at the changelog - https://dlang.org/changelog/2.068.2.html - it looks
like the problem was likely caused by reverting the fix for issue 14708:
https://issues.dlang.org/show_bug.cgi?id=14708

I haven't dug into any of the details, so I really don't know what the exact
issue is, but destructors need to not be running on an already destroyed
object. It can potentially be worked around by explicitly setting a struct to
its init value at the end of a destructor, but no one is going to think of
doing that normally.

I suspect that the main reason that this wasn't caught previously is simply
because destructors aren't used all that frequently in D, but I ran into it at
work when trying to add a destructor to an existing type, and this is one of
the problems that I hit.

--


More information about the Digitalmars-d-bugs mailing list