July 25, 2017
On 07/25/2017 10:43 AM, ag0aep6g wrote:
> On 07/25/2017 04:32 PM, Shachar Shemesh wrote:
>> And, indeed, the code calling "read" shouldn't be able to do that as @safe. Read itself, however, is trusted (because, let's face it, if you cannot trust the kernel, you're screwed anyways).
> 
> That's not how `@trusted` works. The point of `@trusted` is to allow unsafe features in the implementation. The interface must be just as safe as with `@safe`.
> 
> `read` doesn't have a safe interface. `read` is safe as long as long as you pass good arguments. When you pass bad arguments, `read` will break your stuff. A `@trusted` function must always be safe, no matter the arguments.

About http://man7.org/linux/man-pages/man2/read.2.html, there's just a bit of wrapping necessary:

nothrow @trusted @nogc
ssize_t read(int fd, ubyte[] buf)
{
    return read(fd, buf.ptr, buf.length);
}

(btw void[] doesn't work)

The point being that a safe D program needs to guarantee memory will not be corrupted, and there's no way for the type system to ensure that in the Posix read() call the buffer and the length are coordinated.

Certain systems (such as the static checker used at Microsoft - it's fairly well known, there are a couple of papers on it, forgot the name) require annotations in the function signature to indicate the coordination, e.g.:

ssize_t read(int fd, void *buf, @islengthof(buf) size_t count);

Then the type checker can verify upon each call that indeed count is the right size of buf.

A suite of safe wrappers on OS primitives might be useful.


Andrei
July 25, 2017
On Tuesday, 25 July 2017 at 14:39:15 UTC, Shachar Shemesh wrote:
> On 25/07/17 17:24, Moritz Maxeiner wrote:
>> On Tuesday, 25 July 2017 at 13:50:16 UTC, Shachar Shemesh wrote:
>>> The title really does says it all.
>> 
>> Since you explicitly state *all* OS functions:
>> nothrow: Should be OK (only callbacks could violate this and they should be nothrow, anyway).
> Technically, any system call that is a pthreads cancellation point may throw a C++ exception.

Good to know, then since D is supposed to be able to catch C++ exceptions (and can on 64bit Linux [1]) none of those may be attributed as `nothrow`, because C++ exceptions don't derive from `Error`.

>
> If we go down that route, however, calling system calls from nothrow becomes completely impossible, which is another way of saying that decorating just about anything with nothrow becomes impossible.

No. `nothrow` functions can call throwing ones, as long as they catch any exceptions not derived from Error thrown by them.

>
>> @trusted: This can only be done for those functions that don't take arguments open to memory corruption. Take a look at POSIX read, it can never be trusted (same as any C function taking pointer+length of pointed to).
>> @nogc: This can only be done for those functions that are statically known to never call a D callback that's not also @nogc. Take a look at pthread_create vor pthread_join, they can never be @nogc, because that would mean threads may never allocate with the GC.
>
> The decoration's situation with callbacks is pretty horrible throughout D.

Do you mean throughout druntime and phobos?

> I'm not sure this is the most compelling argument, however. The function passed to pthread_create does not, logically, run in the pthread_create function. As such, I don't think this logic holds.

Then the @nogc definition would need to be updated from: "or indirectly through functions it may call" to reflect this, because that can be interpreted both ways.

>
> As for pthread_join, I have no idea what you meant by it. Please elaborate why you think it is a problem.

Possible scenario on single core (no hyperthreading) system:
- thread 1 spawns thread 2
- thread 1 enters @nogc function `foo` and calls `pthread_join` on thread 2 before its own timeslice is over (and thus enters blocked state)
- thread 2 does work allocating via the GC, then terminates
- thread 1 wakes up and leaves @nogc function `foo`

Because @nogc (in contrast to nothrow) is explicitly designed as transitive, logically speaking, `foo` violated its @nogc constraint (it *caused* the GC allocations in thread 2).

>
>> 
>> ---
>> auto result = () @trusted { return systemFunction(...) }();
>> ---
>
> Care to explain how to adapt that neat trick for "nothrow" and "@nogc"?

nothrow: assumeWontThrow [2]
@nogc: assumeNoGC [3]

[1] http://forum.dlang.org/thread/n7jorc$1ied$1@digitalmars.com
[2] https://dlang.org/library/std/exception/assume_wont_throw.html
[3] https://p0nce.github.io/d-idioms/#Bypassing-@nogc
July 25, 2017
On 7/25/17 11:26 AM, Andrei Alexandrescu wrote:
> 
> About http://man7.org/linux/man-pages/man2/read.2.html, there's just a bit of wrapping necessary:
> 
> nothrow @trusted @nogc
> ssize_t read(int fd, ubyte[] buf)
> {
>      return read(fd, buf.ptr, buf.length);
> }
> 
> (btw void[] doesn't work)
> 
[snip]
> A suite of safe wrappers on OS primitives might be useful.

Great idea! Should it be a package on its own, or should we put the wrappers inside the original files?

That is, do we make

core.sys.safe.posix.unistd: read

or do we make

core.sys.posix.unistd: safe_read

?

My preference is for the former, since it's very nice to have a pristine copy of the header file.

-Steve
July 25, 2017
While we're at it, check this: https://github.com/dlang/druntime/blob/master/src/core/stdc/stdio.d#L1047
July 25, 2017
On Tuesday, 25 July 2017 at 15:12:30 UTC, Steven Schveighoffer wrote:
> I think signalfd can be marked @trusted, as @safe code supports pointing at a single element.

What about functions that take zero terminated strings? Are they ok to read past the end of allocated object?
July 25, 2017
On 7/25/17 12:14 PM, Kagamin wrote:
> While we're at it, check this: https://github.com/dlang/druntime/blob/master/src/core/stdc/stdio.d#L1047

Looks fine to me. That's not an array of FILE, it's a single pointer.

-Steve
July 25, 2017
On 7/25/17 12:46 PM, Kagamin wrote:
> On Tuesday, 25 July 2017 at 15:12:30 UTC, Steven Schveighoffer wrote:
>> I think signalfd can be marked @trusted, as @safe code supports pointing at a single element.
> 
> What about functions that take zero terminated strings? Are they ok to read past the end of allocated object?

No, a null terminated string is as arbitrary as passing in a length.

Unfortunately, it's perfectly safe to call with a string literal. But there is no way to detect that during compile time. So it has to be unsafe.

The wrapper would be to use toStringz to make the call.

-Steve
July 25, 2017
On 07/25/2017 11:50 AM, Steven Schveighoffer wrote:
> On 7/25/17 11:26 AM, Andrei Alexandrescu wrote:
>>
>> About http://man7.org/linux/man-pages/man2/read.2.html, there's just a bit of wrapping necessary:
>>
>> nothrow @trusted @nogc
>> ssize_t read(int fd, ubyte[] buf)
>> {
>>      return read(fd, buf.ptr, buf.length);
>> }
>>
>> (btw void[] doesn't work)
>>
> [snip]
>> A suite of safe wrappers on OS primitives might be useful.
> 
> Great idea! Should it be a package on its own, or should we put the wrappers inside the original files?
> 
> That is, do we make
> 
> core.sys.safe.posix.unistd: read
> 
> or do we make
> 
> core.sys.posix.unistd: safe_read
> 
> ?
> 
> My preference is for the former, since it's very nice to have a pristine copy of the header file.

Same here. I'd preserve the function name though. -- Andrei
July 25, 2017
On 07/25/2017 12:14 PM, Kagamin wrote:
> While we're at it, check this: https://github.com/dlang/druntime/blob/master/src/core/stdc/stdio.d#L1047

That might be a mistake. Is fclose(f); getc(f); defined? -- Andrei
July 25, 2017
On 7/25/17 2:14 PM, Andrei Alexandrescu wrote:
> On 07/25/2017 12:14 PM, Kagamin wrote:
>> While we're at it, check this: https://github.com/dlang/druntime/blob/master/src/core/stdc/stdio.d#L1047
> 
> That might be a mistake. Is fclose(f); getc(f); defined? -- Andrei

fclose is not @safe.

The charter of @safe (or @trusted in this case) is to assume valid pointers for parameters.

-Steve