mirror of
https://github.com/golang/go
synced 2024-11-24 02:00:20 -07:00
613383c765
Before, a slice with cap=0 or a string with len=0 might have its base pointer pointing beyond the actual slice/string data into the next block. The collector had to ignore slices and strings with cap=0 in order to avoid misinterpreting the base pointer. Now, a slice with cap=0 or a string with len=0 still has a base pointer pointing into the actual slice/string data, no matter what. The collector can now always scan the pointer, which means strings and slices are no longer special. Fixes #8404. LGTM=khr, josharian R=josharian, khr, dvyukov CC=golang-codereviews https://golang.org/cl/112570044
161 lines
2.9 KiB
Go
161 lines
2.9 KiB
Go
// runoutput
|
|
|
|
// Copyright 2013 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.
|
|
|
|
// Test run-time behavior of 3-index slice expressions.
|
|
|
|
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
var bout *bufio.Writer
|
|
|
|
func main() {
|
|
bout = bufio.NewWriter(os.Stdout)
|
|
|
|
fmt.Fprintf(bout, "%s", programTop)
|
|
fmt.Fprintf(bout, "func main() {\n")
|
|
|
|
index := []string{
|
|
"0",
|
|
"1",
|
|
"2",
|
|
"3",
|
|
"10",
|
|
"20",
|
|
"vminus1",
|
|
"v0",
|
|
"v1",
|
|
"v2",
|
|
"v3",
|
|
"v10",
|
|
"v20",
|
|
}
|
|
|
|
parse := func(s string) (n int, isconst bool) {
|
|
if s == "vminus1" {
|
|
return -1, false
|
|
}
|
|
isconst = true
|
|
if s[0] == 'v' {
|
|
isconst = false
|
|
s = s[1:]
|
|
}
|
|
n, _ = strconv.Atoi(s)
|
|
return n, isconst
|
|
}
|
|
|
|
const Cap = 10 // cap of slice, array
|
|
|
|
for _, base := range []string{"array", "slice"} {
|
|
for _, i := range index {
|
|
iv, iconst := parse(i)
|
|
for _, j := range index {
|
|
jv, jconst := parse(j)
|
|
for _, k := range index {
|
|
kv, kconst := parse(k)
|
|
// Avoid errors that would make the program not compile.
|
|
// Those are tested by slice3err.go.
|
|
switch {
|
|
case iconst && jconst && iv > jv,
|
|
jconst && kconst && jv > kv,
|
|
iconst && kconst && iv > kv,
|
|
iconst && base == "array" && iv > Cap,
|
|
jconst && base == "array" && jv > Cap,
|
|
kconst && base == "array" && kv > Cap:
|
|
continue
|
|
}
|
|
|
|
expr := base + "[" + i + ":" + j + ":" + k + "]"
|
|
var xbase, xlen, xcap int
|
|
if iv > jv || jv > kv || kv > Cap || iv < 0 || jv < 0 || kv < 0 {
|
|
xbase, xlen, xcap = -1, -1, -1
|
|
} else {
|
|
xbase = iv
|
|
xlen = jv - iv
|
|
xcap = kv - iv
|
|
}
|
|
fmt.Fprintf(bout, "\tcheckSlice(%q, func() []byte { return %s }, %d, %d, %d)\n", expr, expr, xbase, xlen, xcap)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fmt.Fprintf(bout, "\tif !ok { os.Exit(1) }\n")
|
|
fmt.Fprintf(bout, "}\n")
|
|
bout.Flush()
|
|
}
|
|
|
|
var programTop = `
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"unsafe"
|
|
)
|
|
|
|
var ok = true
|
|
|
|
var (
|
|
array = new([10]byte)
|
|
slice = array[:]
|
|
|
|
vminus1 = -1
|
|
v0 = 0
|
|
v1 = 1
|
|
v2 = 2
|
|
v3 = 3
|
|
v4 = 4
|
|
v5 = 5
|
|
v10 = 10
|
|
v20 = 20
|
|
)
|
|
|
|
func notOK() {
|
|
if ok {
|
|
println("BUG:")
|
|
ok = false
|
|
}
|
|
}
|
|
|
|
func checkSlice(desc string, f func() []byte, xbase, xlen, xcap int) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
if xbase >= 0 {
|
|
notOK()
|
|
println(desc, " unexpected panic: ", fmt.Sprint(err))
|
|
}
|
|
}
|
|
// "no panic" is checked below
|
|
}()
|
|
|
|
x := f()
|
|
|
|
arrayBase := uintptr(unsafe.Pointer(array))
|
|
raw := *(*[3]uintptr)(unsafe.Pointer(&x))
|
|
base, len, cap := raw[0] - arrayBase, raw[1], raw[2]
|
|
if xbase < 0 {
|
|
notOK()
|
|
println(desc, "=", base, len, cap, "want panic")
|
|
return
|
|
}
|
|
if cap != 0 && base != uintptr(xbase) || base >= 10 || len != uintptr(xlen) || cap != uintptr(xcap) {
|
|
notOK()
|
|
if cap == 0 {
|
|
println(desc, "=", base, len, cap, "want", "0-9", xlen, xcap)
|
|
} else {
|
|
println(desc, "=", base, len, cap, "want", xbase, xlen, xcap)
|
|
}
|
|
}
|
|
}
|
|
|
|
`
|