]> Cypherpunks.ru repositories - gostls13.git/blob - src/internal/fuzz/sys_windows.go
[dev.fuzz] all: merge master (d137b74) into dev.fuzz
[gostls13.git] / src / internal / fuzz / sys_windows.go
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.
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         // Create a file mapping object. The object itself is not shared.
28         mapObj, err := syscall.CreateFileMapping(
29                 syscall.Handle(f.Fd()), // fhandle
30                 nil,                    // sa
31                 syscall.PAGE_READWRITE, // prot
32                 0,                      // maxSizeHigh
33                 0,                      // maxSizeLow
34                 nil,                    // name
35         )
36         if err != nil {
37                 return nil, err
38         }
39
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(
43                 mapObj,        // handle
44                 access,        // access
45                 0,             // offsetHigh
46                 0,             // offsetLow
47                 uintptr(size), // length
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(&region))
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 // 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.
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 // setWorkerComm configures communciation channels on the cmd that will
90 // run a worker process.
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 // getWorkerComm returns communication channels in the worker process.
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         // 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.
141         return false
142 }