• Austin Clements's avatar
    runtime: don't free stack spans during GC · d57056ba
    Austin Clements authored
    Memory for stacks is manually managed by the runtime and, currently
    (with one exception) we free stack spans immediately when the last
    stack on a span is freed. However, the garbage collector assumes that
    spans can never transition from non-free to free during scan or mark.
    This disagreement makes it possible for the garbage collector to mark
    uninitialized objects and is blocking us from re-enabling the bad
    pointer test in the garbage collector (issue #9880).
    
    For example, the following sequence will result in marking an
    uninitialized object:
    
    1. scanobject loads a pointer slot out of the object it's scanning.
       This happens to be one of the special pointers from the heap into a
       stack. Call the pointer p and suppose it points into X's stack.
    
    2. X, running on another thread, grows its stack and frees its old
       stack.
    
    3. The old stack happens to be large or was the last stack in its
       span, so X frees this span, setting it to state _MSpanFree.
    
    4. The span gets reused as a heap span.
    
    5. scanobject calls heapBitsForObject, which loads the span containing
       p, which is now in state _MSpanInUse, but doesn't necessarily have
       an object at p. The not-object at p gets marked, and at this point
       all sorts of things can go wrong.
    
    We already have a partial solution to this. When shrinking a stack, we
    put the old stack on a queue to be freed at the end of garbage
    collection. This was done to address exactly this problem, but wasn't
    a complete solution.
    
    This commit generalizes this solution to both shrinking and growing
    stacks. For stacks that fit in the stack pool, we simply don't free
    the span, even if its reference count reaches zero. It's fine to reuse
    the span for other stacks, and this enables that. At the end of GC, we
    sweep for cached stack spans with a zero reference count and free
    them. For larger stacks, we simply queue the stack span to be freed at
    the end of GC. Ideally, we would reuse these large stack spans the way
    we can small stack spans, but that's a more invasive change that will
    have to wait until after the freeze.
    
    Fixes #11267.
    
    Change-Id: Ib7f2c5da4845cc0268e8dc098b08465116972a71
    Reviewed-on: https://go-review.googlesource.com/11502Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
    d57056ba
mheap.go 31.1 KB