Skip to content

Commit

Permalink
cmd/compile: make jump table symbol local
Browse files Browse the repository at this point in the history
When using plugins, if the plugin and the main executable both
have the same function, and if it uses jump table, currently the
jump table symbol have the same name so it will be deduplicated by
the dynamic linker. This causes a function in the plugin may (in
the middle of the function) jump to the function with the same name
in the main executable (or vice versa). But the function may be
compiled slightly differently, because the plugin needs to be PIC.
Jumping from the middle of one function to the other will not work.
Avoid this problem by marking the jump table symbol local to a DSO.

Fixes #53989.

Change-Id: I2b573b9dfc22401c8a09ffe9b9ea8bb83d3700ca
Reviewed-on: https://go-review.googlesource.com/c/go/+/418960
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Cherry Mui <cherryyz@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
  • Loading branch information
cherrymui committed Jul 22, 2022
1 parent 774fa58 commit c5da4fb
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 0 deletions.
6 changes: 6 additions & 0 deletions misc/cgo/testplugin/plugin_test.go
Expand Up @@ -307,6 +307,12 @@ func TestIssue52937(t *testing.T) {
goCmd(t, "build", "-buildmode=plugin", "-o", "issue52937.so", "./issue52937/main.go")
}

func TestIssue53989(t *testing.T) {
goCmd(t, "build", "-buildmode=plugin", "-o", "issue53989.so", "./issue53989/plugin.go")
goCmd(t, "build", "-o", "issue53989.exe", "./issue53989/main.go")
run(t, "./issue53989.exe")
}

func TestForkExec(t *testing.T) {
// Issue 38824: importing the plugin package causes it hang in forkExec on darwin.

Expand Down
32 changes: 32 additions & 0 deletions misc/cgo/testplugin/testdata/issue53989/main.go
@@ -0,0 +1,32 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Issue 53989: the use of jump table caused a function
// from the plugin jumps in the middle of the function
// to the function with the same name in the main
// executable. As these two functions may be compiled
// differently as plugin needs to be PIC, this causes
// crash.

package main

import (
"plugin"

"testplugin/issue53989/p"
)

func main() {
p.Square(7) // call the function in main executable

p, err := plugin.Open("issue53989.so")
if err != nil {
panic(err)
}
f, err := p.Lookup("Square")
if err != nil {
panic(err)
}
f.(func(int))(7) // call the plugin one
}
52 changes: 52 additions & 0 deletions misc/cgo/testplugin/testdata/issue53989/p/p.go
@@ -0,0 +1,52 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package p

import (
"fmt"
"runtime"
)

var y int

//go:noinline
func Square(x int) {
var pc0, pc1 [1]uintptr
runtime.Callers(1, pc0[:]) // get PC at entry

// a switch using jump table
switch x {
case 1:
y = 1
case 2:
y = 4
case 3:
y = 9
case 4:
y = 16
case 5:
y = 25
case 6:
y = 36
case 7:
y = 49
case 8:
y = 64
default:
panic("too large")
}

// check PC is in the same function
runtime.Callers(1, pc1[:])
if pc1[0] < pc0[0] || pc1[0] > pc0[0]+1000000 {
fmt.Printf("jump across DSO boundary. pc0=%x, pc1=%x\n", pc0[0], pc1[0])
panic("FAIL")
}

if y != x*x {
fmt.Printf("x=%d y=%d!=%d\n", x, y, x*x)
panic("FAIL")
}
}
13 changes: 13 additions & 0 deletions misc/cgo/testplugin/testdata/issue53989/plugin.go
@@ -0,0 +1,13 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import "testplugin/issue53989/p"

func Square(x int) { // export Square for plugin
p.Square(x)
}

func main() {}
1 change: 1 addition & 0 deletions src/cmd/compile/internal/ssa/rewrite.go
Expand Up @@ -1959,5 +1959,6 @@ func logicFlags32(x int32) flagConstant {
func makeJumpTableSym(b *Block) *obj.LSym {
s := base.Ctxt.Lookup(fmt.Sprintf("%s.jump%d", b.Func.fe.LSym(), b.ID))
s.Set(obj.AttrDuplicateOK, true)
s.Set(obj.AttrLocal, true)
return s
}

0 comments on commit c5da4fb

Please sign in to comment.