// run // Copyright 2020 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. // This test is not for a fix of 29312 proper, but for the patch that // makes sure we at least don't have a security hole because of 29312. // This code generates lots of types. The binary should contain // a runtime.slicetype for each of the following 253 types: // // []*pwn // [][]*pwn // ... // [][]...[][]*pwn - 249 total "[]" // [][]...[][][]*pwn - 250 total "[]" // [][]...[][][][]*pwn - 251 total "[]" // [][]...[][][][][]*pwn - 252 total "[]" // [][]...[][][][][][]*pwn - 253 total "[]" // // The type names for these types are as follows. Because we truncate // the name at depth 250, the last few names are all identical: // // type:[]*"".pwn // type:[][]*"".pwn // ... // type:[][]...[][]*pwn - 249 total "[]" // type:[][]...[][][]*<...> - 250 total "[]" // type:[][]...[][][][]<...> - 251 total "[]" // type:[][]...[][][][]<...> - 252 total "[]" (but only 251 "[]" in the name) // type:[][]...[][][][]<...> - 253 total "[]" (but only 251 "[]" in the name) // // Because the names of the last 3 types are all identical, the // compiler will generate only a single runtime.slicetype data // structure for all 3 underlying types. It turns out the compiler // generates just the 251-entry one. There aren't any // runtime.slicetypes generated for the final two types. // // The compiler passes type:[]...[]<...> (251 total "[]") to // fmt.Sprintf (instead of the correct 253 one). But the data // structure at runtime actually has 253 nesting levels. So we end up // calling String on something that is of type [][]*pwn instead of // something of type *pwn. The way arg passing in Go works, the // backing store pointer for the outer slice becomes the "this" // pointer of the String method, which points to the inner []*pwn // slice. The String method then modifies the length of that inner // slice. package main import "fmt" type pwn struct { a [3]uint } func (this *pwn) String() string { this.a[1] = 7 // update length return "" } func main() { var a pwn s := [][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]*pwn{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{&a}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} // depth 253 fmt.Sprint(s) n := len(s[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]) // depth 252, type []*pwn if n != 1 { panic(fmt.Sprintf("length was changed, want 1 got %d", n)) } }