Jump to page: 1 2 3
Thread overview
Bug in RefCounted?
Oct 24, 2013
Rene Zwanenburg
Oct 24, 2013
Jesse Phillips
Oct 27, 2013
Rene Zwanenburg
Oct 24, 2013
Ali Çehreli
Oct 27, 2013
Rene Zwanenburg
Oct 27, 2013
monarch_dodra
Oct 27, 2013
Ali Çehreli
Oct 28, 2013
Rene Zwanenburg
Oct 28, 2013
monarch_dodra
Oct 28, 2013
Maxim Fomin
Oct 28, 2013
Ali Çehreli
Oct 29, 2013
Maxim Fomin
Oct 29, 2013
Ali Çehreli
Oct 29, 2013
Maxim Fomin
Oct 29, 2013
Ali Çehreli
Oct 29, 2013
Rene Zwanenburg
Oct 29, 2013
Maxim Fomin
Oct 30, 2013
Kenji Hara
Oct 28, 2013
Maxim Fomin
Oct 29, 2013
Rene Zwanenburg
Oct 29, 2013
Maxim Fomin
October 24, 2013
I'm writing a D wrapper for a C library. I was planning to use RefCounted structs to control the lifetime of objects created by this library. Please check the following example:

http://dpaste.dzfl.pl/b49962bf

Foo would be an opaque struct. createFoo() and destroyFoo() would be implemented in the C library (I know I have to declare them extern(C), this is just an example).

As you can see, that code prints 'Destroying Foo' twice, with different pointers. I expected destroyFoo to be called only once, on the instance created by createFoo(), when the Bar instance goes out of scope. Current behaviour causes an invalid pointer to be passed to destroyFoo(). Is this a bug in RefCounted or am I doing something wrong?
October 24, 2013
On Thursday, 24 October 2013 at 14:58:21 UTC, Rene Zwanenburg wrote:
> I'm writing a D wrapper for a C library. I was planning to use RefCounted structs to control the lifetime of objects created by this library. Please check the following example:
>
> http://dpaste.dzfl.pl/b49962bf
>
> Foo would be an opaque struct. createFoo() and destroyFoo() would be implemented in the C library (I know I have to declare them extern(C), this is just an example).
>
> As you can see, that code prints 'Destroying Foo' twice, with different pointers. I expected destroyFoo to be called only once, on the instance created by createFoo(), when the Bar instance goes out of scope. Current behaviour causes an invalid pointer to be passed to destroyFoo(). Is this a bug in RefCounted or am I doing something wrong?

I answered a question related to RefCount on SO
http://stackoverflow.com/questions/4632355/making-a-reference-counted-object-in-d-using-refcountedt/4635050#4635050

Not written to your specific problem, but may give you the information you need.
October 24, 2013
On 10/24/2013 07:58 AM, Rene Zwanenburg wrote:
> I'm writing a D wrapper for a C library. I was planning to use
> RefCounted structs to control the lifetime of objects created by this
> library. Please check the following example:
>
> http://dpaste.dzfl.pl/b49962bf
>
> Foo would be an opaque struct. createFoo() and destroyFoo() would be
> implemented in the C library (I know I have to declare them extern(C),
> this is just an example).
>
> As you can see, that code prints 'Destroying Foo' twice, with different
> pointers. I expected destroyFoo to be called only once, on the instance
> created by createFoo(), when the Bar instance goes out of scope. Current
> behaviour causes an invalid pointer to be passed to destroyFoo(). Is
> this a bug in RefCounted or am I doing something wrong?

Technically, it is a problem with FooWrapper. Regardless of whether RefCounted's behavior, by default, structs in D are freely copyable and movable value types. The compiler can do those things as it sees fit.

Since FooWrapper owns a resource, it must also define the post-blit to make a copy of Foo.

(As an aside, dmd at git head does not make such a copy.)

Ali

October 27, 2013
On Thursday, 24 October 2013 at 16:40:42 UTC, Jesse Phillips wrote:
> I answered a question related to RefCount on SO
> http://stackoverflow.com/questions/4632355/making-a-reference-counted-object-in-d-using-refcountedt/4635050#4635050
>
> Not written to your specific problem, but may give you the information you need.

Thanks, that did help. Still, I think there's something strange going on.

The problem is that RefCounted calls the FooWrapper destructor twice, one time with a garbage foo pointer. The example prints:
Destroying Foo 40CED748
Destroying Foo 4002DFF0
There is only one Foo instance created. A null pointer would make sense, but where's that second pointer coming from?
October 27, 2013
On Thursday, 24 October 2013 at 16:46:37 UTC, Ali Çehreli wrote:
> Technically, it is a problem with FooWrapper. Regardless of whether RefCounted's behavior, by default, structs in D are freely copyable and movable value types. The compiler can do those things as it sees fit.
>
> Since FooWrapper owns a resource, it must also define the post-blit to make a copy of Foo.
>
> (As an aside, dmd at git head does not make such a copy.)
>
> Ali

Thanks, that's indeed an oversight on my part. Still, I think there's something strange going on.

The problem is that the FooWrapper destructor is called twice, one time with a garbage foo pointer. The example prints:
Destroying Foo 40CED748
Destroying Foo 4002DFF0
There is only one Foo instance created. A null pointer would make sense, but where's that second pointer coming from?
October 27, 2013
On Sunday, 27 October 2013 at 21:02:01 UTC, Rene Zwanenburg wrote:
> On Thursday, 24 October 2013 at 16:46:37 UTC, Ali Çehreli wrote:
>> Technically, it is a problem with FooWrapper. Regardless of whether RefCounted's behavior, by default, structs in D are freely copyable and movable value types. The compiler can do those things as it sees fit.
>>
>> Since FooWrapper owns a resource, it must also define the post-blit to make a copy of Foo.
>>
>> (As an aside, dmd at git head does not make such a copy.)
>>
>> Ali
>
> Thanks, that's indeed an oversight on my part. Still, I think there's something strange going on.
>
> The problem is that the FooWrapper destructor is called twice, one time with a garbage foo pointer. The example prints:
> Destroying Foo 40CED748
> Destroying Foo 4002DFF0
> There is only one Foo instance created. A null pointer would make sense, but where's that second pointer coming from?

This is indeed strange. I don't have access to my development
platform, but it *could* be an (older) emplace bug. Do you
reproduce with head? I'll investigate further as soon as I can.
This is not normal behavior.

Also, keep in mind that DMD *is* allowed to destroy the same
object several times. YOur destructor should look like this:
~this()
{
     if (foo)
         destroyFoo(foo);
     foo = null;
}

This doesn't explain what you are seeing, but keep it in mind.
October 27, 2013
On 10/27/2013 03:04 PM, monarch_dodra wrote:

> it *could* be an (older) emplace bug. Do you reproduce with head?

I had tested it with head. No, doesn't happen on head.

> Also, keep in mind that DMD *is* allowed to destroy the same
> object several times.

That's news to me. I know that objects may never be destroyed but why multiple times? How many lives do they have? ;)

> YOur destructor should look like this:

> ~this()
> {
>       if (foo)
>           destroyFoo(foo);
>       foo = null;
> }

Welcome back to C. :p

Ali

October 28, 2013
On Sunday, 27 October 2013 at 23:33:55 UTC, Ali Çehreli wrote:
> On 10/27/2013 03:04 PM, monarch_dodra wrote:
>
> > it *could* be an (older) emplace bug. Do you reproduce with
> head?
>
> I had tested it with head. No, doesn't happen on head.

Thanks for testing that. I'm not set up to build dmd or phobos myself.

> > Also, keep in mind that DMD *is* allowed to destroy the same
> > object several times.
>
> That's news to me. I know that objects may never be destroyed but why multiple times? How many lives do they have? ;)

Yeah, I'd like to know this as well. I do remember structs allocated on the heap don't have their destructors called at all due to the GC not being precise, I think.

But one object allowed to be destructed multiple times? That sounds really bad.. If that's true a lot of my code is probably incorrect.
October 28, 2013
On Monday, 28 October 2013 at 10:07:15 UTC, Rene Zwanenburg wrote:
> Yeah, I'd like to know this as well. I do remember structs allocated on the heap don't have their destructors called at all due to the GC not being precise, I think.
>
> But one object allowed to be destructed multiple times? That sounds really bad.. If that's true a lot of my code is probably incorrect.

Hum... I seem to remember having replied earlier, but I guess I
forgot to hit send.

In any case, I could be mistaken, but I simply know that under
certain circumstances, it can happen. I don't know if that's a
bug though. I'll try to find the cases where it happens.

Furthermore, you must *always* make sure that the T.init state is
destroyable (which is not the case here).
October 28, 2013
On Monday, 28 October 2013 at 16:53:11 UTC, monarch_dodra wrote:
> On Monday, 28 October 2013 at 10:07:15 UTC, Rene Zwanenburg wrote:
>> Yeah, I'd like to know this as well. I do remember structs allocated on the heap don't have their destructors called at all due to the GC not being precise, I think.
>>
>> But one object allowed to be destructed multiple times? That sounds really bad.. If that's true a lot of my code is probably incorrect.
>
> Hum... I seem to remember having replied earlier, but I guess I
> forgot to hit send.
>
> In any case, I could be mistaken, but I simply know that under
> certain circumstances, it can happen.

OK

> I don't know if that's a
> bug though. I'll try to find the cases where it happens.
>

So do you *know* cases or suspect that they may exists? Or remember some bug issue?

Here is my attempt:

import std.stdio;

struct S
{
   int i;
   this(int i)   { writefln("ctor, %X", i); this.i = i; }
   this(this)  { writefln("postblit, %X, %X", &this, i); }
   ~this()     { writefln("dtor, %X, %X", &this, i); }
}

auto foo()
{
   S s = S(1);
   return { s = S(2); } ;
}

void main()
{
   foo()();
}

ctor, 1
dtor, 7FFFF7ED8FF8, 1
ctor, 2
dtor, 7FFFFFFFDB30, 1

Inside foo() function object 's' is destroyed twice: first time as a regular struct at the end of block scope, second time before assigning S(2).

There are other tools: union bug, control flow tricks, __traits, __dtor but they are move obvious.

« First   ‹ Prev
1 2 3