Thread overview
Using array slices with C-style fread() from file
Jun 21, 2017
uncorroded
Jun 21, 2017
tetyys
Jun 21, 2017
tetyys
Jun 21, 2017
uncorroded
Jun 21, 2017
Ali Çehreli
Jun 21, 2017
uncorroded
Jun 21, 2017
Ali Çehreli
Jun 21, 2017
Ali Çehreli
June 21, 2017
Hi all,

I am writing a program to read device /dev/urandom file to get some random bytes. I am trying to bypass D's GC as I know the length of the buffer needed. I tried using std.stdio.File and rawRead but File cannot be used with @nogc. So I used core.stdc.stdio and used traditional C style. My code is here - https://dpaste.dzfl.pl/36e1df4cb99b (Also at end of post). I am using fread instead of read because /dev/urandom can be accessed by other programs (From this post - http://insanecoding.blogspot.in/2014/05/a-good-idea-with-bad-usage-devurandom.html ). As you can see from code, I ended up doing pointer arithmetic. Is there a way of making this work with D slices? Can they be used as C-style pointers?

My D function used for getting random bytes:

@nogc ubyte[n] rand_bytes(uint n)() {
    import core.stdc.stdio;
    FILE *fp;
    fp = fopen("/dev/urandom", "r");
    ubyte[n] buf;
    ubyte *bp = &buf[0];
    uint bread = 0;
    while (bread < n) {
        auto toread = n - bread;
        auto read = fread(bp, ubyte.sizeof, toread, fp);
        bread += read;
        bp += read;
    }
    fclose(fp);
    return buf;
}
June 21, 2017
On Wednesday, 21 June 2017 at 18:49:01 UTC, uncorroded wrote:
> Is there a way of making this work with D slices? Can they be used as C-style pointers?

What about this:

@nogc ubyte[n] rand_bytes(uint n)() {
    import core.stdc.stdio;
    FILE *fp;
    fp = fopen("/dev/urandom", "r");
    ubyte[n] buf;
    uint bread = 0;
    while (bread < n) {
        auto toread = n - bread;
        auto read = fread(buf[bread .. $].ptr, ubyte.sizeof, toread, fp);
        bread += read;
    }
    fclose(fp);
    return buf;
}

?
June 21, 2017
- Fixed-length arrays are value types. You may not want to return them if n is very large.

- Every array has the .ptr property that gives the pointer to the first element.

- What can be helpful to you here is the fact that you can treat any memory as a slice:

import core.stdc.stdlib;

struct S {
    double d;
}

void main() {
    ubyte * p = cast(ubyte*)malloc(10);
    ubyte[] slice = p[0..10];    // 10 is number of elements

    // Another example with a struct object:
    auto objectCount = 7;
    S * objects = cast(S*)malloc(objectCount * S.sizeof);
    auto S_slice = objects[0..objectCount];
}

Of course, you must be careful with slice lifetimes in this case; you shouldn't use the slices after freeing the memory.

Ali

June 21, 2017
On Wednesday, 21 June 2017 at 18:58:58 UTC, tetyys wrote:
> On Wednesday, 21 June 2017 at 18:49:01 UTC, uncorroded wrote:
>> Is there a way of making this work with D slices? Can they be used as C-style pointers?
>
> What about this
>

Or simpler,

while (left)
    left -= fread(buf[n-left .. $].ptr, ubyte.sizeof, left, fp);
June 21, 2017
On Wednesday, 21 June 2017 at 18:58:58 UTC, tetyys wrote:
> On Wednesday, 21 June 2017 at 18:49:01 UTC, uncorroded wrote:
>> Is there a way of making this work with D slices? Can they be used as C-style pointers?
>
> What about this:
>
> @nogc ubyte[n] rand_bytes(uint n)() {
>     import core.stdc.stdio;
>     FILE *fp;
>     fp = fopen("/dev/urandom", "r");
>     ubyte[n] buf;
>     uint bread = 0;
>     while (bread < n) {
>         auto toread = n - bread;
>         auto read = fread(buf[bread .. $].ptr, ubyte.sizeof, toread, fp);
>         bread += read;
>     }
>     fclose(fp);
>     return buf;
> }
>
> ?

Thanks a lot! That works. Did not know about the .ptr for a slice. Is there any way of making the function with @safe as well? I get the errors "cannot call @system function 'core.stdc.stdio.fread,fopen,fclose'.
June 21, 2017
On 06/21/2017 12:06 PM, uncorroded wrote:

> Is
> there any way of making the function with @safe as well? I get the
> errors "cannot call @system function 'core.stdc.stdio.fread,fopen,fclose'.

@trusted is exactly for that. It can be called from @safe code:

@trusted @nogc ubyte[n] rand_bytes(uint n)() {
    // ...
}

@safe auto foo() {
    return rand_bytes!3();
}

Ali

June 21, 2017
On Wednesday, 21 June 2017 at 19:11:44 UTC, Ali Çehreli wrote:
> On 06/21/2017 12:06 PM, uncorroded wrote:
>
> > Is
> > there any way of making the function with @safe as well? I
> get the
> > errors "cannot call @system function
> 'core.stdc.stdio.fread,fopen,fclose'.
>
> @trusted is exactly for that. It can be called from @safe code:
>
> @trusted @nogc ubyte[n] rand_bytes(uint n)() {
>     // ...
> }
>
> @safe auto foo() {
>     return rand_bytes!3();
> }
>
> Ali

Thanks! So @trusted is me guaranteeing to the compiler that this function is safe? Is there any way of auditing this code through valgrind, etc. Also, thanks a lot for your book on D. It has been an invaluable resource in getting me started.
June 21, 2017
On 06/21/2017 12:20 PM, uncorroded wrote:

> So @trusted is me guaranteeing to the compiler that this
> function is safe?

Yes and you shouldn't lie. :)

> Is there any way of auditing this code through
> valgrind, etc.

That's a good idea, which you can do yourself but I don't think you can be sure beyond the tests that you've ran. There can always be corner cases where the library you use may not be memory-safe. You have to trust... :)

> invaluable resource in getting me started.

Thank you! Makes me very happy to hear that. :)

Ali