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