mirror of
https://github.com/golang/go
synced 2024-09-29 20:24:34 -06:00
55b58018f4
The issue11656 code was using the trap instruction as a PC value, but it is intended to call a PC value that contains the trap instruction. It doesn't matter too much as in practice the address is not executable anyhow. But may as well have the code act the way it is documented to act. Also, don't run the test with gccgo/GoLLVM, as it can't work. The illegal instruction will have no unwind data, so the unwinder won't be able to get past it. In other words, gccgo/GoLLVM suffer from the exact problem that the issue describes, but it seems insoluble. For golang/go#11656 Change-Id: Ib2e50ffc91d215fd50e78f742fafe476c92d704e Reviewed-on: https://go-review.googlesource.com/c/go/+/278473 Trust: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
87 lines
2.1 KiB
Go
87 lines
2.1 KiB
Go
// run
|
|
|
|
// Copyright 2015 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.
|
|
|
|
// windows doesn't work, because Windows exception handling
|
|
// delivers signals based on the current PC, and that current PC
|
|
// doesn't go into the Go runtime.
|
|
// +build !windows
|
|
|
|
// wasm does not work, because the linear memory is not executable.
|
|
// +build !wasm
|
|
|
|
// This test doesn't work on gccgo/GoLLVM, because they will not find
|
|
// any unwind information for the artificial function, and will not be
|
|
// able to unwind past that point.
|
|
// +build !gccgo
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"runtime"
|
|
"runtime/debug"
|
|
"unsafe"
|
|
)
|
|
|
|
func main() {
|
|
debug.SetPanicOnFault(true)
|
|
defer func() {
|
|
if err := recover(); err == nil {
|
|
panic("not panicking")
|
|
}
|
|
pc, _, _, _ := runtime.Caller(10)
|
|
f := runtime.FuncForPC(pc)
|
|
if f == nil || f.Name() != "main.f" {
|
|
if f == nil {
|
|
println("no func for ", unsafe.Pointer(pc))
|
|
} else {
|
|
println("found func:", f.Name())
|
|
}
|
|
panic("cannot find main.f on stack")
|
|
}
|
|
}()
|
|
f(20)
|
|
}
|
|
|
|
func f(n int) {
|
|
if n > 0 {
|
|
f(n - 1)
|
|
}
|
|
var f struct {
|
|
x uintptr
|
|
}
|
|
|
|
// We want to force an illegal instruction, to get a crash
|
|
// at a PC value != 0.
|
|
// Not all systems make the data section non-executable.
|
|
ill := make([]byte, 64)
|
|
switch runtime.GOARCH {
|
|
case "386", "amd64":
|
|
binary.LittleEndian.PutUint16(ill, 0x0b0f) // ud2
|
|
case "arm":
|
|
binary.LittleEndian.PutUint32(ill, 0xe7f000f0) // no name, but permanently undefined
|
|
case "arm64":
|
|
binary.LittleEndian.PutUint32(ill, 0xd4207d00) // brk #1000
|
|
case "ppc64":
|
|
binary.BigEndian.PutUint32(ill, 0x7fe00008) // trap
|
|
case "ppc64le":
|
|
binary.LittleEndian.PutUint32(ill, 0x7fe00008) // trap
|
|
case "mips", "mips64":
|
|
binary.BigEndian.PutUint32(ill, 0x00000034) // trap
|
|
case "mipsle", "mips64le":
|
|
binary.LittleEndian.PutUint32(ill, 0x00000034) // trap
|
|
case "s390x":
|
|
binary.BigEndian.PutUint32(ill, 0) // undefined instruction
|
|
default:
|
|
// Just leave it as 0 and hope for the best.
|
|
}
|
|
|
|
f.x = uintptr(unsafe.Pointer(&ill[0]))
|
|
p := &f
|
|
fn := *(*func())(unsafe.Pointer(&p))
|
|
fn()
|
|
}
|