June 13, 2019
On 13.06.19 02:18, Timon Gehr wrote:
> int foo()@safe pure{
>      int x=void;
>      return x;
> }
> 
> Any code that is optimized based on the assumption that `foo()` will always return the same value will have undefined behavior, including the possibility of buffer overflows or dangling pointers.

In the same vein:

size_t foo() @safe pure
{
    return cast(size_t) new int;
}
June 13, 2019
On 6/11/2019 7:37 AM, ag0aep6g wrote:
> The spec very much defines @safe as "no undefined behavior".
> 
> <https://dlang.org/spec/function.html#function-safety>: "Safe functions are functions that are statically checked to exhibit no possibility of undefined behavior."

The spec's wrong, because it doesn't do that.
June 13, 2019
On 6/11/2019 11:16 AM, Manu wrote:
> You've missed my entire point. I understand memory safety is a thing,
> I'm saying I don't care for @safe defined that narrowly. Common sense
> would suggest that a "safe" function would alarm you to a blindingly
> obvious crash, and I don't care that that crash is specifically a
> memory safety violation or not. You can argue semantics, but nobody
> that's not a language lawyer who hangs out on forums like this would
> expect that.

When you get into details of how a language works, you put on the language lawyer hat, not your hand-wavy hat.

There's no other way.

Every science/engineering discipline finds it necessary to precisely nail down the meanings of terms, and not rely on hand-wavy definitions what prevent communication between engineers. For example, Boeing has a specific definition of what failing a load test is. Sounds silly, but there's a very good reason for it. Architectural drawings have very specific fonts that must be used. Again, good reasons.

(C++, now there's a language made for language lawyers. There are so many, many finicky rules. I have no idea how you can be successful with C++ and not be a language lawyer. How can you even talk to another C++ programmer?)

The D spec does have a problem with imprecise use of language. It's a PROBLEM and it needs fixing.
June 13, 2019
On Thursday, 13 June 2019 at 07:27:16 UTC, Walter Bright wrote:
> On 6/11/2019 7:37 AM, ag0aep6g wrote:
>> The spec very much defines @safe as "no undefined behavior".
>> 
>> <https://dlang.org/spec/function.html#function-safety>: "Safe functions are functions that are statically checked to exhibit no possibility of undefined behavior."
>
> The spec's wrong, because it doesn't do that.

No: the spec disagrees with the implementation, therefore at least one of them is wrong. It does not immediately follow that it is the spec that is in error.

If you have a race condition on a pointer write, and that write corrupts memory, then that is a memory safety bug that is also a thread safety bug.

In the world of multithreading, memory safety and thread safety are _not_ separable.

I know because we'e had a bug exposed by LDC breaking such optimisation that relied on that.
June 13, 2019
On Thursday, 13 June 2019 at 00:18:42 UTC, Timon Gehr wrote:
>> track allocated memory pointers. But that has nothing to do with undefined values for integers.
>
> Undefined values are not undefined behavior.

Let's try to sort out the terminology, because it seems to cause a lot of noise:

Integers don't have undefined values. An integer variable might provide an arbitrary value, but  it does not matter what it is if you use an algorithm that always multiply by 0 in the first iteration then assigns the variable a new value…

If the value was truly undefined, then it could cause undefined behaviour, because then the hardware might not have a specified consequence for its usage (so it could in theory vary between different revisions of the CPU).

But undefined behaviour does not mean that anything can happen, it just means that the spec does not say what will happen. The hardware vendor or compiler implementor could make that deterministic and explicit in the docs.

So, since C is meant to produce fast code for all kinds of hardware you have "implementation defined", which means that compiler implementors are required to define and document it. Then you have "undefined", which means that the implementors are not required to define and document it.

June 13, 2019
On Thursday, 13 June 2019 at 09:48:20 UTC, Ola Fosheim Grøstad wrote:
> Integers don't have undefined values. An integer variable might provide an arbitrary value, but  it does not matter what it is

Just to avoid further confusion, D presumes an integer representation that use all the combinations of bits available.

C does not presume a specific integer representation, so in C you could in theory have undefined bitpatterns for integer variables on very odd or old architectures.

In D you can't.

So there is a difference there.
June 13, 2019
On 13.06.19 02:37, Walter Bright wrote:
> On 6/12/2019 5:18 PM, Timon Gehr wrote:
>> Undefined values are not undefined behavior.
> 
> I think that is the salient point. You're right.
> 
> 
>> However, there are potential problems, based on which properties you want to assume that strongly pure functions have:
>>
>> int foo()@safe pure{
>>      int x=void;
>>      return x;
>> }
>>
>> Any code that is optimized based on the assumption that `foo()` will always return the same value will have undefined behavior, including the possibility of buffer overflows or dangling pointers.
> 
> Optimizing it means caching the returned value. I don't see how that can lead to undefined behavior.

E.g., in principle, an optimizer can end up caching the result of the bounds check but not the result of the function call for something like a[foo()]+a[foo()]. (The particular example could be more involved, the point is that it is possible that the optimizer only partially applies the available information.)
June 13, 2019
On 13.06.19 08:11, ag0aep6g wrote:
> On 13.06.19 02:18, Timon Gehr wrote:
>> int foo()@safe pure{
>>      int x=void;
>>      return x;
>> }
>>
>> Any code that is optimized based on the assumption that `foo()` will always return the same value will have undefined behavior, including the possibility of buffer overflows or dangling pointers.
> 
> In the same vein:
> 
> size_t foo() @safe pure
> {
>      return cast(size_t) new int;
> }

Yes. IMHO this shouldn't be a @safe pure operation.
June 13, 2019
On 13.06.19 09:27, Walter Bright wrote:
> On 6/11/2019 7:37 AM, ag0aep6g wrote:
>> The spec very much defines @safe as "no undefined behavior".
>>
>> <https://dlang.org/spec/function.html#function-safety>: "Safe functions are functions that are statically checked to exhibit no possibility of undefined behavior."
> 
> The spec's wrong, because it doesn't do that.

So the spec needs an addendum?

Surely it's correct that @safe code can't be allowed to exhibit undefined behavior. What else do we have to disallow? How can one corrupt memory without relying on undefined behavior?
June 13, 2019
On Thursday, 13 June 2019 at 08:24:38 UTC, Nicholas Wilson wrote:
> No: the spec disagrees with the implementation, therefore at least one of them is wrong. It does not immediately follow that it is the spec that is in error.

It's reasonable to say in this case that the spec is in error, because Walter has always been 100% clear that @safe refers only to memory safety, and the implementation reflects that intent.

> If you have a race condition on a pointer write, and that write corrupts memory, then that is a memory safety bug that is also a thread safety bug.
>
> In the world of multithreading, memory safety and thread safety are _not_ separable.
>
> I know because we'e had a bug exposed by LDC breaking such optimisation that relied on that.

There's certainly a reasonable case for trying to support constraints that rule out undefined behaviour, but let's make that case in the understanding that we're asking for something new, not something that was always intended to be part of the language spec.