]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: include the alignment of zero-sized types in stack offsets
authorMichael Anthony Knyszek <mknyszek@google.com>
Thu, 18 Feb 2021 17:33:01 +0000 (17:33 +0000)
committerMichael Knyszek <mknyszek@google.com>
Fri, 5 Mar 2021 15:34:32 +0000 (15:34 +0000)
This change modifies the reflect ABI assignment algorithm to catch
zero-sized types at the top level of each argument and faux-stack-assign
them. It doesn't actually generate an ABI step, which is unnecessary,
but it ensures that the offsets of further stack-assigned arguments are
aligned to the alignment of that zero-sized argument.

This change is necessary to have the register ABI assignment algorithm
gracefully degrade to ABI0 when no registers are present in the ABI.

Fixes #44377.

Change-Id: Ia95571688a61259302bb3c6d5fb33fbb6b5e8db8
Reviewed-on: https://go-review.googlesource.com/c/go/+/293789
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Trust: Than McIntosh <thanm@google.com>

src/reflect/abi.go

index 618efd0980b726fc4f7d3487c9f237a57b4b11a1..50e63121728a2bffd7706782a4b14bdaf8592a3b 100644 (file)
@@ -123,6 +123,24 @@ func (a *abiSeq) stepsForValue(i int) []abiStep {
 func (a *abiSeq) addArg(t *rtype) *abiStep {
        pStart := len(a.steps)
        a.valueStart = append(a.valueStart, pStart)
+       if t.size == 0 {
+               // If the size of the argument type is zero, then
+               // in order to degrade gracefully into ABI0, we need
+               // to stack-assign this type. The reason is that
+               // although zero-sized types take up no space on the
+               // stack, they do cause the next argument to be aligned.
+               // So just do that here, but don't bother actually
+               // generating a new ABI step for it (there's nothing to
+               // actually copy).
+               //
+               // We cannot handle this in the recursive case of
+               // regAssign because zero-sized *fields* of a
+               // non-zero-sized struct do not cause it to be
+               // stack-assigned. So we need a special case here
+               // at the top.
+               a.stackBytes = align(a.stackBytes, uintptr(t.align))
+               return nil
+       }
        if !a.regAssign(t, 0) {
                a.steps = a.steps[:pStart]
                a.stackAssign(t.size, uintptr(t.align))