github.com/JimmyHuang454/JLS-go@v0.0.0-20230831150107-90d536585ba0/internal/fuzz/sys_windows.go (about) 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 "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 // Create a file mapping object. The object itself is not shared. 27 mapObj, err := syscall.CreateFileMapping( 28 syscall.Handle(f.Fd()), // fhandle 29 nil, // sa 30 syscall.PAGE_READWRITE, // prot 31 0, // maxSizeHigh 32 0, // maxSizeLow 33 nil, // name 34 ) 35 if err != nil { 36 return nil, err 37 } 38 39 // Create a view from the file mapping object. 40 access := uint32(syscall.FILE_MAP_READ | syscall.FILE_MAP_WRITE) 41 addr, err := syscall.MapViewOfFile( 42 mapObj, // handle 43 access, // access 44 0, // offsetHigh 45 0, // offsetLow 46 uintptr(size), // length 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 // Close unmaps the shared memory and closes the temporary file. If this 63 // sharedMem was created with sharedMemTempFile, Close also removes the file. 64 func (m *sharedMem) Close() error { 65 // Attempt all operations, even if we get an error for an earlier operation. 66 // os.File.Close may fail due to I/O errors, but we still want to delete 67 // the temporary file. 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 // setWorkerComm configures communication channels on the cmd that will 85 // run a worker process. 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 // getWorkerComm returns communication channels in the worker process. 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 // On Windows, we can't tell whether the process was interrupted by the error 135 // returned by Wait. It looks like an ExitError with status 1. 136 return false 137 } 138 139 // terminationSignal returns -1 and false because Windows doesn't have signals. 140 func terminationSignal(err error) (os.Signal, bool) { 141 return syscall.Signal(-1), false 142 } 143 144 // isCrashSignal is not implemented because Windows doesn't have signals. 145 func isCrashSignal(signal os.Signal) bool { 146 panic("not implemented: no signals on windows") 147 }