What should happen here?

Steven Schveighoffer schveiguy at gmail.com
Mon Sep 20 18:49:12 UTC 2021


OK, so here is what Actually happens consistently (all this is with dmd):

1. Macos 64-bit: Option 2
2. Windows 64-bit: Option 1
3. Windows 32-bit: Option 2
4. Windows 32-bit with -g: Option 1
5. Linux 64-bit: Option 1
6. Linux 32-bit: Option 2

I'm sure other compilers would have varying degrees of options.

What is happening?

What happens is that the variable `c` is sometimes not stored on the 
stack, but in a register. after a call to `GC.collect`, that register is 
overwritten, and there is no longer any reference to the object, it gets 
collected.

In this simple example, we are doing nothing with c afterwards. But 
there is a real case of trouble happening to someone 
[here](https://forum.dlang.org/post/xchnfzvpmxgytqprbosz@forum.dlang.org). 
They are passing the class reference into a C function that registers 
the class in a place the GC can't see. The GC collects that information, 
and by the time that C library uses that (all *before* `main` exits), 
the data is invalid.

I feel like this might not necessarily be an issue, because technically, 
you aren't using `c` any more, so it can be deallocated immediately. But 
right in our documentation 
[here](https://dlang.org/spec/interfaceToC.html#storage_allocation) it 
lists ways to alleviate this:

```
If pointers to D garbage collector allocated memory are passed to C 
functions, it's critical to ensure that the memory will not be collected 
by the garbage collector before the C function is done with it. This is 
accomplished by:

* Making a copy of the data using core.stdc.stdlib.malloc() and passing 
the copy instead.
* Leaving a pointer to it on the stack (as a parameter or automatic 
variable), as the garbage collector will scan the stack.
* Leaving a pointer to it in the static data segment, as the garbage 
collector will scan the static data segment.
* Registering the pointer with the garbage collector with the 
std.gc.addRoot() or std.gc.addRange() calls.
```

This to me seems like "leaving a pointer to it on the stack". I'm not 
sure how else I would do that specifically? Plus, this option is the 
only "free" one -- the others all require much more complication. Adding 
a pointer to the stack is free. It's just, I don't know how to tell the 
compiler to do that besides declaring it.

Note that I don't think any other data types allocated on the heap do 
this. I tried to change C to a struct, and it is not collected. Change 
the line to `auto c = [new C]` and it works fine.

It's just class references that the compiler seems to not care about 
ensuring stack references stay alive.

Should it be this way?

-Steve


More information about the Digitalmars-d mailing list