summaryrefslogtreecommitdiffstats
path: root/test/fixedbugs/issue29312.go
blob: cbf79f704c11b0d27aac175471c01d7c66fad6a2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// 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))
	}
}