aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/csource/options.go
blob: e253b3cdf82ec20ab50b43915d8119810fd041f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// Copyright 2017 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 csource

import (
	"bytes"
	"errors"
	"fmt"
)

// Options control various aspects of source generation.
// Dashboard also provides serialized Options along with syzkaller reproducers.
type Options struct {
	Threaded bool
	Collide  bool
	Repeat   bool
	Procs    int
	Sandbox  string

	Fault     bool // inject fault into FaultCall/FaultNth
	FaultCall int
	FaultNth  int

	// These options allow for a more fine-tuned control over the generated C code.
	EnableTun  bool
	UseTmpDir  bool
	HandleSegv bool
	WaitRepeat bool
	Debug      bool

	// Generate code for use with repro package to prints log messages,
	// which allows to distinguish between a hang and an absent crash.
	Repro bool
}

// Check checks if the opts combination is valid or not.
// For example, Collide without Threaded is not valid.
// Invalid combinations must not be passed to Write.
func (opts Options) Check() error {
	if !opts.Threaded && opts.Collide {
		// Collide requires threaded.
		return errors.New("Collide without Threaded")
	}
	if !opts.Repeat && opts.Procs > 1 {
		// This does not affect generated code.
		return errors.New("Procs>1 without Repeat")
	}
	if opts.Sandbox == "namespace" && !opts.UseTmpDir {
		// This is borken and never worked.
		// This tries to create syz-tmp dir in cwd,
		// which will fail if procs>1 and on second run of the program.
		return errors.New("Sandbox=namespace without UseTmpDir")
	}
	return nil
}

func (opts Options) Serialize() []byte {
	return []byte(fmt.Sprintf("%+v", opts))
}

func DeserializeOptions(data []byte) (Options, error) {
	data = bytes.Replace(data, []byte("Sandbox: "), []byte("Sandbox:empty "), -1)
	var opts Options
	n, err := fmt.Sscanf(string(data),
		"{Threaded:%t Collide:%t Repeat:%t Procs:%d Sandbox:%s"+
			" Fault:%t FaultCall:%d FaultNth:%d EnableTun:%t UseTmpDir:%t"+
			" HandleSegv:%t WaitRepeat:%t Debug:%t Repro:%t}",
		&opts.Threaded, &opts.Collide, &opts.Repeat, &opts.Procs, &opts.Sandbox,
		&opts.Fault, &opts.FaultCall, &opts.FaultNth, &opts.EnableTun, &opts.UseTmpDir,
		&opts.HandleSegv, &opts.WaitRepeat, &opts.Debug, &opts.Repro)
	if err != nil {
		return opts, fmt.Errorf("failed to parse repro options: %v", err)
	}
	if want := 14; n != want {
		return opts, fmt.Errorf("failed to parse repro options: got %v fields, want %v", n, want)
	}
	if opts.Sandbox == "empty" {
		opts.Sandbox = ""
	}
	return opts, nil
}