| |
| |
| |
|
|
| package fuzz |
|
|
| import ( |
| "fmt" |
| "os" |
| "os/exec" |
| "syscall" |
| "unsafe" |
| ) |
|
|
| type sharedMemSys struct { |
| mapObj syscall.Handle |
| } |
|
|
| func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (mem *sharedMem, err error) { |
| defer func() { |
| if err != nil { |
| err = fmt.Errorf("mapping temporary file %s: %w", f.Name(), err) |
| } |
| }() |
|
|
| |
| mapObj, err := syscall.CreateFileMapping( |
| syscall.Handle(f.Fd()), |
| nil, |
| syscall.PAGE_READWRITE, |
| 0, |
| 0, |
| nil, |
| ) |
| if err != nil { |
| return nil, err |
| } |
|
|
| |
| access := uint32(syscall.FILE_MAP_READ | syscall.FILE_MAP_WRITE) |
| addr, err := syscall.MapViewOfFile( |
| mapObj, |
| access, |
| 0, |
| 0, |
| uintptr(size), |
| ) |
| if err != nil { |
| syscall.CloseHandle(mapObj) |
| return nil, err |
| } |
|
|
| region := unsafe.Slice((*byte)(unsafe.Pointer(addr)), size) |
| return &sharedMem{ |
| f: f, |
| region: region, |
| removeOnClose: removeOnClose, |
| sys: sharedMemSys{mapObj: mapObj}, |
| }, nil |
| } |
|
|
| |
| |
| func (m *sharedMem) Close() error { |
| |
| |
| |
| var errs []error |
| errs = append(errs, |
| syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&m.region[0]))), |
| syscall.CloseHandle(m.sys.mapObj), |
| m.f.Close()) |
| if m.removeOnClose { |
| errs = append(errs, os.Remove(m.f.Name())) |
| } |
| for _, err := range errs { |
| if err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
|
|
| |
| |
| func setWorkerComm(cmd *exec.Cmd, comm workerComm) { |
| mem := <-comm.memMu |
| memFD := mem.f.Fd() |
| comm.memMu <- mem |
| syscall.SetHandleInformation(syscall.Handle(comm.fuzzIn.Fd()), syscall.HANDLE_FLAG_INHERIT, 1) |
| syscall.SetHandleInformation(syscall.Handle(comm.fuzzOut.Fd()), syscall.HANDLE_FLAG_INHERIT, 1) |
| syscall.SetHandleInformation(syscall.Handle(memFD), syscall.HANDLE_FLAG_INHERIT, 1) |
| cmd.Env = append(cmd.Env, fmt.Sprintf("GO_TEST_FUZZ_WORKER_HANDLES=%x,%x,%x", comm.fuzzIn.Fd(), comm.fuzzOut.Fd(), memFD)) |
| cmd.SysProcAttr = &syscall.SysProcAttr{AdditionalInheritedHandles: []syscall.Handle{syscall.Handle(comm.fuzzIn.Fd()), syscall.Handle(comm.fuzzOut.Fd()), syscall.Handle(memFD)}} |
| } |
|
|
| |
| func getWorkerComm() (comm workerComm, err error) { |
| v := os.Getenv("GO_TEST_FUZZ_WORKER_HANDLES") |
| if v == "" { |
| return workerComm{}, fmt.Errorf("GO_TEST_FUZZ_WORKER_HANDLES not set") |
| } |
| var fuzzInFD, fuzzOutFD, memFileFD uintptr |
| if _, err := fmt.Sscanf(v, "%x,%x,%x", &fuzzInFD, &fuzzOutFD, &memFileFD); err != nil { |
| return workerComm{}, fmt.Errorf("parsing GO_TEST_FUZZ_WORKER_HANDLES=%s: %v", v, err) |
| } |
|
|
| fuzzIn := os.NewFile(fuzzInFD, "fuzz_in") |
| fuzzOut := os.NewFile(fuzzOutFD, "fuzz_out") |
| memFile := os.NewFile(memFileFD, "fuzz_mem") |
| fi, err := memFile.Stat() |
| if err != nil { |
| return workerComm{}, fmt.Errorf("worker checking temp file size: %w", err) |
| } |
| size := int(fi.Size()) |
| if int64(size) != fi.Size() { |
| return workerComm{}, fmt.Errorf("fuzz temp file exceeds maximum size") |
| } |
| removeOnClose := false |
| mem, err := sharedMemMapFile(memFile, size, removeOnClose) |
| if err != nil { |
| return workerComm{}, err |
| } |
| memMu := make(chan *sharedMem, 1) |
| memMu <- mem |
|
|
| return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, memMu: memMu}, nil |
| } |
|
|
| func isInterruptError(err error) bool { |
| |
| |
| return false |
| } |
|
|
| |
| func terminationSignal(err error) (os.Signal, bool) { |
| return syscall.Signal(-1), false |
| } |
|
|
| |
| func isCrashSignal(signal os.Signal) bool { |
| panic("not implemented: no signals on windows") |
| } |
|
|