digitalmars.D.learn - Segmentation error at the end problem
- Charles Hixson (25/25) Jan 27 2009 Main routine:
- Gide Nwawudu (7/32) Jan 28 2009 I'm thinking it might be an issue with close and the dtor being called
- Charles Hixson (22/60) Jan 28 2009 I had to wriggle the code around a bit. (It's D2 not D1.) However it
- Gide Nwawudu (7/67) Jan 29 2009 Calling close and dtor on BufferedFile is the problem. Rewiting
- Charles Hixson (8/80) Jan 29 2009 I replaced BlockFile.close with:
- grauzone (8/16) Jan 30 2009 Your destructor calls close(), and close() accesses the reference bf.
- Charles Hixson (12/30) Jan 30 2009 Hmmm.... reasonable. Any idea how I should handle it? I want to ensure...
- grauzone (14/14) Jan 31 2009 The garbage collector isn't guaranteed to to free and destroy an
- Daniel Keep (8/26) Jan 31 2009 If you're going to do that, you really should make the it a scope class
- grauzone (10/38) Jan 31 2009 I think it'd be even better to make them different functions. The
- Daniel Keep (21/42) Jan 31 2009 Personally, I'd be happy if I could get this to work:
- Charles Hixson (25/53) Jan 31 2009 So after the discussion I decided that it appeared to make BlockFile
Main routine: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } Results in: Exiting BlockFile::this before close after close Exiting BlockFile::this after second open Segmentation fault I could post all the code. It's only 146 lines. But perhaps this is enough?
Jan 27 2009
On Tue, 27 Jan 2009 22:48:33 -0800, Charles Hixson <charleshixsn earthlink.net> wrote:Main routine: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } Results in: Exiting BlockFile::this before close after close Exiting BlockFile::this after second open Segmentation fault I could post all the code. It's only 146 lines. But perhaps this is enough?I'm thinking it might be an issue with close and the dtor being called on the same object. If you add std.gc.fullCollect() after the bf = null. Does that make the code seg fault before 'after close' is written? Gide
Jan 28 2009
Gide Nwawudu wrote:On Tue, 27 Jan 2009 22:48:33 -0800, Charles Hixson <charleshixsn earthlink.net> wrote:I had to wriggle the code around a bit. (It's D2 not D1.) However it didn't make any difference to do: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; GC.collect; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } ------------------- And the docs say that GC.collect does a full collect; P.S.: Attached is the full listingMain routine: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } Results in: Exiting BlockFile::this before close after close Exiting BlockFile::this after second open Segmentation fault I could post all the code. It's only 146 lines. But perhaps this is enough?I'm thinking it might be an issue with close and the dtor being called on the same object. If you add std.gc.fullCollect() after the bf = null. Does that make the code seg fault before 'after close' is written? Gide
Jan 28 2009
On Wed, 28 Jan 2009 13:37:40 -0800, Charles Hixson <charleshixsn earthlink.net> wrote:Gide Nwawudu wrote:Calling close and dtor on BufferedFile is the problem. Rewiting BlockFile.close as follows fixes the problem, but I think your code should work. void close() { delete bf; bf = null; } GideOn Tue, 27 Jan 2009 22:48:33 -0800, Charles Hixson <charleshixsn earthlink.net> wrote:I had to wriggle the code around a bit. (It's D2 not D1.) However it didn't make any difference to do: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; GC.collect; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } ------------------- And the docs say that GC.collect does a full collect; P.S.: Attached is the full listingMain routine: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } Results in: Exiting BlockFile::this before close after close Exiting BlockFile::this after second open Segmentation fault I could post all the code. It's only 146 lines. But perhaps this is enough?I'm thinking it might be an issue with close and the dtor being called on the same object. If you add std.gc.fullCollect() after the bf = null. Does that make the code seg fault before 'after close' is written? Gide
Jan 29 2009
Gide Nwawudu wrote:On Wed, 28 Jan 2009 13:37:40 -0800, Charles Hixson <charleshixsn earthlink.net> wrote:I replaced BlockFile.close with: void close() { if (bf !is null) delete bf; // bf.close; bf = null; } But that didn't alter the segmentation fault. (Did you try it under D1 or D2?)Gide Nwawudu wrote:Calling close and dtor on BufferedFile is the problem. Rewiting BlockFile.close as follows fixes the problem, but I think your code should work. void close() { delete bf; bf = null; } GideOn Tue, 27 Jan 2009 22:48:33 -0800, Charles Hixson <charleshixsn earthlink.net> wrote:I had to wriggle the code around a bit. (It's D2 not D1.) However it didn't make any difference to do: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; GC.collect; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } ------------------- And the docs say that GC.collect does a full collect; P.S.: Attached is the full listingMain routine: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } Results in: Exiting BlockFile::this before close after close Exiting BlockFile::this after second open Segmentation fault I could post all the code. It's only 146 lines. But perhaps this is enough?I'm thinking it might be an issue with close and the dtor being called on the same object. If you add std.gc.fullCollect() after the bf = null. Does that make the code seg fault before 'after close' is written? Gide
Jan 29 2009
Charles Hixson wrote:I replaced BlockFile.close with: void close() { if (bf !is null) delete bf; // bf.close; bf = null; } But that didn't alter the segmentation fault. (Did you try it under D1 or D2?)Your destructor calls close(), and close() accesses the reference bf. But accessing references is not allowed in destructors. I think "delete bf;" still counts as accessing a reference. The reason is, that the garbage collector calls the destructor, when an object becomes unreachable. The order the destructors are called is undefined. References to other objects may no longer be valid, because these objects were already destroyed.
Jan 30 2009
grauzone wrote:Charles Hixson wrote:Hmmm.... reasonable. Any idea how I should handle it? I want to ensure that the file is closed when the container is released. Maybe just get rid of the close method? But the garbage collector isn't guaranteed to run at any particular time...(OTOH, I am doing GC.collect...it would be nice to find a way to get rid of that, too. Maybe I could solve this by moving GC.collect inside the delete method, and not doing anything else there?) Didn't work. And when I added: writefln ("after writefln"); into the main program after "writefln (\"after second open\");" it had a segmentation error before reaching the "after writefln"I replaced BlockFile.close with: void close() { if (bf !is null) delete bf; // bf.close; bf = null; } But that didn't alter the segmentation fault. (Did you try it under D1 or D2?)Your destructor calls close(), and close() accesses the reference bf. But accessing references is not allowed in destructors. I think "delete bf;" still counts as accessing a reference. The reason is, that the garbage collector calls the destructor, when an object becomes unreachable. The order the destructors are called is undefined. References to other objects may no longer be valid, because these objects were already destroyed.
Jan 30 2009
The garbage collector isn't guaranteed to to free and destroy an unreachable object. That's because the GC is conservative. So if you want to be sure the object's resources are freed, you have to do it explicitly. I think you have two choices: 1. Remove close() from the destructor, and call close() manually when you're done. 2. Use scope or delete to ensure the destructor is always directly called, and never by the GC. Here's how you can use scope: { scope BlockFile f = new BlockFile(...); //... do something with f } //f goes out of scope, and the compiler inserts delete f;
Jan 31 2009
grauzone wrote:The garbage collector isn't guaranteed to to free and destroy an unreachable object. That's because the GC is conservative. So if you want to be sure the object's resources are freed, you have to do it explicitly. I think you have two choices: 1. Remove close() from the destructor, and call close() manually when you're done. 2. Use scope or delete to ensure the destructor is always directly called, and never by the GC. Here's how you can use scope: { scope BlockFile f = new BlockFile(...); //... do something with f } //f goes out of scope, and the compiler inserts delete f;If you're going to do that, you really should make the it a scope class to ensure you never accidentally let the GC try to delete it. I (and a few others) petitioned what feels like years ago for a simple argument to dtors to distinguish between deterministic destruction (delete/scope) and automatic destruction (GC). Never gained any ground, sadly. -- Daniel
Jan 31 2009
Daniel Keep wrote:grauzone wrote:I think it'd be even better to make them different functions. The finalizer could just be a virtual function called finalize(). Really, the differences between proper destructors and finalizers should be large enough to justify separate functions. Or even better, ditch finalizers and their wacky semantics (which make them quite useless anyway), and invent something like notify-able weakpointers. D already provides basic support for this (Object.notifyRegister()), but I think in Phobos 1.0 it's a bit buggy. There were some issues with race conditions and locking.The garbage collector isn't guaranteed to to free and destroy an unreachable object. That's because the GC is conservative. So if you want to be sure the object's resources are freed, you have to do it explicitly. I think you have two choices: 1. Remove close() from the destructor, and call close() manually when you're done. 2. Use scope or delete to ensure the destructor is always directly called, and never by the GC. Here's how you can use scope: { scope BlockFile f = new BlockFile(...); //... do something with f } //f goes out of scope, and the compiler inserts delete f;If you're going to do that, you really should make the it a scope class to ensure you never accidentally let the GC try to delete it. I (and a few others) petitioned what feels like years ago for a simple argument to dtors to distinguish between deterministic destruction (delete/scope) and automatic destruction (GC). Never gained any ground, sadly.
Jan 31 2009
grauzone wrote:Daniel Keep wrote:Personally, I'd be happy if I could get this to work: class Foo : Disposable { void dispose() { // do cleanup } ~this(bool deterministic) { if( deterministic ) { if( ! isDisposed ) dispose; } else if( ! isDisposed ) throw new DisposeException("You forgot to dispose, you thick burke!"); } } -- Daniel[snip] If you're going to do that, you really should make the it a scope class to ensure you never accidentally let the GC try to delete it. I (and a few others) petitioned what feels like years ago for a simple argument to dtors to distinguish between deterministic destruction (delete/scope) and automatic destruction (GC). Never gained any ground, sadly.I think it'd be even better to make them different functions. The finalizer could just be a virtual function called finalize(). Really, the differences between proper destructors and finalizers should be large enough to justify separate functions. Or even better, ditch finalizers and their wacky semantics (which make them quite useless anyway), and invent something like notify-able weakpointers. D already provides basic support for this (Object.notifyRegister()), but I think in Phobos 1.0 it's a bit buggy. There were some issues with race conditions and locking.
Jan 31 2009
Charles Hixson wrote:Main routine: void main() { try { BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); bf.close; bf = null; writefln ("after close"); BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); } catch (Exception e) { writefln ("Caught Exception ", e); } } Results in: Exiting BlockFile::this before close after close Exiting BlockFile::this after second open Segmentation fault I could post all the code. It's only 146 lines. But perhaps this is enough?So after the discussion I decided that it appeared to make BlockFile into a scope class. I did, removing all destructors and delete operations. The new main method was: void main() { { scope BlockFile bf; bf = new BlockFile ("test.bf", 4096); writefln ("before close"); } { writefln ("after close"); scope BlockFile cf = new BlockFile ("test.bf", 4096); writefln ("after second open"); writefln ("after writefln"); } } Yielding: Exiting BlockFile::this before close after close Exiting BlockFile::this after second open after writefln Apparently this can't be handled with garbage collection.
Jan 31 2009