Issue 19175 - @safe code can escape local array references
Summary: @safe code can escape local array references
Status: RESOLVED WORKSFORME
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P1 critical
Assignee: No Owner
URL:
Keywords: accepts-invalid, safe
Depends on:
Blocks:
 
Reported: 2018-08-17 07:12 UTC by Peter Alexander
Modified: 2019-08-22 10:12 UTC (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Peter Alexander 2018-08-17 07:12:40 UTC
--------
import std.algorithm, std.stdio;

@safe:
    
auto foo() {
  int[6] xs = [0, 1, 2, 3, 4, 5];
  return xs[].map!(x => x);
}

void main() {
  writeln(foo());
}
--------

Observed: this compiles and (for me) prints [0, 0, -2132056872, 22008, 0, 0].

Expected: fail to compile with error about the escaped local reference.
Comment 1 Jonathan M Davis 2018-08-17 07:43:54 UTC
This is a duplicate of https://issues.dlang.org/show_bug.cgi?id=8838, which was closed as fixed based on the fact that -dip1000 fixes the problem. It's still quite broken without -dip1000 though.
Comment 2 Peter Alexander 2018-08-17 10:50:25 UTC
It is still broken with -dip1000

https://run.dlang.io/is/gJi2Fa
Comment 3 anonymous4 2018-08-21 13:07:34 UTC
Reduced:

@safe:

struct A(alias fun)
{
    int[] r;
    this(int[] q){r=q;}
}

template m(alias fun)
{
    auto m(int[] r)
    {
        return A!fun(r);
    }
}
    
auto foo() {
  int[6] xs = [0, 1, 2, 3, 4, 5];
  return xs[].m!(x => x);
}

void main() {
  auto a=foo();
}
Comment 4 anonymous4 2018-08-21 13:20:52 UTC
@safe:

struct A(T)
{
    int[] r;
    this(int[] q){r=q;}
}

int[] escape(T)(int[] r)
{
    return A!int(r).r;
}
    
int[] f()
{
    int[6] xs = [0, 1, 2, 3, 4, 5];
    return xs.escape!int;
}
Comment 5 Radu Racariu 2018-08-26 21:45:24 UTC
Under dip1000, what I think is that slicing a static array should always be considered scope.

Also, calling a functions with a scope slice with the parameter for the slice not annotated as scope should result in an error if the compiler can't prove that the parameter can't escape.
Comment 6 anonymous4 2018-08-27 08:00:24 UTC
Same for pointers:

@safe:

struct A(T)
{
    int* r;
    this(int* q){r=q;}
}

int* escape(T)(int* r)
{
    return A!int(r).r;
}

int* f()
{
    int x;
    return escape!int(&x);
}
Comment 7 ag0aep6g 2018-08-27 09:24:56 UTC
(In reply to anonymous4 from comment #6)
> Same for pointers:
[...]

Resolving the templates shows that this is related to `pure`:

----
@safe:

struct A
{
    int* r;
    this(int* q) pure { r = q; }
}

int* escape(int* r) pure
{
    return A(r).r;
}

int* f()
{
    int x;
    return escape(&x);
}
----
Comment 8 Mike Franklin 2019-08-22 04:59:41 UTC
Works for me as in v2.087.1
Comment 9 ag0aep6g 2019-08-22 10:12:42 UTC
(In reply to Mike Franklin from comment #8)
> Works for me as in v2.087.1

Most of the test cases are correctly rejected now with -dip1000. But the one from comment #7 is still accepted. Moved to issue 20150.