二 Syzkaller学习笔记---更新syz-manager(19)


位置:pkg//.go: (*).()
功能:生成C代码,编译成二进制文件,执行并检查是否crash 。
说明:调用 .Write() 生成C代码; .() 编译出可执行文件; inst.() 执行二进制文件 。
func (inst *ExecProgInstance) RunCProg(p *prog.Prog, duration time.Duration,opts csource.Options) (*RunResult, error) {src, err := csource.Write(p, opts)if err != nil {return nil, err}inst.Logf(2, "testing compiled C program (duration=%v, %+v): %s", duration, opts, p)return inst.RunCProgRaw(src, p.Target, duration)}func (inst *ExecProgInstance) RunCProgRaw(src []byte, target *prog.Target,duration time.Duration) (*RunResult, error) {bin, err := csource.BuildNoWarn(target, src)if err != nil {return nil, err}defer os.Remove(bin)return inst.runBinary(bin, duration)
这两个函数是结构体的方法,用于执行经过编译的 C 程序 。具体来说:
方法接收一个 Go 语言的程序 p,先将其转换为 C 语言源代码,并使用 . 对象指定编译选项,最后调用方法执行编译好的二进制文件 。方法接收一个二进制文件(已经通过 . 编译好了),并在执行过程中限制运行时间不超过。如果运行成功,则返回包含相应信息的对象,否则返回错误信息 。
需要注意的是,这两个方法都使用了 os. 函数删除了生成的临时文件
()
调用链: () -> () ->-> &
位置:
// Simplify repro options (threaded, sandbox, etc).func (ctx *context) simplifyProg(res *Result) (*Result, error) {ctx.reproLogf(2, "simplifying guilty program options")start := time.Now()defer func() {ctx.stats.SimplifyProgTime = time.Since(start)}()// Do further simplifications.for _, simplify := range progSimplifies {opts := res.Optsif !simplify(&opts) || !checkOpts(&opts, ctx.timeouts, res.Duration) {continue}crashed, err := ctx.testProg(res.Prog, res.Duration, opts)if err != nil {return nil, err}if !crashed {continue}res.Opts = opts// Simplification successful, try extracting C repro.res, err = ctx.extractC(res)if err != nil {return nil, err}if res.CRepro {return res, nil}}return res, nil}
这个函数实现了对程序参数的简化,以便更容易地重现导致崩溃或错误的场景 。具体来说:
在执行过程中,该函数首先遍历列表中的每个函数,并尝试将结果应用于对象的选项 。如果简化后的选项合法,则使用 ctx. 函数测试是否可以在新的选项下触发相同的错误 。如果测试成功,则将简化后的选项保存到 res.Opts 中,并进一步尝试提取 C 语言重现文件 。如果最终提取出 C 重现文件成功,则返回包含此信息的对象;否则,该函数将继续尝试其他简化方法,直到所有方法都被尝试完毕为止 。
需要注意的是,在执行过程中,该函数会记录运行时间、统计信息等,并在最后返回处理后的对象 。
func (ctx *context) testProgs(entries []*prog.LogEntry, duration time.Duration, opts csource.Options) (crashed bool, err error) {if len(entries) == 0 {return false, fmt.Errorf("no programs to execute")}pstr := encodeEntries(entries)program := entries[0].P.String()if len(entries) > 1 {program = "["for i, entry := range entries {program += fmt.Sprintf("%v", len(entry.P.Calls))if i != len(entries)-1 {program += ", "}}program += "]"}ctx.reproLogf(2, "testing program (duration=%v, %+v): %s", duration, opts, program)ctx.reproLogf(3, "detailed listing:\n%s", pstr)//重点在下面return ctx.testWithInstance(func(inst *instance.ExecProgInstance) (*instance.RunResult, error) {return inst.RunSyzProg(pstr, duration, opts)})}
这个函数实际上是一个调用 ctx. 函数的简写方式,其中传递了一个匿名函数作为参数 。具体来说:
匿名函数的定义与类型为 func(*.) (*., error),即它接收一个 *. 类型的参数,返回一个 *. 类型的对象以及一个错误对象(如果有) 。在执行过程中,该匿名函数将调用 inst. 方法来执行程序,并返回相应的结果和错误值 。该函数将该匿名函数作为参数传递给 ctx. 函数,然后将其返回值(即对象和错误值)返回给调用者 。