April 13, 2020
On 4/13/20 3:50 AM, Walter Bright wrote:
> On 4/11/2020 7:43 PM, Timon Gehr wrote:
>> Clearly there is a bug or bad design if the address of a`` escaping in `b ~= &a` and in `b = [&a]` are not treated the same.
> 
> They are treated the same with dip1000.
> 
>> But like Adam I don't see why there should be such a check in @system/@trusted code at all. (I understand that there is a workaround, but that should not be required.)
>>
>> Can we please settle on making @safe actually memory safe and @system/@trusted actually trust the programmer?
> 
> Consider:
> 
>    @system int* pumpkin(int i) { return &i);
> 
> Should that give an error or not?

Yes. This one directly exposes dangling references, and is easily caught by the compiler.

> 
> I.e. where does one draw the line?
> 

Where it's possible to write valid code that is memory safe even though it cannot be proven.

For instance:

void foo()
{
	int*[] b;
	int a;
	b ~= &a;
        // use b but don't expose it outside foo
}

There are no memory safety violations there.

This one is also memory safe:

int*[] b;
void foo()
{
   int a;
   b ~= &a;
   // use b, but don't allow it to be exposed in a way that can result in corruption.
   b = b[0 .. $-1];
}

The first case is highly useful, as one often needs scratch space to perform complex calculations or graph algorithms. I see no reason to disallow it.

The second case is more questionable, because it's very easy for someone to keep a copy of b at some point, and then you have lost track of who has access to a's memory. But it still is possible for it to be safe. @system is supposed to mean "I know what I'm doing".

-Steve
April 14, 2020
On 4/13/2020 2:03 AM, Timon Gehr wrote:
>> Consider:
>>
>>    @system int* pumpkin(int i) { return &i; }
>>
>> Should that give an error or not?
>> ...
> 
> I don't see why not.

I've written code like that to get the stack pointer value.

As to the other case, to my mind putting the address of a stack local into a GC allocated object is highly suspicious:

1. it is very very easy to do it unintentionally

2. GC objects tend to be intended to outlast a function, yet the stack address will not, so why is this a GC allocated object, as opposed to, say, an RAII object or even a stack allocated object?

I don't know what Adam's actual use case for this is, but I would reject such code because of (1) and (2) even for @system use in any project I have control over.

Therefore, whether you agree with where I drew the line or not, this is a subjective decision not an objective one.
April 14, 2020
On 4/13/2020 5:25 AM, Steven Schveighoffer wrote:
> For instance:
> 
> void foo()
> {
>      int*[] b;
>      int a;
>      b ~= &a;
>          // use b but don't expose it outside foo
> }
> 
> There are no memory safety violations there.
> The first case is highly useful, as one often needs scratch space to perform complex calculations or graph algorithms. I see no reason to disallow it.

I see a reason:

 void foo()
 {
    int*[1] b = void;
    int a;
    b[0] = &a;
 }

It's faster, too. And if it is written as:

 &safe void foo()
 {
    int a;
    int*[1] b;
    b[0] = &a;
 }

it's even @safe (with -preview=dip1000).

I know, I know, this isn't the real use case. But I've done plenty of "use scratch data structures on the stack" programming for speed and I know how to make it work without needing to store addresses in GC objects.
April 14, 2020
On 4/14/20 5:56 AM, Walter Bright wrote:
> On 4/13/2020 2:03 AM, Timon Gehr wrote:
>>> Consider:
>>>
>>>    @system int* pumpkin(int i) { return &i; }
>>>
>>> Should that give an error or not?
>>> ...
>>
>> I don't see why not.
> 
> I've written code like that to get the stack pointer value.

Can't you use inline assembly?

> 
> As to the other case, to my mind putting the address of a stack local into a GC allocated object is highly suspicious:
> 
> 1. it is very very easy to do it unintentionally
> 
> 2. GC objects tend to be intended to outlast a function, yet the stack address will not, so why is this a GC allocated object, as opposed to, say, an RAII object or even a stack allocated object?

Because the stack doesn't provide a high limit of data space, and RAII may not be what you want to use. In @system code, you should be free to shoot yourself in the foot, and also to correctly write memory safe code knowing where memory will stop being accessed.

-Steve
April 14, 2020
On Tuesday, 14 April 2020 at 12:32:18 UTC, Steven Schveighoffer wrote:
> On 4/14/20 5:56 AM, Walter Bright wrote:
>> On 4/13/2020 2:03 AM, Timon Gehr wrote:
>>>> Consider:
>>>>
>>>>    @system int* pumpkin(int i) { return &i; }
>>>>
>>>> Should that give an error or not?
>>>> ...
>>>
>>> I don't see why not.
>> 
>> I've written code like that to get the stack pointer value.
>
> Can't you use inline assembly?

You can cast at least:

ptrdiff_t f(int i) { return cast(ptrdiff_t)&i; }

Also,

I tried annotating that with @safe but it didn't work. What's the danger of casting the address of a variable to an integer type thing?

(I know that I can use @trusted as a work around)

>
>> 
>> As to the other case, to my mind putting the address of a stack local into a GC allocated object is highly suspicious:
>> 
>> 1. it is very very easy to do it unintentionally
>> 
>> 2. GC objects tend to be intended to outlast a function, yet

GC objects are a matter of convenience and safety and are using within function scopes all the time.

>> the stack address will not, so why is this a GC allocated object, as opposed to, say, an RAII object or even a stack allocated object?
>
> Because the stack doesn't provide a high limit of data space, and RAII may not be what you want to use. In @system code, you should be free to shoot yourself in the foot, and also to correctly write memory safe code knowing where memory will stop being accessed.
>
> -Steve

Another reason, you may not know how big your array is and need to rely on the GC (or manual memory management but the GC is just much more easier and safer to use)


April 14, 2020
On Tuesday, 14 April 2020 at 09:56:39 UTC, Walter Bright wrote:
> As to the other case, to my mind putting the address of a stack local into a GC allocated object is highly suspicious:
>
> 1. it is very very easy to do it unintentionally

Indeed, but isn't that what @safe is for? There should be a way do it intentionally, to tell the compiler "trust me". That's my main point with this thread - D is being overbearing now.

"Copy the pointer to that array please, D."

"I'm afraid I can't do that, Adam."

https://www.youtube.com/watch?v=ARJ8cAGm6JE
April 14, 2020
On Tuesday, 14 April 2020 at 13:34:00 UTC, Adam D. Ruppe wrote:
> On Tuesday, 14 April 2020 at 09:56:39 UTC, Walter Bright wrote:
>> As to the other case, to my mind putting the address of a stack local into a GC allocated object is highly suspicious:
>>
>> 1. it is very very easy to do it unintentionally
>
> Indeed, but isn't that what @safe is for? There should be a way do it intentionally, to tell the compiler "trust me". That's my main point with this thread - D is being overbearing now.
>
> "Copy the pointer to that array please, D."
>
> "I'm afraid I can't do that, Adam."
>
> https://www.youtube.com/watch?v=ARJ8cAGm6JE

+1 Most of us aren't writing web browsers and probably none of us are working on airplanes. Give us enough rope to shoot ourselves in the foot. If I wanted a language to tell me how to program, I'd still be using Go.
April 14, 2020
On 4/14/20 6:08 AM, Walter Bright wrote:
> On 4/13/2020 5:25 AM, Steven Schveighoffer wrote:
>> For instance:
>>
>> void foo()
>> {
>>      int*[] b;
>>      int a;
>>      b ~= &a;
>>          // use b but don't expose it outside foo
>> }
>>
>> There are no memory safety violations there.
>> The first case is highly useful, as one often needs scratch space to perform complex calculations or graph algorithms. I see no reason to disallow it.
> 
> I see a reason:
> 
>   void foo()
>   {
>      int*[1] b = void;
>      int a;
>      b[0] = &a;
>   }

The toy cases aren't real cases, they just show the error and that the usage is safe.

We are not trying to solve the toy. Of course, adding one element to an array and doing nothing is not the real case. I'm talking about maybe an array of millions of pointers, some of which are on the stack (consider like a linked list where you store the head on the stack), and ensuring the array doesn't escape the function.

> 
> It's faster, too. And if it is written as:
> 
>   &safe void foo()
>   {
>      int a;
>      int*[1] b;
>      b[0] = &a;
>   }
> 
> it's even @safe (with -preview=dip1000).
> 
> I know, I know, this isn't the real use case. But I've done plenty of "use scratch data structures on the stack" programming for speed and I know how to make it work without needing to store addresses in GC objects.

It's not about knowing how to do it other ways, or doing it the fastest way. It's about knowing how to do it correctly *this* way. Maybe I don't want to deal with having to ensure things are freed properly. What if my graph algorithm has cycles, will RAII (e.g. RefCounted) take care of that? If you do it right with the GC, then there are no memory issues, why is the compiler stopping that in @system code? @system is supposed to be "I know what I am doing".

The answer to "why won't @system let me write this memory safe code?" shouldn't be "you're doing it wrong". That's factually incorrect, and the compiler shouldn't bug me about it. Especially when it's trivially circumvented. @safe is for compiler checks for safety.

That being said, I agree with the simple case of returning a pointer from a stack variable directly from a function being disallowed. That also can be easily worked around, which should probably be required, but is never correct anyway.

-Steve
April 14, 2020
On 4/14/2020 6:34 AM, Adam D. Ruppe wrote:
> Indeed, but isn't that what @safe is for? There should be a way do it intentionally, to tell the compiler "trust me". That's my main point with this thread - D is being overbearing now.
> 
> "Copy the pointer to that array please, D."


So, Adam, how do you feel about:

  @system int* pumpkin(int i) { return &i);

Timon says that should be an error. What is your opinion?
April 14, 2020
On 4/14/2020 10:16 AM, Steven Schveighoffer wrote:
> That being said, I agree with the simple case of returning a pointer from a stack variable directly from a function being disallowed. That also can be easily worked around, which should probably be required, but is never correct anyway.

Oh, it can be correct, when one wants to examine the stack pointer value. I've used it for that purpose myself. (Examining the stack pointer is valuable when determining whether other pointers are pointing into the stack or not.)

As I replied to Timon, you're drawing a subjective (not objective) line at what is acceptable or not.