aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/error.go
diff options
context:
space:
mode:
authorAlan Donovan <adonovan@google.com>2024-04-23 12:44:54 -0400
committerGopher Robot <gobot@golang.org>2024-05-08 19:10:41 +0000
commit69e75c8581e15328454bb6e2f1dc347f73616b37 (patch)
treef0fabe495e978fb211ef909e4c4b8d8a4085d559 /src/runtime/error.go
parent4513f1a1c1037574bfd94b8637329246f475a534 (diff)
downloadgo-69e75c8581e15328454bb6e2f1dc347f73616b37.tar.xz
runtime: properly frame panic values in tracebacks
This CL causes the printing of panic values to ensure that all newlines in the output are immediately followed by a tab, so that there is no way for a maliciously crafted panic value to fool a program attempting to parse the traceback into thinking that the panic value is in fact a goroutine stack. See https://github.com/golang/go/issues/64590#issuecomment-1932675696 + release note Updates #64590 Updates #63455 Change-Id: I5142acb777383c0c122779d984e73879567dc627 Reviewed-on: https://go-review.googlesource.com/c/go/+/581215 Auto-Submit: Alan Donovan <adonovan@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/error.go')
-rw-r--r--src/runtime/error.go35
1 files changed, 29 insertions, 6 deletions
diff --git a/src/runtime/error.go b/src/runtime/error.go
index fe95f31005..406f36ca5f 100644
--- a/src/runtime/error.go
+++ b/src/runtime/error.go
@@ -211,11 +211,16 @@ type stringer interface {
String() string
}
-// printany prints an argument passed to panic.
+// printpanicval prints an argument passed to panic.
// If panic is called with a value that has a String or Error method,
// it has already been converted into a string by preprintpanics.
-func printany(i any) {
- switch v := i.(type) {
+//
+// To ensure that the traceback can be unambiguously parsed even when
+// the panic value contains "\ngoroutine" and other stack-like
+// strings, newlines in the string representation of v are replaced by
+// "\n\t".
+func printpanicval(v any) {
+ switch v := v.(type) {
case nil:
print("nil")
case bool:
@@ -251,19 +256,22 @@ func printany(i any) {
case complex128:
print(v)
case string:
- print(v)
+ printindented(v)
default:
- printanycustomtype(i)
+ printanycustomtype(v)
}
}
+// Invariant: each newline in the string representation is followed by a tab.
func printanycustomtype(i any) {
eface := efaceOf(&i)
typestring := toRType(eface._type).string()
switch eface._type.Kind_ {
case abi.String:
- print(typestring, `("`, *(*string)(eface.data), `")`)
+ print(typestring, `("`)
+ printindented(*(*string)(eface.data))
+ print(`")`)
case abi.Bool:
print(typestring, "(", *(*bool)(eface.data), ")")
case abi.Int:
@@ -301,6 +309,21 @@ func printanycustomtype(i any) {
}
}
+// printindented prints s, replacing "\n" with "\n\t".
+func printindented(s string) {
+ for {
+ i := bytealg.IndexByteString(s, '\n')
+ if i < 0 {
+ break
+ }
+ i += len("\n")
+ print(s[:i])
+ print("\t")
+ s = s[i:]
+ }
+ print(s)
+}
+
// panicwrap generates a panic for a call to a wrapped value method
// with a nil pointer receiver.
//