September 09
https://issues.dlang.org/show_bug.cgi?id=24757

          Issue ID: 24757
           Summary: Escaping with typesafe variadic functions is not
                    detected, making @safe code potentially unsafe
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: normal
          Priority: P1
         Component: dmd
          Assignee: nobody@puremagic.com
          Reporter: issues.dlang@jmdavisProg.com

This code compiles and runs, but the assertion fails

---
void main() @safe
{
    auto arr = bar();
    assert(arr == [1, 2, 3]);
}

int[] foo(int[] args...) @safe
{
    auto saved = args;
    return saved;
}

int[] bar() @safe
{
    return foo(1, 2, 3);
}
---

If you have

---
void main() @safe
{
    auto arr = foo(1, 2, 3);
    assert(arr == [1, 2, 3]);
}

int[] foo(int[] args...) @safe
{
    auto saved = args;
    return saved;
}
---

it works - presumably because the array ends up sitting on the stack in main in that case - but it's still not actually memory safe.

If you have

---
void main() @safe
{
    auto arr = foo(1, 2, 3);
    assert(arr == [1, 2, 3]);
}

int[] foo(int[] args...) @safe
{
    return args;
}
---

then the compiler catches it with

---
q.d(9): Error: returning `args` escapes a reference to variadic parameter
`args`
---

but once you slice the array, it can no longer catch the problem, making it so that @safe code is not actually memory safe.

The issue is pretty similar to what happens with slicing static arrays - https://issues.dlang.org/show_bug.cgi?id=24750 - in that DIP 1000 does solve the problem, but without it, we have a hole in @safe. Also, just like with static arrays, slicing the array is caught when returning it directly but isn't otherwise (without DIP 1000).

If we want to close the hole without needing DIP 1000, it seems to me that we either need to make it so that typesafe variadic functions are not considered @safe, or we need the compiler to flag anywhere that slices the variadic array as @system (even if it's implicit like when passing it to a function or using auto to slice the entire array). Making it @system to slice the variadic array would likely be the better choice, because then more code can be @safe, though I expect that a large percentage of such functions will ultimately have to be @trusted anyway, since in most cases, you're probably going to want to slice the array rather than simply access its elements.

Also, special attention may have to be take with foreach, since depending on how that's implemented, it could be slicing the array, but if it is, it's guaranteed that the slice isn't escaping, because the compiler is doing it in a way that it can't escape. But it could be that that's simply lowered to using for with an index, in which case, no slicing actually happens, and it's a non-issue. I just bring it up, since it occurs to me that it might be, and it should not be flagged as @system.

But regardless of how we want to solve it, as things stand, without DIP 1000, it's very possible to escape a variadic array from an @safe function.

--