1
2
3
4
5 package fuzz
6
7 import (
8 "fmt"
9 "os"
10 "os/exec"
11 "reflect"
12 "syscall"
13 "unsafe"
14 )
15
16 type sharedMemSys struct {
17 mapObj syscall.Handle
18 }
19
20 func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (mem *sharedMem, err error) {
21 defer func() {
22 if err != nil {
23 err = fmt.Errorf("mapping temporary file %s: %w", f.Name(), err)
24 }
25 }()
26
27
28 mapObj, err := syscall.CreateFileMapping(
29 syscall.Handle(f.Fd()),
30 nil,
31 syscall.PAGE_READWRITE,
32 0,
33 0,
34 nil,
35 )
36 if err != nil {
37 return nil, err
38 }
39
40
41 access := uint32(syscall.FILE_MAP_READ | syscall.FILE_MAP_WRITE)
42 addr, err := syscall.MapViewOfFile(
43 mapObj,
44 access,
45 0,
46 0,
47 uintptr(size),
48 )
49 if err != nil {
50 syscall.CloseHandle(mapObj)
51 return nil, err
52 }
53
54 var region []byte
55 header := (*reflect.SliceHeader)(unsafe.Pointer(®ion))
56 header.Data = addr
57 header.Len = size
58 header.Cap = size
59 return &sharedMem{
60 f: f,
61 region: region,
62 removeOnClose: removeOnClose,
63 sys: sharedMemSys{mapObj: mapObj},
64 }, nil
65 }
66
67
68
69 func (m *sharedMem) Close() error {
70
71
72
73 var errs []error
74 errs = append(errs,
75 syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&m.region[0]))),
76 syscall.CloseHandle(m.sys.mapObj),
77 m.f.Close())
78 if m.removeOnClose {
79 errs = append(errs, os.Remove(m.f.Name()))
80 }
81 for _, err := range errs {
82 if err != nil {
83 return err
84 }
85 }
86 return nil
87 }
88
89
90
91 func setWorkerComm(cmd *exec.Cmd, comm workerComm) {
92 mem := <-comm.memMu
93 memName := mem.f.Name()
94 comm.memMu <- mem
95 syscall.SetHandleInformation(syscall.Handle(comm.fuzzIn.Fd()), syscall.HANDLE_FLAG_INHERIT, 1)
96 syscall.SetHandleInformation(syscall.Handle(comm.fuzzOut.Fd()), syscall.HANDLE_FLAG_INHERIT, 1)
97 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_TEST_FUZZ_WORKER_HANDLES=%x,%x,%q", comm.fuzzIn.Fd(), comm.fuzzOut.Fd(), memName))
98 cmd.SysProcAttr = &syscall.SysProcAttr{AdditionalInheritedHandles: []syscall.Handle{syscall.Handle(comm.fuzzIn.Fd()), syscall.Handle(comm.fuzzOut.Fd())}}
99 }
100
101
102 func getWorkerComm() (comm workerComm, err error) {
103 v := os.Getenv("GO_TEST_FUZZ_WORKER_HANDLES")
104 if v == "" {
105 return workerComm{}, fmt.Errorf("GO_TEST_FUZZ_WORKER_HANDLES not set")
106 }
107 var fuzzInFD, fuzzOutFD uintptr
108 var memName string
109 if _, err := fmt.Sscanf(v, "%x,%x,%q", &fuzzInFD, &fuzzOutFD, &memName); err != nil {
110 return workerComm{}, fmt.Errorf("parsing GO_TEST_FUZZ_WORKER_HANDLES=%s: %v", v, err)
111 }
112
113 fuzzIn := os.NewFile(fuzzInFD, "fuzz_in")
114 fuzzOut := os.NewFile(fuzzOutFD, "fuzz_out")
115 tmpFile, err := os.OpenFile(memName, os.O_RDWR, 0)
116 if err != nil {
117 return workerComm{}, fmt.Errorf("worker opening temp file: %w", err)
118 }
119 fi, err := tmpFile.Stat()
120 if err != nil {
121 return workerComm{}, fmt.Errorf("worker checking temp file size: %w", err)
122 }
123 size := int(fi.Size())
124 if int64(size) != fi.Size() {
125 return workerComm{}, fmt.Errorf("fuzz temp file exceeds maximum size")
126 }
127 removeOnClose := false
128 mem, err := sharedMemMapFile(tmpFile, size, removeOnClose)
129 if err != nil {
130 return workerComm{}, err
131 }
132 memMu := make(chan *sharedMem, 1)
133 memMu <- mem
134
135 return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, memMu: memMu}, nil
136 }
137
138 func isInterruptError(err error) bool {
139
140
141 return false
142 }
143
144
145 func terminationSignal(err error) (os.Signal, bool) {
146 return syscall.Signal(-1), false
147 }
148
149
150 func isCrashSignal(signal os.Signal) bool {
151 panic("not implemented: no signals on windows")
152 }
153
View as plain text