www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Segmentation error at the end problem

reply Charles Hixson <charleshixsn earthlink.net> writes:
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
next sibling parent reply Gide Nwawudu <gide btinternet.com> writes:
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
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Gide Nwawudu wrote:
 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
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 listing
Jan 28 2009
parent reply Gide Nwawudu <gide btinternet.com> writes:
On Wed, 28 Jan 2009 13:37:40 -0800, Charles Hixson
<charleshixsn earthlink.net> wrote:

Gide Nwawudu wrote:
 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
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 listing
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; } Gide
Jan 29 2009
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
Gide Nwawudu wrote:
 On Wed, 28 Jan 2009 13:37:40 -0800, Charles Hixson
 <charleshixsn earthlink.net> wrote:
 
 Gide Nwawudu wrote:
 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
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 listing
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; } Gide
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?)
Jan 29 2009
parent reply grauzone <none example.net> writes:
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
parent reply Charles Hixson <charleshixsn earthlink.net> writes:
grauzone wrote:
 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.
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"
Jan 30 2009
parent reply grauzone <none example.net> writes:
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
parent reply Daniel Keep <daniel.keep.lists gmail.com> writes:
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
parent reply grauzone <none example.net> writes:
Daniel Keep wrote:
 
 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.
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
parent Daniel Keep <daniel.keep.lists gmail.com> writes:
grauzone wrote:
 Daniel Keep wrote:
 [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.
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
Jan 31 2009
prev sibling parent Charles Hixson <charleshixsn earthlink.net> writes:
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