1
0
mirror of https://github.com/golang/go synced 2024-11-26 02:17:58 -07:00

cmd/compile: fix funcdata encode for functions with large frame size

The funcdata is encoded as varint, with the upper limit set to 1e9.
However, the stack offsets could be up to 1<<30. Thus emitOpenDeferInfo
will trigger an ICE for function with large frame size.

By using binary.PutUvarint, the frame offset could be encoded correctly
for value larger than 1<<35, allow the compiler to report the error.

Further, the runtime also do validation when reading in the funcdata
value, so a bad offset won't likely cause mis-behavior.

Fixes #52697

Change-Id: I084c243c5d24c5d31cc22d5b439f0889e42b107c
Reviewed-on: https://go-review.googlesource.com/c/go/+/535077
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Cuong Manh Le 2023-10-13 10:32:57 +07:00 committed by Gopher Robot
parent 80834af206
commit da7ac77380
4 changed files with 34 additions and 17 deletions

View File

@ -7,6 +7,7 @@ package ssagen
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"go/constant"
"html"
@ -258,26 +259,15 @@ func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig {
// dvarint writes a varint v to the funcdata in symbol x and returns the new offset.
func dvarint(x *obj.LSym, off int, v int64) int {
if v < 0 || v > 1e9 {
if v < 0 {
panic(fmt.Sprintf("dvarint: bad offset for funcdata - %v", v))
}
if v < 1<<7 {
return objw.Uint8(x, off, uint8(v))
var buf [binary.MaxVarintLen64]byte
n := binary.PutUvarint(buf[:], uint64(v))
for _, b := range buf[:n] {
off = objw.Uint8(x, off, b)
}
off = objw.Uint8(x, off, uint8((v&127)|128))
if v < 1<<14 {
return objw.Uint8(x, off, uint8(v>>7))
}
off = objw.Uint8(x, off, uint8(((v>>7)&127)|128))
if v < 1<<21 {
return objw.Uint8(x, off, uint8(v>>14))
}
off = objw.Uint8(x, off, uint8(((v>>14)&127)|128))
if v < 1<<28 {
return objw.Uint8(x, off, uint8(v>>21))
}
off = objw.Uint8(x, off, uint8(((v>>21)&127)|128))
return objw.Uint8(x, off, uint8(v>>28))
return off
}
// emitOpenDeferInfo emits FUNCDATA information about the defers in a function

View File

@ -328,6 +328,7 @@ func TestStdFixed(t *testing.T) {
"issue49767.go", // go/types does not have constraints on channel element size
"issue49814.go", // go/types does not have constraints on array size
"issue56103.go", // anonymous interface cycles; will be a type checker error in 1.22
"issue52697.go", // types2 does not have constraints on stack size
// These tests requires runtime/cgo.Incomplete, which is only available on some platforms.
// However, types2 does not know about build constraints.

View File

@ -330,6 +330,7 @@ func TestStdFixed(t *testing.T) {
"issue49767.go", // go/types does not have constraints on channel element size
"issue49814.go", // go/types does not have constraints on array size
"issue56103.go", // anonymous interface cycles; will be a type checker error in 1.22
"issue52697.go", // go/types does not have constraints on stack size
// These tests requires runtime/cgo.Incomplete, which is only available on some platforms.
// However, go/types does not know about build constraints.

View File

@ -0,0 +1,25 @@
// errorcheck
// Copyright 2023 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.
//go:build !386 && !amd64p32 && !arm && !mips && !mipsle
package main
func g() { // GC_ERROR "stack frame too large"
xs := [3000 * 2000][33]int{}
for _, x := range xs {
if len(x) > 50 {
}
}
}
func main() { // GC_ERROR "stack frame too large"
defer f()
g()
}
func f() {}