Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/compile: DUFFZERO in autogenerated methods corrupts LR #12108

Closed
davecheney opened this issue Aug 11, 2015 · 8 comments
Closed

cmd/compile: DUFFZERO in autogenerated methods corrupts LR #12108

davecheney opened this issue Aug 11, 2015 · 8 comments
Milestone

Comments

@davecheney
Copy link
Contributor

The following program faults on ppc64le

http://play.golang.org/p/hRlQs7hss2

package main

type APIEndpoint struct {
        Addresses []string
        Hostnames []string
        CACert string
        EnvironUUID string
        ServerUUID string
}

type Base struct {
        name string
}

func (b *Base) ConnectionEndpoint() (APIEndpoint, error) {
        return APIEndpoint{}, nil
}

type Super struct {
        Base
}

type T interface {
    ConnectionEndpoint() (APIEndpoint, error)
}

func main() {
    var q T = new(Super)
    q.ConnectionEndpoint()
}
% go run x.go 
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x11208]

goroutine 1 [running]:
main.(*Super).ConnectionEndpoint(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
        <autogenerated>:1 +0x48
main.main()
        /home/ubuntu/src/x/x.go:29 +0x9c
exit status 2

The program does not fault on any other architecture.

/cc @rsc @aclements @minux

@davecheney
Copy link
Contributor Author

Reducing the size of APIEndpoint by arbitrarily commenting out fields makes the test pass once the struct is 8 words of less.

@davecheney
Copy link
Contributor Author

Here is a shorter example

package main

const N = 9 // values > 8 cause ppc64 to fault

type Base struct {
    name string
}

func (b *Base) ConnectionEndpoint() (x [N]uintptr, e error) {
    return
}

type Super struct {
    Base
}

type T interface {
    ConnectionEndpoint() ([N]uintptr, error)
}

func f(q T) {
    q.ConnectionEndpoint()
}

func main() {
    var s Super
    f(&s)
}

http://play.golang.org/p/PWbXrURQOD

@davecheney
Copy link
Contributor Author

It's duffzero

Program received signal SIGSEGV, Segmentation fault.
0x000000000001121c in main.(*Super).ConnectionEndpoint (this=0x0, x=...) at <autogenerated>:2
2       <autogenerated>: No such file or directory.
(gdb) disassemble 
Dump of assembler code for function main.(*Super).ConnectionEndpoint:
   0x00000000000111d0 <+0>:     ld      r3,16(r30)
   0x00000000000111d4 <+4>:     cmpld   r3,r1
   0x00000000000111d8 <+8>:     blt     0x111e8 <main.(*Super).ConnectionEndpoint+24>
   0x00000000000111dc <+12>:    mflr    r5
   0x00000000000111e0 <+16>:    bl      0x64450 <runtime.morestack_noctxt>
   0x00000000000111e4 <+20>:    b       0x111d0 <main.(*Super).ConnectionEndpoint>
   0x00000000000111e8 <+24>:    mflr    r31
   0x00000000000111ec <+28>:    stdu    r31,-8(r1)
   0x00000000000111f0 <+32>:    addi    r3,r1,24
   0x00000000000111f4 <+36>:    addi    r3,r3,-8
   0x00000000000111f8 <+40>:    bl      0x6705c <runtime.duffzero+476>
   0x00000000000111fc <+44>:    addi    r3,r1,24
   0x0000000000011200 <+48>:    addi    r3,r3,-8
   0x0000000000011204 <+52>:    bl      0x6705c <runtime.duffzero+476>
   0x0000000000011208 <+56>:    ld      r2,16(r1)
   0x000000000001120c <+60>:    std     r2,16(r1)
   0x0000000000011210 <+64>:    ld      r2,16(r1)
   0x0000000000011214 <+68>:    cmpd    r2,r0
   0x0000000000011218 <+72>:    bne     0x11220 <main.(*Super).ConnectionEndpoint+80>
=> 0x000000000001121c <+76>:    std     r0,0(0)
   0x0000000000011220 <+80>:    b       0x11000 <main.(*Base).ConnectionEndpoint>
   0x0000000000011224 <+84>:    .long 0x0
End of assembler dump.
(gdb) bt
#0  0x000000000001121c in main.(*Super).ConnectionEndpoint (this=0x0, x=...) at <autogenerated>:2
#1  0x0000000000011128 in main.main () at /home/ubuntu/src/x/x.go:27

For some reason, when duffzero is required, it's being invoked twice.

@davecheney
Copy link
Contributor Author

Sorry. I think I was wrong about DUFFZERO. After looking at arm64 and amd64 output, this appears to be consistent, all archs' have this double duffzero pattern. However when duffzero is not present, no corruption appears.

@mwhudson
Copy link
Contributor

I see a problem in that: the tail call to the underlying method assumes that lr still points to the caller of the wrapper method, but the bl to duffzero stomps on that.

@ianlancetaylor ianlancetaylor added this to the Go1.6 milestone Aug 11, 2015
@davecheney davecheney changed the title cmd/compile: cmd/compile: DUFFZERO in autogenerated method corrupts LR Aug 11, 2015
@davecheney davecheney changed the title cmd/compile: DUFFZERO in autogenerated method corrupts LR cmd/compile: DUFFZERO in autogenerated methods corrupts LR Aug 11, 2015
@gopherbot
Copy link

CL https://golang.org/cl/13570 mentions this issue.

davecheney added a commit that referenced this issue Aug 12, 2015
Update #12108

If DUFFZERO is used within a tail call method it will overwrite the
link register.

Change-Id: I6abd2fde0f0ad909ccd55eb119b992673a74f0e2
Reviewed-on: https://go-review.googlesource.com/13570
Reviewed-by: Russ Cox <rsc@golang.org>
mwhudson pushed a commit to mwhudson/go that referenced this issue Sep 2, 2015
Update golang#12108

If DUFFZERO is used within a tail call method it will overwrite the
link register.

Change-Id: I6abd2fde0f0ad909ccd55eb119b992673a74f0e2
@gopherbot
Copy link

CL https://golang.org/cl/14937 mentions this issue.

@golang golang locked and limited conversation to collaborators Oct 9, 2016
@gopherbot
Copy link

CL https://golang.org/cl/32181 mentions this issue.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants