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