Jump to page: 1 2
Thread overview
Segmentation error at the end problem
Jan 28, 2009
Charles Hixson
Jan 28, 2009
Gide Nwawudu
Re: Segmentation error at the end problem (148 line program listing)
Jan 28, 2009
Charles Hixson
Jan 29, 2009
Gide Nwawudu
Jan 29, 2009
Charles Hixson
Jan 30, 2009
grauzone
Jan 30, 2009
Charles Hixson
Jan 31, 2009
grauzone
Jan 31, 2009
Daniel Keep
Jan 31, 2009
grauzone
Jan 31, 2009
Daniel Keep
Solution Re: Segmentation error at the end problem
Feb 01, 2009
Charles Hixson
January 28, 2009
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?
January 28, 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
January 28, 2009
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


January 29, 2009
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
January 29, 2009
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?)
January 30, 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.
January 30, 2009
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"
January 31, 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;
January 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
January 31, 2009
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.
« First   ‹ Prev
1 2