www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Manually allocating a File

reply Chris M. <chrismohrfeld comcast.net> writes:
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__lambda1ZQCkMFAxPyS6
bject10ModuleInfoZv ()
    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?
Feb 20
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
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...
Feb 20
parent reply Chris M. <chrismohrfeld comcast.net> writes:
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
Feb 20
parent reply Nicholas Wilson <iamthewilsonator hotmail.com> writes:
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.
Feb 20
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
Feb 20
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
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
Feb 21
prev sibling parent reply Uknown <sireeshkodali1 gmail.com> writes:
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__lambda1ZQCkMFAxPyS6
bject10ModuleInfoZv ()
    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
Feb 20
parent Uknown <sireeshkodali1 gmail.com> writes:
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...
Feb 20