View mode: basic / threaded / horizontal-split · Log in · Help
June 09, 2004
Destruction Derby
Destruction - Definitive test results.

Faced with uncertainty, I did what any scientist would do. I did an experiment.
Here's the source code:

//======== BEGIN =========
>   import std.c.stdio;
>   import std.c.stdlib;
>   import std.gc;
>   
>   FILE * f;
>   
>   class A
>   {
>       new(uint n)
>       {
>           f = fopen("C:\\gctest.txt","wt");
>           fprintf(f,"Allocator called\n");
>           return malloc(n);
>       }
>       
>       this()
>       {
>           fprintf(f,"Constructor called\n");
>       }
>       
>       ~this()
>       {
>           fprintf(f,"Destructor called\n");
>       }
>       
>       delete(void* p)
>       {
>           fprintf(f,"Deallocator called\n");
>           fclose(f);
>           free(p);
>       }
>       
>       int t;
>   }
>   
>   int main()
>   {
>       A a = new A();
>       a = null;
>       fullCollect();
>       return 0;
>   }
//========= END ==========

And here's the contents of the file after the program is run:

//======= BEGIN ========
Allocator called
Constructor called
//======== END =========

Conclusions:
(1) The destructor was not called.
(2) The class deallocator was not called.

Observe that the garbage collector WAS EXPLICITLY INVOKED, and that the variable
'a' was not reachable at the time the gc was run. This "destruction" is not
merely lazy, it seems to be actually on vacation.

Now, there are two possibilities. Either
(a) This is correct behavior
(b) This is a bug in the compiler

If it's (a) I will need to think very hard to try to find a workaround. If I
can't find one I will have to abandon my D project and write the thing in C++.
If it's (b) then it's critical to me that the bug be fixed asap, because, again,
this has to work, or D becomes useless for my purposes.
June 09, 2004
Re: Destruction Derby
Arcane Jill wrote:

>If it's (a) I will need to think very hard to try to find a workaround. If I
>can't find one I will have to abandon my D project and write the thing in C++.
>If it's (b) then it's critical to me that the bug be fixed asap, because, again,
>this has to work, or D becomes useless for my purposes.
>  
>

Are you saying that the only reason you are using D is because of the 
gc?  If you use C++ you won't get automatic deconstruction either, you 
have to call delete (in D and C++) to get that.


-- 
-Anderson: http://badmama.com.au/~anderson/
June 09, 2004
Re: Destruction Derby
In article <ca6us1$27g7$1@digitaldaemon.com>, J Anderson says...
>
>If you use C++ you won't get automatic deconstruction either, you 
>have to call delete (in D and C++) to get that.

Not true.

>    void f()  // C++
>    {
>        SecurePassword p;   // constructed on the stack
>
>        /* do stuff with p which auto makes illegal in D */
>
>    }
>    // Destructor of p WILL be called, even in the event of an exception

Jill
June 09, 2004
Re: Destruction Derby
In article <ca6us1$27g7$1@digitaldaemon.com>, J Anderson says...

>Are you saying that the only reason you are using D is because of the 
>gc?

No. I'm using D because D is brilliant. I beleive I've said that a few times
already. Please don't read into my words that which I have not said.

Destructors which refuse to execute are merely a recently discovered problem
which I'm currently trying either to solve or work around.

Jill
June 09, 2004
Re: Destruction Derby
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message
news:ca6rl9$22p9$1@digitaldaemon.com...
> Destruction - Definitive test results.
>
> Faced with uncertainty, I did what any scientist would do. I did an
experiment.
> Here's the source code:
>
> //======== BEGIN =========
> >   import std.c.stdio;
> >   import std.c.stdlib;
> >   import std.gc;
> >
> >   FILE * f;
> >
> >   class A
> >   {
> >       new(uint n)
> >       {
> >           f = fopen("C:\\gctest.txt","wt");
> >           fprintf(f,"Allocator called\n");
> >           return malloc(n);
> >       }
> >
> >       this()
> >       {
> >           fprintf(f,"Constructor called\n");
> >       }
> >
> >       ~this()
> >       {
> >           fprintf(f,"Destructor called\n");
> >       }
> >
> >       delete(void* p)
> >       {
> >           fprintf(f,"Deallocator called\n");
> >           fclose(f);
> >           free(p);
> >       }
> >
> >       int t;
> >   }
> >
> >   int main()
> >   {
> >       A a = new A();
> >       a = null;
> >       fullCollect();
> >       return 0;
> >   }
> //========= END ==========
>
> And here's the contents of the file after the program is run:
>
> //======= BEGIN ========
> Allocator called
> Constructor called
> //======== END =========
>
> Conclusions:
> (1) The destructor was not called.
> (2) The class deallocator was not called.
>
> Observe that the garbage collector WAS EXPLICITLY INVOKED, and that the
variable
> 'a' was not reachable at the time the gc was run. This "destruction" is
not
> merely lazy, it seems to be actually on vacation.

Maybe i am missing something but is it out of the question to use
delete a; ?

> Now, there are two possibilities. Either
> (a) This is correct behavior
> (b) This is a bug in the compiler
>
> If it's (a) I will need to think very hard to try to find a workaround. If
I
> can't find one I will have to abandon my D project and write the thing in
C++.
> If it's (b) then it's critical to me that the bug be fixed asap, because,
again,
> this has to work, or D becomes useless for my purposes.
>
>
>
June 09, 2004
Re: Destruction Derby
what if you explicitly call delete a; before setting it to null?
In article <ca6rl9$22p9$1@digitaldaemon.com>, Arcane Jill says...
>
>Destruction - Definitive test results.
>
>Faced with uncertainty, I did what any scientist would do. I did an experiment.
>Here's the source code:
>
>//======== BEGIN =========
>>   import std.c.stdio;
>>   import std.c.stdlib;
>>   import std.gc;
>>   
>>   FILE * f;
>>   
>>   class A
>>   {
>>       new(uint n)
>>       {
>>           f = fopen("C:\\gctest.txt","wt");
>>           fprintf(f,"Allocator called\n");
>>           return malloc(n);
>>       }
>>       
>>       this()
>>       {
>>           fprintf(f,"Constructor called\n");
>>       }
>>       
>>       ~this()
>>       {
>>           fprintf(f,"Destructor called\n");
>>       }
>>       
>>       delete(void* p)
>>       {
>>           fprintf(f,"Deallocator called\n");
>>           fclose(f);
>>           free(p);
>>       }
>>       
>>       int t;
>>   }
>>   
>>   int main()
>>   {
>>       A a = new A();
>>       a = null;
>>       fullCollect();
>>       return 0;
>>   }
>//========= END ==========
>
>And here's the contents of the file after the program is run:
>
>//======= BEGIN ========
>Allocator called
>Constructor called
>//======== END =========
>
>Conclusions:
>(1) The destructor was not called.
>(2) The class deallocator was not called.
>
>Observe that the garbage collector WAS EXPLICITLY INVOKED, and that the variable
>'a' was not reachable at the time the gc was run. This "destruction" is not
>merely lazy, it seems to be actually on vacation.
>
>Now, there are two possibilities. Either
>(a) This is correct behavior
>(b) This is a bug in the compiler
>
>If it's (a) I will need to think very hard to try to find a workaround. If I
>can't find one I will have to abandon my D project and write the thing in C++.
>If it's (b) then it's critical to me that the bug be fixed asap, because, again,
>this has to work, or D becomes useless for my purposes.
>
>
>
June 09, 2004
Re: Destruction Derby
Try this:

>  int main()
>  {
>      {
>          auto A a = new A();
>          // use a here
>      }
>      // a's destructor should be called by this point
>      fullCollect();
>      return 0;
>  }

I haven't tested this firsthand, but it should have the effect of 
finalizing a when its enclosing scope terminates. (even if an exception 
is thrown)

 -- andy
June 09, 2004
Re: Destruction Derby
Ivan Senji schrieb:

> Maybe i am missing something but is it out of the question to use
> delete a; ?

It is a question of *guarantees*. If a language with automatic memory 
management doesn't guarantee that destructors get called, it has to 
become a problem if more or less critical resources want to be managed 
in an advanced manner. And as shown, auto doesn't always help either.

-eye
June 09, 2004
Re: Destruction Derby
In article <ca78n4$2mq2$1@digitaldaemon.com>, hellcatv@hotmail.com says...
>
>what if you explicitly call delete a; before setting it to null?

You are not the only person who has suggested this, however please, please
understand that in the field in which I am working, this is simply not an
option. Yes OF COURSE it is possible to explicitly call delete() - it's not like
I hadn't thought of that. It's also possible to call a specially written
function called wipeThisSensitiveDataNow().

But that would be missing the point.

A class which manages sensitive data *MUST* be capable of managing that resource
completely, of preventing access to it except through authorized methods, and of
securely erasing that sensitive data, REGARDLESS of what calls a user of that
class does or does not make.

I could write pages and pages on this, on why it is important. But ... I'd
rather that you trusted me that I know what I'm doing. This is my area of
expertise. (Well, that and three decades of experience writing system software).
Computer security is fraught with dangers. There are holes everywhere you look.
One - single - omission ... could render sensitive data such as passwords,
encryption keys, etc., open to an attacker. (Well, to an attacker who knows as
much as I, anyway). And it could be YOUR data that is being protected by SOMEONE
ELSE'S application built using MY toolkit. And THEY might not have called
delete() (or even read the manual).

It's not that there's anything wrong with calling delete(). It's that I cannot
rely on callers of my API doing that. And I have to guard against the
possibility that they may not.

Fortunately, I am going to succeed, come what may. Even if I have to construct
things on the stack (so that they can be routinely erased just by declaring a
large array from time to time), I will find a way.

But all of this is irrelevant, and a side-issue. I can demonstrate, in a simple,
repeatable experiment, that a destructor is not always called. So either this is
correct behavior (in which case, fine, I'll figure out a way round it), or it's
a bug (in which case, it is critical to anyone doing resource management that it
be fixed). That's all.

I do recognise that you were trying to help though, and I do appreciate that.
Arcane Jill
June 09, 2004
Re: Destruction Derby
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message
news:ca7hnm$3ed$1@digitaldaemon.com...
> In article <ca78n4$2mq2$1@digitaldaemon.com>, hellcatv@hotmail.com says...
> >
> >what if you explicitly call delete a; before setting it to null?
>
> You are not the only person who has suggested this, however please, please
> understand that in the field in which I am working, this is simply not an
> option. Yes OF COURSE it is possible to explicitly call delete() - it's
not like
> I hadn't thought of that. It's also possible to call a specially written
> function called wipeThisSensitiveDataNow().
>
> But that would be missing the point.
>
> A class which manages sensitive data *MUST* be capable of managing that
resource
> completely, of preventing access to it except through authorized methods,
and of
> securely erasing that sensitive data, REGARDLESS of what calls a user of
that
> class does or does not make.
>
> I could write pages and pages on this, on why it is important. But ... I'd
> rather that you trusted me that I know what I'm doing. This is my area of
> expertise. (Well, that and three decades of experience writing system
software).
> Computer security is fraught with dangers. There are holes everywhere you
look.
> One - single - omission ... could render sensitive data such as passwords,
> encryption keys, etc., open to an attacker. (Well, to an attacker who
knows as
> much as I, anyway). And it could be YOUR data that is being protected by
SOMEONE
> ELSE'S application built using MY toolkit. And THEY might not have called
> delete() (or even read the manual).
>
> It's not that there's anything wrong with calling delete(). It's that I
cannot
> rely on callers of my API doing that. And I have to guard against the
> possibility that they may not.
>
> Fortunately, I am going to succeed, come what may. Even if I have to
construct
> things on the stack (so that they can be routinely erased just by
declaring a
> large array from time to time), I will find a way.
>
> But all of this is irrelevant, and a side-issue. I can demonstrate, in a
simple,
> repeatable experiment, that a destructor is not always called. So either
this is
> correct behavior (in which case, fine, I'll figure out a way round it), or
it's
> a bug (in which case, it is critical to anyone doing resource management
that it
> be fixed). That's all.
>
> I do recognise that you were trying to help though, and I do appreciate
that.
> Arcane Jill

Thanks for a good explanation :) I mada a mistake of thinking only about
your
code were you can make sure that you call delete, but i wasn't thinking
about
the user code, and now i see the problem.
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home