• Austin Clements's avatar
    runtime: account for stack guard when shrinking the stack · 7387121d
    Austin Clements authored
    Currently, when shrinkstack computes whether the halved stack
    allocation will have enough room for the stack, it accounts for the
    stack space that's actively in use but fails to leave extra room for
    the stack guard space. As a result, *if* the minimum stack size is
    small enough or the guard large enough, it may shrink the stack and
    leave less than enough room to run nosplit functions. If the next
    function called after the stack shrink is a nosplit function, it may
    overflow the stack without noticing and overwrite non-stack memory.
    
    We don't think this is happening under normal conditions right now.
    The minimum stack allocation is 2K and the guard is 640 bytes. The
    "worst case" stack shrink is from 4K (4048 bytes after stack barrier
    array reservation) to 2K (2016 bytes after stack barrier array
    reservation), which means the largest "used" size that will qualify
    for shrinking is 4048/4 - 8 = 1004 bytes. After copying, that leaves
    2016 - 1004 = 1012 bytes of available stack, which is significantly
    more than the guard space.
    
    If we were to reduce the minimum stack size to 1K or raise the guard
    space above 1012 bytes, the logic in shrinkstack would no longer leave
    enough space.
    
    It's also possible to trigger this problem by setting
    firstStackBarrierOffset to 0, which puts stack barriers in a debug
    mode that steals away *half* of the stack for the stack barrier array
    reservation. Then, the largest "used" size that qualifies for
    shrinking is (4096/2)/4 - 8 = 504 bytes. After copying, that leaves
    (2096/2) - 504 = 8 bytes of available stack; much less than the
    required guard space. This causes failures like those in issue #11027
    because func gc() shrinks its own stack and then immediately calls
    casgstatus (a nosplit function), which overflows the stack and
    overwrites a free list pointer in the neighboring span. However, since
    this seems to require the special debug mode, we don't think it's
    responsible for issue #11027.
    
    To forestall all of these subtle issues, this commit modifies
    shrinkstack to correctly account for the guard space when considering
    whether to halve the stack allocation.
    
    Change-Id: I7312584addc63b5bfe55cc384a1012f6181f1b9d
    Reviewed-on: https://go-review.googlesource.com/10714Reviewed-by: 's avatarKeith Randall <khr@golang.org>
    Reviewed-by: 's avatarRuss Cox <rsc@golang.org>
    7387121d
Name
Last commit
Last update
api Loading commit data...
doc Loading commit data...
lib/time Loading commit data...
misc Loading commit data...
src Loading commit data...
test Loading commit data...
.gitattributes Loading commit data...
.gitignore Loading commit data...
AUTHORS Loading commit data...
CONTRIBUTING.md Loading commit data...
CONTRIBUTORS Loading commit data...
LICENSE Loading commit data...
PATENTS Loading commit data...
README.md Loading commit data...
favicon.ico Loading commit data...
robots.txt Loading commit data...