Golang程序  |  188行  |  4.2 KB

// Copyright 2018 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package report

import (
	"bytes"
	"regexp"
)

type gvisor struct {
	ignores []*regexp.Regexp
}

func ctorGvisor(kernelSrc, kernelObj string, ignores []*regexp.Regexp) (Reporter, []string, error) {
	ctx := &gvisor{
		ignores: ignores,
	}
	suppressions := []string{
		"fatal error: runtime: out of memory",
		"fatal error: runtime: cannot allocate memory",
		"panic: ptrace sysemu failed: no such process",     // OOM kill
		"panic: ptrace set fpregs failed: no such process", // OOM kill
		"panic: ptrace set regs failed: no such process",   // OOM kill
		"panic: failed to start executor binary",
		"panic: executor failed: pthread_create failed",
		"ERROR: ThreadSanitizer", // Go race failing due to OOM.
		"FATAL: ThreadSanitizer",
	}
	return ctx, suppressions, nil
}

func (ctx *gvisor) ContainsCrash(output []byte) bool {
	return containsCrash(output, gvisorOopses, ctx.ignores)
}

func (ctx *gvisor) Parse(output []byte) *Report {
	rep := simpleLineParser(output, gvisorOopses, nil, ctx.ignores)
	if rep == nil {
		return nil
	}
	rep.Title = replaceTable(gvisorTitleReplacement, rep.Title)
	rep.Report = ctx.shortenReport(rep.Report)
	return rep
}

func (ctx *gvisor) shortenReport(report []byte) []byte {
	// gvisor panics include stacks of all goroutines.
	// This output is too lengthy for report and not very useful.
	// So we always take 5 lines from report and then cut it at the next empty line.
	// The intention is to capture panic header and traceback of the first goroutine.
	pos := 0
	for i := 0; i < 5; i++ {
		pos1 := bytes.IndexByte(report[pos:], '\n')
		if pos1 == -1 {
			return report
		}
		pos += pos1 + 1
	}
	end := bytes.Index(report[pos:], []byte{'\n', '\n'})
	if end == -1 {
		return report
	}
	if bytes.Contains(report, []byte("WARNING: DATA RACE")) {
		// For data races extract both stacks.
		end2 := bytes.Index(report[pos+end+2:], []byte{'\n', '\n'})
		if end2 != -1 {
			end += end2 + 2
		}
	}
	return report[:pos+end+1]
}

func (ctx *gvisor) Symbolize(rep *Report) error {
	return nil
}

var gvisorTitleReplacement = []replacement{
	{
		regexp.MustCompile(`container ".*"`),
		"container NAME",
	},
}

var gvisorOopses = []*oops{
	{
		[]byte("panic:"),
		[]oopsFormat{
			{
				title:        compile("panic:(.*)"),
				fmt:          "panic:%[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
	{
		[]byte("Panic:"),
		[]oopsFormat{
			{
				title:        compile("Panic:(.*)"),
				fmt:          "Panic:%[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
	{
		[]byte("fatal error:"),
		[]oopsFormat{
			{
				title:        compile("fatal error:(.*)"),
				fmt:          "fatal error:%[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
	{
		[]byte("runtime error:"),
		[]oopsFormat{
			{
				title:        compile("runtime error:(.*)"),
				fmt:          "runtime error:%[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
	{
		[]byte("SIGSEGV:"),
		[]oopsFormat{
			{
				title:        compile("SIGSEGV:(.*)"),
				fmt:          "SIGSEGV:%[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
	{
		[]byte("SIGBUS:"),
		[]oopsFormat{
			{
				title:        compile("SIGBUS:(.*)"),
				fmt:          "SIGBUS:%[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
	{
		[]byte("FATAL ERROR:"),
		[]oopsFormat{
			{
				title:        compile("FATAL ERROR:(.*)"),
				fmt:          "FATAL ERROR:%[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
	{
		[]byte("WARNING: DATA RACE"),
		[]oopsFormat{
			{
				title:        compile("WARNING: DATA RACE"),
				report:       compile("WARNING: DATA RACE\n(?:.*\n)*?  (?:[a-zA-Z0-9./-_]+/)([a-zA-Z0-9.()*_]+)\\(\\)\n"),
				fmt:          "DATA RACE in %[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
	{
		[]byte("Invalid request partialResult"),
		[]oopsFormat{
			{
				title:        compile("Invalid request partialResult"),
				report:       compile("Invalid request partialResult .* for (.*) operation"),
				fmt:          "Invalid request partialResult in %[1]v",
				noStackTrace: true,
			},
		},
		[]*regexp.Regexp{},
	},
}