Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(105)

Delta Between Two Patch Sets: test/nosplit.go

Issue 88190043: code review 88190043: liblink, cmd/ld: reenable nosplit checking and test (Closed)
Left Patch Set: diff -r 4b36e597c444 https://code.google.com/p/go/ Created 10 years, 11 months ago
Right Patch Set: diff -r 4873079c140c https://code.google.com/p/go/ Created 10 years, 11 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/debug/goobj/read.go ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
1 // run
2
3 // Copyright 2014 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6
7 package main
8
9 import (
10 "bytes"
11 "fmt"
12 "io/ioutil"
13 "os"
14 "os/exec"
15 "path/filepath"
16 "regexp"
17 "runtime"
18 "strconv"
19 "strings"
20 )
21
22 var tests = `
23 # These are test cases for the linker analysis that detects chains of
24 # nosplit functions that would cause a stack overflow.
25 #
26 # Lines beginning with # are comments.
27 #
28 # Each test case describes a sequence of functions, one per line.
29 # Each function definition is the function name, then the frame size,
30 # then optionally the keyword 'nosplit', then the body of the function.
31 # The body is assembly code, with some shorthands.
32 # The shorthand 'call x' stands for CALL x(SB).
33 # The shorthand 'callind' stands for 'CALL R0', where R0 is a register.
34 # Each test case must define a function named main, and it must be first.
35 # That is, a line beginning "main " indicates the start of a new test case.
36 # Within a stanza, ; can be used instead of \n to separate lines.
37 #
38 # After the function definition, the test case ends with an optional
39 # REJECT line, specifying the architectures on which the case should
40 # be rejected. "REJECT" without any architectures means reject on all architectu res.
41 # The linker should accept the test case on systems not explicitly rejected.
42 #
43 # 64-bit systems do not attempt to execute test cases with frame sizes
44 # that are only 32-bit aligned.
45
46 # Ordinary function should work
47 main 0
48
49 # Large frame marked nosplit is always wrong.
50 main 10000 nosplit
51 REJECT
52
53 # Calling a large frame is okay.
54 main 0 call big
55 big 10000
56
57 # But not if the frame is nosplit.
58 main 0 call big
59 big 10000 nosplit
60 REJECT
61
62 # Recursion is okay.
63 main 0 call main
64
65 # Recursive nosplit runs out of space.
66 main 0 nosplit call main
67 REJECT
68
69 # Chains of ordinary functions okay.
70 main 0 call f1
71 f1 80 call f2
72 f2 80
73
74 # Chains of nosplit must fit in the stack limit, 128 bytes.
75 main 0 call f1
76 f1 80 nosplit call f2
77 f2 80 nosplit
78 REJECT
79
80 # Larger chains.
81 main 0 call f1
82 f1 16 call f2
83 f2 16 call f3
84 f3 16 call f4
85 f4 16 call f5
86 f5 16 call f6
87 f6 16 call f7
88 f7 16 call f8
89 f8 16 call end
90 end 1000
91
92 main 0 call f1
93 f1 16 nosplit call f2
94 f2 16 nosplit call f3
95 f3 16 nosplit call f4
96 f4 16 nosplit call f5
97 f5 16 nosplit call f6
98 f6 16 nosplit call f7
99 f7 16 nosplit call f8
100 f8 16 nosplit call end
101 end 1000
102 REJECT
103
104 # Test cases near the 128-byte limit.
105
106 # Ordinary stack split frame is always okay.
107 main 112
108 main 116
109 main 120
110 main 124
111 main 128
112 main 132
113 main 136
114
115 # A nosplit leaf can use the whole 128-CallSize bytes available on entry.
116 main 112 nosplit
117 main 116 nosplit
118 main 120 nosplit
119 main 124 nosplit
120 main 128 nosplit; REJECT
121 main 132 nosplit; REJECT
122 main 136 nosplit; REJECT
123
124 # Calling a nosplit function from a nosplit function requires
125 # having room for the saved caller PC and the called frame.
126 # Because ARM doesn't save LR in the leaf, it gets an extra 4 bytes.
127 main 112 nosplit call f; f 0 nosplit
128 main 116 nosplit call f; f 0 nosplit; REJECT amd64
129 main 120 nosplit call f; f 0 nosplit; REJECT amd64
130 main 124 nosplit call f; f 0 nosplit; REJECT amd64 386
131 main 128 nosplit call f; f 0 nosplit; REJECT
132 main 132 nosplit call f; f 0 nosplit; REJECT
133 main 136 nosplit call f; f 0 nosplit; REJECT
134
135 # Calling a splitting function from a nosplit function requires
136 # having room for the saved caller PC of the call but also the
137 # saved caller PC for the call to morestack. Again the ARM works
138 # in less space.
139 main 104 nosplit call f; f 0 call f
140 main 108 nosplit call f; f 0 call f
141 main 112 nosplit call f; f 0 call f; REJECT amd64
142 main 116 nosplit call f; f 0 call f; REJECT amd64
143 main 120 nosplit call f; f 0 call f; REJECT amd64 386
144 main 124 nosplit call f; f 0 call f; REJECT amd64 386
145 main 128 nosplit call f; f 0 call f; REJECT
146 main 132 nosplit call f; f 0 call f; REJECT
147 main 136 nosplit call f; f 0 call f; REJECT
148
149 # Indirect calls are assumed to be splitting functions.
150 main 104 nosplit callind
151 main 108 nosplit callind
152 main 112 nosplit callind; REJECT amd64
153 main 116 nosplit callind; REJECT amd64
154 main 120 nosplit callind; REJECT amd64 386
155 main 124 nosplit callind; REJECT amd64 386
156 main 128 nosplit callind; REJECT
157 main 132 nosplit callind; REJECT
158 main 136 nosplit callind; REJECT
159
160 # Issue 7623
161 main 0 call f; f 112
162 main 0 call f; f 116
163 main 0 call f; f 120
164 main 0 call f; f 124
165 main 0 call f; f 128
166 main 0 call f; f 132
167 main 0 call f; f 136
168 `
169
170 var (
171 commentRE = regexp.MustCompile(`(?m)^#.*`)
172 rejectRE = regexp.MustCompile(`(?s)\A(.+?)((\n|; *)REJECT(.*))?\z`)
173 lineRE = regexp.MustCompile(`(\w+) (\d+)( nosplit)?(.*)`)
174 callRE = regexp.MustCompile(`\bcall (\w+)\b`)
175 callindRE = regexp.MustCompile(`\bcallind\b`)
176 )
177
178 func main() {
179 goarch := os.Getenv("GOARCH")
180 if goarch == "" {
181 goarch = runtime.GOARCH
182 }
183
184 dir, err := ioutil.TempDir("", "go-test-nosplit")
185 if err != nil {
186 bug()
187 fmt.Printf("creating temp dir: %v\n", err)
188 return
189 }
190 defer os.RemoveAll(dir)
191 ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte("package main\nfu nc main()\n"), 0666)
192
193 tests = strings.Replace(tests, "\t", " ", -1)
194 tests = commentRE.ReplaceAllString(tests, "")
195
196 nok := 0
197 nfail := 0
198 TestCases:
199 for len(tests) > 0 {
200 var stanza string
201 i := strings.Index(tests, "\nmain ")
202 if i < 0 {
203 stanza, tests = tests, ""
204 } else {
205 stanza, tests = tests[:i], tests[i+1:]
206 }
207
208 m := rejectRE.FindStringSubmatch(stanza)
209 if m == nil {
210 bug()
211 fmt.Printf("invalid stanza:\n\t%s\n", indent(stanza))
212 continue
213 }
214 lines := strings.TrimSpace(m[1])
215 reject := false
216 if m[2] != "" {
217 if strings.TrimSpace(m[4]) == "" {
218 reject = true
219 } else {
220 for _, rej := range strings.Fields(m[4]) {
221 if rej == goarch {
222 reject = true
223 }
224 }
225 }
226 }
227 if lines == "" && !reject {
228 continue
229 }
230
231 var buf bytes.Buffer
232 if goarch == "arm" {
233 fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0 )\n")
234 } else {
235 fmt.Fprintf(&buf, "#define REGISTER AX\n")
236 }
237
238 for _, line := range strings.Split(lines, "\n") {
239 line = strings.TrimSpace(line)
240 if line == "" {
241 continue
242 }
243 for _, subline := range strings.Split(line, ";") {
244 subline = strings.TrimSpace(subline)
245 if subline == "" {
246 continue
247 }
248 m := lineRE.FindStringSubmatch(subline)
249 if m == nil {
250 bug()
251 fmt.Printf("invalid function line: %s\n" , subline)
252 continue TestCases
253 }
254 name := m[1]
255 size, _ := strconv.Atoi(m[2])
256 if goarch == "amd64" && size%8 == 4 {
257 continue TestCases
258 }
259 nosplit := m[3]
260 body := m[4]
261
262 if nosplit != "" {
263 nosplit = ",7"
264 } else {
265 nosplit = ",0"
266 }
267 body = callRE.ReplaceAllString(body, "CALL ·$1(S B);")
268 body = callindRE.ReplaceAllString(body, "CALL RE GISTER;")
269
270 fmt.Fprintf(&buf, "TEXT ·%s(SB)%s,$%d-0\n\t%s\n\ tRET\n\n", name, nosplit, size, body)
271 }
272 }
273
274 ioutil.WriteFile(filepath.Join(dir, "asm.s"), buf.Bytes(), 0666)
275
276
277 cmd := exec.Command("go", "build")
278 cmd.Dir = dir
279 output, err := cmd.CombinedOutput()
280 if err == nil {
281 nok++
282 if reject {
283 bug()
284 fmt.Printf("accepted incorrectly:\n\t%s\n", inde nt(strings.TrimSpace(stanza)))
285 }
286 } else {
287 nfail++
288 if !reject {
289 bug()
290 fmt.Printf("rejected incorrectly:\n\t%s\n", inde nt(strings.TrimSpace(stanza)))
291 fmt.Printf("\n\tlinker output:\n\t%s\n", indent( string(output)))
292 }
293 }
294 }
295
296 if !bugged && (nok == 0 || nfail == 0) {
297 bug()
298 fmt.Printf("not enough test cases run\n")
299 }
300 }
301
302 func indent(s string) string {
303 return strings.Replace(s, "\n", "\n\t", -1)
304 }
305
306 var bugged = false
307
308 func bug() {
309 if !bugged {
310 bugged = true
311 fmt.Printf("BUG\n")
312 }
313 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b