Program crash: GC destroys an object unexpectedly

Steven Schveighoffer schveiguy at gmail.com
Mon Sep 13 18:42:47 UTC 2021


On 9/13/21 1:54 PM, eugene wrote:
> On Monday, 13 September 2021 at 17:40:41 UTC, user1234 wrote:
>> The problems seems to lies in `newSignal()` which "would" not allocate 
>> using the GC.
> 
>      final Signal newSignal(int signum) {
>          Signal sg = new Signal(signum);
>          sg.owner = this;
>          sg.number = sg_number++;
>          sg.register();
>          return sg;
>      }
> 
> full src is here
> http://zed.karelia.ru/0/e/edsm-in-d-2021-09-10.tar.gz
> 

The GC only scans things that it knows about.

Inside your EventQueue you have this code:

```d
     void registerEventSource(EventSource es) {
         auto e = EpollEvent(0, es);
         int r = epoll_ctl(id, EPOLL_CTL_ADD, es.id, &e);
         assert(r == 0, "epoll_ctl(ADD) failed");
     }

     EventQueue opOpAssign(string op)(EventSource es)
     if (("+" == op) || ("~" == op)) {
         registerEventSource(es);
         return this;
     }

     void deregisterEventSource(EventSource es) {
         auto e = EpollEvent(0, es);
         int r = epoll_ctl(id, EPOLL_CTL_DEL, es.id, &e);
         assert(r == 0, "epoll_ctl(DEL) failed");
     }

     EventQueue opOpAssign(string op)(EventSource es)
     if ("-" == op) {
         deregisterEventSource(es);
         return this;
     }
```

And you are registering your signals using the `+=` operator.

What is happening here, is, `epoll_ctl` is adding your event source to a 
*C allocated* structure (namely the epoll struct, allocated by 
`epoll_create1`, and possibly even managed by the OS). The GC does not 
have access to this struct, so if that's the only reference to them, 
they will get cleaned up by the GC.

Now, with your stopper code that you showed, it looks like you are 
storing the reference to stopper right on the main stack frame. This 
*should* prevent those from being destroyed, since Stopper has a 
reference to both signals.

But I would recommend using `core.memory.GC.addRoot` on your EventSource 
when registering it with epoll, and using `core.memory.GC.removeRoot` 
when unregistering. That will ensure they do not get cleaned up before 
being unregistered. If this doesn't fix the problem, perhaps there is 
some other issue happening.

-Steve


More information about the Digitalmars-d-learn mailing list