mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2024-12-27 13:13:10 +00:00
57dc742c76
Bumps [github.com/KimMachineGun/automemlimit](https://github.com/KimMachineGun/automemlimit) from 0.2.4 to 0.2.5. - [Release notes](https://github.com/KimMachineGun/automemlimit/releases) - [Commits](https://github.com/KimMachineGun/automemlimit/compare/v0.2.4...v0.2.5) --- updated-dependencies: - dependency-name: github.com/KimMachineGun/automemlimit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
206 lines
5.1 KiB
Go
206 lines
5.1 KiB
Go
package internal
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
// ErrorWithLog returns an error which includes logs from the kernel verifier.
|
|
//
|
|
// The default error output is a summary of the full log. The latter can be
|
|
// accessed via VerifierError.Log or by formatting the error, see Format.
|
|
//
|
|
// A set of heuristics is used to determine whether the log has been truncated.
|
|
func ErrorWithLog(err error, log []byte) *VerifierError {
|
|
const whitespace = "\t\r\v\n "
|
|
|
|
// Convert verifier log C string by truncating it on the first 0 byte
|
|
// and trimming trailing whitespace before interpreting as a Go string.
|
|
truncated := false
|
|
if i := bytes.IndexByte(log, 0); i != -1 {
|
|
if i == len(log)-1 && !bytes.HasSuffix(log[:i], []byte{'\n'}) {
|
|
// The null byte is at the end of the buffer and it's not preceded
|
|
// by a newline character. Most likely the buffer was too short.
|
|
truncated = true
|
|
}
|
|
|
|
log = log[:i]
|
|
} else if len(log) > 0 {
|
|
// No null byte? Dodgy!
|
|
truncated = true
|
|
}
|
|
|
|
log = bytes.Trim(log, whitespace)
|
|
logLines := bytes.Split(log, []byte{'\n'})
|
|
lines := make([]string, 0, len(logLines))
|
|
for _, line := range logLines {
|
|
// Don't remove leading white space on individual lines. We rely on it
|
|
// when outputting logs.
|
|
lines = append(lines, string(bytes.TrimRight(line, whitespace)))
|
|
}
|
|
|
|
return &VerifierError{err, lines, truncated}
|
|
}
|
|
|
|
// VerifierError includes information from the eBPF verifier.
|
|
//
|
|
// It summarises the log output, see Format if you want to output the full contents.
|
|
type VerifierError struct {
|
|
// The error which caused this error.
|
|
Cause error
|
|
// The verifier output split into lines.
|
|
Log []string
|
|
// Whether the log output is truncated, based on several heuristics.
|
|
Truncated bool
|
|
}
|
|
|
|
func (le *VerifierError) Unwrap() error {
|
|
return le.Cause
|
|
}
|
|
|
|
func (le *VerifierError) Error() string {
|
|
log := le.Log
|
|
if n := len(log); n > 0 && strings.HasPrefix(log[n-1], "processed ") {
|
|
// Get rid of "processed 39 insns (limit 1000000) ..." from summary.
|
|
log = log[:n-1]
|
|
}
|
|
|
|
n := len(log)
|
|
if n == 0 {
|
|
return le.Cause.Error()
|
|
}
|
|
|
|
lines := log[n-1:]
|
|
if n >= 2 && (includePreviousLine(log[n-1]) || le.Truncated) {
|
|
// Add one more line of context if it aids understanding the error.
|
|
lines = log[n-2:]
|
|
}
|
|
|
|
var b strings.Builder
|
|
fmt.Fprintf(&b, "%s: ", le.Cause.Error())
|
|
|
|
for i, line := range lines {
|
|
b.WriteString(strings.TrimSpace(line))
|
|
if i != len(lines)-1 {
|
|
b.WriteString(": ")
|
|
}
|
|
}
|
|
|
|
omitted := len(le.Log) - len(lines)
|
|
if omitted == 0 && !le.Truncated {
|
|
return b.String()
|
|
}
|
|
|
|
b.WriteString(" (")
|
|
if le.Truncated {
|
|
b.WriteString("truncated")
|
|
}
|
|
|
|
if omitted > 0 {
|
|
if le.Truncated {
|
|
b.WriteString(", ")
|
|
}
|
|
fmt.Fprintf(&b, "%d line(s) omitted", omitted)
|
|
}
|
|
b.WriteString(")")
|
|
|
|
return b.String()
|
|
}
|
|
|
|
// includePreviousLine returns true if the given line likely is better
|
|
// understood with additional context from the preceding line.
|
|
func includePreviousLine(line string) bool {
|
|
// We need to find a good trade off between understandable error messages
|
|
// and too much complexity here. Checking the string prefix is ok, requiring
|
|
// regular expressions to do it is probably overkill.
|
|
|
|
if strings.HasPrefix(line, "\t") {
|
|
// [13] STRUCT drm_rect size=16 vlen=4
|
|
// \tx1 type_id=2
|
|
return true
|
|
}
|
|
|
|
if len(line) >= 2 && line[0] == 'R' && line[1] >= '0' && line[1] <= '9' {
|
|
// 0: (95) exit
|
|
// R0 !read_ok
|
|
return true
|
|
}
|
|
|
|
if strings.HasPrefix(line, "invalid bpf_context access") {
|
|
// 0: (79) r6 = *(u64 *)(r1 +0)
|
|
// func '__x64_sys_recvfrom' arg0 type FWD is not a struct
|
|
// invalid bpf_context access off=0 size=8
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Format the error.
|
|
//
|
|
// Understood verbs are %s and %v, which are equivalent to calling Error(). %v
|
|
// allows outputting additional information using the following flags:
|
|
//
|
|
// + Output the first <width> lines, or all lines if no width is given.
|
|
// - Output the last <width> lines, or all lines if no width is given.
|
|
//
|
|
// Use width to specify how many lines to output. Use the '-' flag to output
|
|
// lines from the end of the log instead of the beginning.
|
|
func (le *VerifierError) Format(f fmt.State, verb rune) {
|
|
switch verb {
|
|
case 's':
|
|
_, _ = io.WriteString(f, le.Error())
|
|
|
|
case 'v':
|
|
n, haveWidth := f.Width()
|
|
if !haveWidth || n > len(le.Log) {
|
|
n = len(le.Log)
|
|
}
|
|
|
|
if !f.Flag('+') && !f.Flag('-') {
|
|
if haveWidth {
|
|
_, _ = io.WriteString(f, "%!v(BADWIDTH)")
|
|
return
|
|
}
|
|
|
|
_, _ = io.WriteString(f, le.Error())
|
|
return
|
|
}
|
|
|
|
if f.Flag('+') && f.Flag('-') {
|
|
_, _ = io.WriteString(f, "%!v(BADFLAG)")
|
|
return
|
|
}
|
|
|
|
fmt.Fprintf(f, "%s:", le.Cause.Error())
|
|
|
|
omitted := len(le.Log) - n
|
|
lines := le.Log[:n]
|
|
if f.Flag('-') {
|
|
// Print last instead of first lines.
|
|
lines = le.Log[len(le.Log)-n:]
|
|
if omitted > 0 {
|
|
fmt.Fprintf(f, "\n\t(%d line(s) omitted)", omitted)
|
|
}
|
|
}
|
|
|
|
for _, line := range lines {
|
|
fmt.Fprintf(f, "\n\t%s", line)
|
|
}
|
|
|
|
if !f.Flag('-') {
|
|
if omitted > 0 {
|
|
fmt.Fprintf(f, "\n\t(%d line(s) omitted)", omitted)
|
|
}
|
|
}
|
|
|
|
if le.Truncated {
|
|
fmt.Fprintf(f, "\n\t(truncated)")
|
|
}
|
|
|
|
default:
|
|
fmt.Fprintf(f, "%%!%c(BADVERB)", verb)
|
|
}
|
|
}
|