1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
16 type sharedMemSys struct {
20 func sharedMemMapFile(f *os.File, size int, removeOnClose bool) (mem *sharedMem, err error) {
23 err = fmt.Errorf("mapping temporary file %s: %w", f.Name(), err)
27 // Create a file mapping object. The object itself is not shared.
28 mapObj, err := syscall.CreateFileMapping(
29 syscall.Handle(f.Fd()), // fhandle
31 syscall.PAGE_READWRITE, // prot
40 // Create a view from the file mapping object.
41 access := uint32(syscall.FILE_MAP_READ | syscall.FILE_MAP_WRITE)
42 addr, err := syscall.MapViewOfFile(
47 uintptr(size), // length
50 syscall.CloseHandle(mapObj)
55 header := (*reflect.SliceHeader)(unsafe.Pointer(®ion))
62 removeOnClose: removeOnClose,
63 sys: sharedMemSys{mapObj: mapObj},
67 // Close unmaps the shared memory and closes the temporary file. If this
68 // sharedMem was created with sharedMemTempFile, Close also removes the file.
69 func (m *sharedMem) Close() error {
70 // Attempt all operations, even if we get an error for an earlier operation.
71 // os.File.Close may fail due to I/O errors, but we still want to delete
72 // the temporary file.
75 syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&m.region[0]))),
76 syscall.CloseHandle(m.sys.mapObj),
79 errs = append(errs, os.Remove(m.f.Name()))
81 for _, err := range errs {
89 // setWorkerComm configures communciation channels on the cmd that will
90 // run a worker process.
91 func setWorkerComm(cmd *exec.Cmd, comm workerComm) {
93 memName := mem.f.Name()
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())}}
101 // getWorkerComm returns communication channels in the worker process.
102 func getWorkerComm() (comm workerComm, err error) {
103 v := os.Getenv("GO_TEST_FUZZ_WORKER_HANDLES")
105 return workerComm{}, fmt.Errorf("GO_TEST_FUZZ_WORKER_HANDLES not set")
107 var fuzzInFD, fuzzOutFD uintptr
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)
113 fuzzIn := os.NewFile(fuzzInFD, "fuzz_in")
114 fuzzOut := os.NewFile(fuzzOutFD, "fuzz_out")
115 tmpFile, err := os.OpenFile(memName, os.O_RDWR, 0)
117 return workerComm{}, fmt.Errorf("worker opening temp file: %w", err)
119 fi, err := tmpFile.Stat()
121 return workerComm{}, fmt.Errorf("worker checking temp file size: %w", err)
123 size := int(fi.Size())
124 if int64(size) != fi.Size() {
125 return workerComm{}, fmt.Errorf("fuzz temp file exceeds maximum size")
127 removeOnClose := false
128 mem, err := sharedMemMapFile(tmpFile, size, removeOnClose)
130 return workerComm{}, err
132 memMu := make(chan *sharedMem, 1)
135 return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, memMu: memMu}, nil
138 func isInterruptError(err error) bool {
139 // On Windows, we can't tell whether the process was interrupted by the error
140 // returned by Wait. It looks like an ExitError with status 1.