@trust is an encapsulation method, not an escape

Zach the Mystic via Digitalmars-d digitalmars-d at puremagic.com
Fri Feb 6 21:35:49 PST 2015


On Saturday, 7 February 2015 at 01:41:19 UTC, Andrei Alexandrescu 
wrote:
> Consider the previous code:
> [...]
>     static trustedRead(int fildes, void* buf, size_t nbyte) 
> @trusted
>     {
>         return core.sys.posix.unistd.read(fildes, buf, nbyte);
>     }
>     static trustedRealloc(void* p, size_t sz, uint ba = 0, 
> const TypeInfo ti = null) @trusted
>     {
>         return GC.realloc(p, sz, ba, ti);
>     }
>     static trustedPtrAdd(void[] buf, size_t s) @trusted
>     {
>         return buf.ptr+s;
>     }
>     static trustedPtrSlicing(void* ptr, size_t lb, size_t ub) 
> @trusted
>     {
>         return ptr[lb..ub];
>     }

First of all, these little @trusted functions are made obsolete 
by the new system. They should certainly be omitted.

>     @system
>     {
>         immutable fd = 
> core.sys.posix.fcntl.open(name.tempCString(),
>             core.sys.posix.fcntl.O_RDONLY);
>     }

Next, you have to realize that @system blocks are like 'try' 
blocks: You don't need brackets if there's only one statement in 
them.

Here's how I would rewrite what you have written using the new 
method:

version (Posix) void[] read(in char[] name, size_t upTo = 
size_t.max)
@trusted
{
     import core.memory;
     // A few internal configuration parameters {
     enum size_t
         minInitialAlloc = 1024 * 4,
         maxInitialAlloc = size_t.max / 2,
         sizeIncrement = 1024 * 16,
         maxSlackMemoryAllowed = 1024;
     // }

     @system immutable fd = 
core.sys.posix.fcntl.open(name.tempCString(),
             core.sys.posix.fcntl.O_RDONLY);
     cenforce(fd != -1, name);
     scope(exit) core.sys.posix.unistd.close(fd);

     stat_t statbuf = void;
     @system cenforce(trustedFstat(fd, trustedRef(statbuf)) == 0, 
name);

     immutable initialAlloc = to!size_t(statbuf.st_size
         ? min(statbuf.st_size + 1, maxInitialAlloc)
         : minInitialAlloc);
     void[] result = uninitializedArray!(ubyte[])(initialAlloc);
     scope(failure) delete result;
     size_t size = 0;

     for (;;)
     {
         @system immutable actual = core.sys.posix.unistd.read(fd,
                 result.ptr + size, min(result.length, upTo) - 
size);
         cenforce(actual != -1, name);
         if (actual == 0) break;
         size += actual;
         if (size < result.length) continue;
         immutable newAlloc = size + sizeIncrement;
         @system result = GC.realloc(
                 result.ptr, newAlloc, GC.BlkAttr.NO_SCAN)[0 .. 
newAlloc];
     }

     @system return result.length - size >= maxSlackMemoryAllowed
         ? GC.realloc(result.ptr, size, 
GC.BlkAttr.NO_SCAN)[0..size]
             : result[0 .. size];
}

Note that I just mechanically your @system blocks with the better 
form. I didn't arrange for them to be elegant. There's nothing 
wrong with encapsulating a @trusted sequence in a @system block 
with brackets, to aid future reviewers in identifying subsequent 
code thought to be affected by the @system statements. Also, few 
functions will have their @system blocks more or less evenly 
distributed throughout like the above function does.

The new proposal will never let you add an unsafe operation 
without your knowing it. It's definitely the way forward.


More information about the Digitalmars-d mailing list