Thread overview
Manually allocating a File
Feb 20, 2018
Chris M.
Feb 20, 2018
Adam D. Ruppe
Feb 20, 2018
Chris M.
Feb 21, 2018
Nicholas Wilson
Feb 21, 2018
Jonathan M Davis
Feb 20, 2018
Uknown
Feb 20, 2018
Uknown
February 20, 2018
I'm doing this mainly for experimentation, but the following piece of code gives all sorts of errors. Hangs, segfaults or prints nothing and exits

import std.stdio;
import core.stdc.stdlib;

void main()
{
    auto f = cast(File *) malloc(File.sizeof);
    *f = File("test.txt", "r");
    (*f).readln.writeln;
    // freeing is for chumps
}

I could have sworn I've done something similar recently and it worked, unfortunately I can't remember what the case was.

This is what gdb gave me on a segfault

Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a56c32 in _D2rt5minfo__T17runModuleFuncsRevSQBgQBg11ModuleGroup8runDtorsMFZ9__lambda1ZQCkMFAxPyS6object10ModuleInfoZv ()
   from /usr/lib64/libphobos2.so.0.78

So it looks like it's reaching the end of main. Past that I can't tell what's going on. Ideas?
February 20, 2018
On Tuesday, 20 February 2018 at 14:56:54 UTC, Chris M. wrote:
> I'm doing this mainly for experimentation, but the following piece of code gives all sorts of errors.

so important note: this will perform worse than the automatic allocation, which just puts it down in-place. You should basically never `new` or `malloc` a `File` struct. (in fact, i think we should @disable new on it! yes, D can do that!)


>     auto f = cast(File *) malloc(File.sizeof);
>     *f = File("test.txt", "r");

Two notes here: 1) it will call the destructor on *f, which is uninitialized data and 2) the destructor that actually wants to run will have to wait until the GC reaps it, which is also not ideal. The segfault you see is in #2 here, though I'm not sure exactly what is causing it, could be out-of-order, could be some other corruption, idk.

Generally, when manually allocating D objects, first malloc it, then copy the `.init` value over, before casting it to the other type - do all this as bytes so it doesn't trigger postblits, destructors, etc like a real struct. The `std.conv.emplace` function from phobos does this and its source code can help you see how in a few cases.

>     (*f).readln.writeln;

That * is unnecessary btw, in D you can

f.readln

and it will see it is a pointer to struct and dereference it for you.


> I could have sworn I've done something similar recently and it worked, unfortunately I can't remember what the case was.

With other types, you can do this, but File is designed to be used in-place...
February 20, 2018
On Tuesday, 20 February 2018 at 14:56:54 UTC, Chris M. wrote:
> I'm doing this mainly for experimentation, but the following piece of code gives all sorts of errors. Hangs, segfaults or prints nothing and exits
>
> import std.stdio;
> import core.stdc.stdlib;
>
> void main()
> {
>     auto f = cast(File *) malloc(File.sizeof);
>     *f = File("test.txt", "r");
>     (*f).readln.writeln;
>     // freeing is for chumps
> }
>
> I could have sworn I've done something similar recently and it worked, unfortunately I can't remember what the case was.
>
> This is what gdb gave me on a segfault
>
> Program received signal SIGSEGV, Segmentation fault.
> 0x00007ffff7a56c32 in _D2rt5minfo__T17runModuleFuncsRevSQBgQBg11ModuleGroup8runDtorsMFZ9__lambda1ZQCkMFAxPyS6object10ModuleInfoZv ()
>    from /usr/lib64/libphobos2.so.0.78
>
> So it looks like it's reaching the end of main. Past that I can't tell what's going on. Ideas?

File * is a C standard library type. You mixed the C standard library and D standard library in a way that would not work.

The correct way to initialize a File*:

void main()
{
    import core.stdc.stdlib;
    auto F = fopen("test.txt", "r");
    scope_exit(fclose(f));

    //Reading from the file:

    char[100] str;
    fgets(&s[0], s.length, f);
}

Honestly speaking though you should avoid using the C library when you can use th D standard library.

You can read more on the C standard library and how to use it here:
http://en.cppreference.com/w/c/io
February 20, 2018
On Tuesday, 20 February 2018 at 15:21:59 UTC, Uknown wrote:
> On Tuesday, 20 February 2018 at 14:56:54 UTC, Chris M. wrote:
> void main()
> [snip]

Never mind, I confused FILE* with File...
February 20, 2018
On Tuesday, 20 February 2018 at 15:18:11 UTC, Adam D. Ruppe wrote:
> On Tuesday, 20 February 2018 at 14:56:54 UTC, Chris M. wrote:
>> I'm doing this mainly for experimentation, but the following piece of code gives all sorts of errors.
>
> so important note: this will perform worse than the automatic allocation, which just puts it down in-place. You should basically never `new` or `malloc` a `File` struct. (in fact, i think we should @disable new on it! yes, D can do that!)
>
>
>>     auto f = cast(File *) malloc(File.sizeof);
>>     *f = File("test.txt", "r");
>
> Two notes here: 1) it will call the destructor on *f, which is uninitialized data and 2) the destructor that actually wants to run will have to wait until the GC reaps it, which is also not ideal. The segfault you see is in #2 here, though I'm not sure exactly what is causing it, could be out-of-order, could be some other corruption, idk.
>
> Generally, when manually allocating D objects, first malloc it, then copy the `.init` value over, before casting it to the other type - do all this as bytes so it doesn't trigger postblits, destructors, etc like a real struct. The `std.conv.emplace` function from phobos does this and its source code can help you see how in a few cases.

Thanks for the info, that clears things up. Like I said, it was more experimentation rather than me planning to actually use it. Works now with the following modifications.

import std.stdio;
import core.stdc.stdlib;
import std.conv;

void main()
{
    auto f = cast(File*) malloc(File.sizeof);
    emplace!File(f, "test.txt", "r");
    f.readln.write;
    free(f);
}

>>     (*f).readln.writeln;
>
> That * is unnecessary btw, in D you can
>
> f.readln
>
> and it will see it is a pointer to struct and dereference it for you.

That's what I had originally, but I put the * in to see if it would help with the original issue and never removed it


February 21, 2018
On Tuesday, 20 February 2018 at 15:32:45 UTC, Chris M. wrote:
> Thanks for the info, that clears things up. Like I said, it was more experimentation rather than me planning to actually use it. Works now with the following modifications.
>
> import std.stdio;
> import core.stdc.stdlib;
> import std.conv;
>
> void main()
> {
>     auto f = cast(File*) malloc(File.sizeof);
>     emplace!File(f, "test.txt", "r");
>     f.readln.write;
>     free(f);
> }
>
>>>     (*f).readln.writeln;
>>
>> That * is unnecessary btw, in D you can
>>
>> f.readln
>>
>> and it will see it is a pointer to struct and dereference it for you.
>
> That's what I had originally, but I put the * in to see if it would help with the original issue and never removed it

FYI, File is a reference counted FILE* so theres not really any point of heap allocating it.
February 20, 2018
On Wednesday, February 21, 2018 02:59:21 Nicholas Wilson via Digitalmars-d- learn wrote:
> On Tuesday, 20 February 2018 at 15:32:45 UTC, Chris M. wrote:
> > Thanks for the info, that clears things up. Like I said, it was more experimentation rather than me planning to actually use it. Works now with the following modifications.
> >
> > import std.stdio;
> > import core.stdc.stdlib;
> > import std.conv;
> >
> > void main()
> > {
> >
> >     auto f = cast(File*) malloc(File.sizeof);
> >     emplace!File(f, "test.txt", "r");
> >     f.readln.write;
> >     free(f);
> >
> > }
> >
> >>>     (*f).readln.writeln;
> >>
> >> That * is unnecessary btw, in D you can
> >>
> >> f.readln
> >>
> >> and it will see it is a pointer to struct and dereference it for you.
> >
> > That's what I had originally, but I put the * in to see if it would help with the original issue and never removed it
>
> FYI, File is a reference counted FILE* so theres not really any point of heap allocating it.

And worse, simply calling free does not run the File's destructor, so simply using malloc to allocate it and free to free is not going to result in File functioning properly. If someone were going to just use the C API and not use std.stdio.File, then using malloc and free with FILE might make sense, but it really doesn't make sense with File.

- Jonathan M Davis

February 21, 2018
On 2/20/18 9:59 PM, Nicholas Wilson wrote:
> 
> FYI, File is a reference counted FILE* so theres not really any point of heap allocating it.

More FYI, the reference counted payload is actually allocated on the C heap :) So you are wasting a lot of effort to do something that is already done.

-Steve