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 memName := mem.f.Name()
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 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_TEST_FUZZ_WORKER_HANDLES=%x,%x,%q", comm.fuzzIn.Fd(), comm.fuzzOut.Fd(), memName))
93 cmd.SysProcAttr = &syscall.SysProcAttr{AdditionalInheritedHandles: []syscall.Handle{syscall.Handle(comm.fuzzIn.Fd()), syscall.Handle(comm.fuzzOut.Fd())}}
94 }
95
96
97 func getWorkerComm() (comm workerComm, err error) {
98 v := os.Getenv("GO_TEST_FUZZ_WORKER_HANDLES")
99 if v == "" {
100 return workerComm{}, fmt.Errorf("GO_TEST_FUZZ_WORKER_HANDLES not set")
101 }
102 var fuzzInFD, fuzzOutFD uintptr
103 var memName string
104 if _, err := fmt.Sscanf(v, "%x,%x,%q", &fuzzInFD, &fuzzOutFD, &memName); 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 tmpFile, err := os.OpenFile(memName, os.O_RDWR, 0)
111 if err != nil {
112 return workerComm{}, fmt.Errorf("worker opening temp file: %w", err)
113 }
114 fi, err := tmpFile.Stat()
115 if err != nil {
116 return workerComm{}, fmt.Errorf("worker checking temp file size: %w", err)
117 }
118 size := int(fi.Size())
119 if int64(size) != fi.Size() {
120 return workerComm{}, fmt.Errorf("fuzz temp file exceeds maximum size")
121 }
122 removeOnClose := false
123 mem, err := sharedMemMapFile(tmpFile, size, removeOnClose)
124 if err != nil {
125 return workerComm{}, err
126 }
127 memMu := make(chan *sharedMem, 1)
128 memMu <- mem
129
130 return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, memMu: memMu}, nil
131 }
132
133 func isInterruptError(err error) bool {
134
135
136 return false
137 }
138
139
140 func terminationSignal(err error) (os.Signal, bool) {
141 return syscall.Signal(-1), false
142 }
143
144
145 func isCrashSignal(signal os.Signal) bool {
146 panic("not implemented: no signals on windows")
147 }
148
View as plain text