A bug in my code

Sergey Gromov snake.scaly at gmail.com
Mon Sep 8 03:37:35 PDT 2008


bearophile <bearophileHUGS at lycos.com> wrote:
> So I have tried this, I have written this assuming that addRoot() adds
> a single pointer to the GC collected pool, but this last solution
> doesn't work, I don't know why:
> auto new_block = cast(Block*)mem_alloc(Block.sizeof);
> new_block.data = cast(int*)mem_alloc(nints * int.sizeof);
> new_block.len = nints;
> new_block.next = null;
> addRoot(new_block.next);
> addRoot(new_block.data);

What you do here is add two roots to GC: null and a pointer to your 
ints.  While the latter is relatively valid, the former is obviously 
wrong: you tell GC to never collect a memory block which includes an 
address of 0.  What happens next is a) whatever you assign to block.next 
is not kept alive by block since the .next field itself is not checked 
for pointers;  and b) if you ever change .data the old block will live 
forever while the new one will not be referenced for the same reason as 
a).

Here are the possible solutions.  Note that they are independent, you 
need to implement only one of them to make your code work.

1.  Replace Block.next with

    private Block* _next;
    Block* next() {return _next;}
    Block* next(Block* other) {
        removeRoot(_next);
        _next = other;
        addRoot(_next);
        return _next;
    }

2.  Replace

    addRoot(new_block.next);
    addRoot(new_block.data);

with

    addRange(&new_block.next, &new_block.data+1);

which will make GC scan Block.next and Block.data for pointers on every 
collection cycle, therefore automatically picking any changes to these 
pointers.

Both changes make your code work.  Both require Block.~this() to remove 
any unneeded roots or ranges, since they are permanent by their nature 
and will keep any pointed memory allocated until the process terminates.


More information about the Digitalmars-d-learn mailing list