Source File
mem.go
Belonging Package
internal/fuzz
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fuzz
import (
)
// sharedMem manages access to a region of virtual memory mapped from a file,
// shared between multiple processes. The region includes space for a header and
// a value of variable length.
//
// When fuzzing, the coordinator creates a sharedMem from a temporary file for
// each worker. This buffer is used to pass values to fuzz between processes.
// Care must be taken to manage access to shared memory across processes;
// sharedMem provides no synchronization on its own. See workerComm for an
// explanation.
type sharedMem struct {
// f is the file mapped into memory.
f *os.File
// region is the mapped region of virtual memory for f. The content of f may
// be read or written through this slice.
region []byte
// removeOnClose is true if the file should be deleted by Close.
removeOnClose bool
// sys contains OS-specific information.
sys sharedMemSys
}
// sharedMemHeader stores metadata in shared memory.
type sharedMemHeader struct {
// count is the number of times the worker has called the fuzz function.
// May be reset by coordinator.
count int64
// valueLen is the number of bytes in region which should be read.
valueLen int
// randState and randInc hold the state of a pseudo-random number generator.
randState, randInc uint64
// rawInMem is true if the region holds raw bytes, which occurs during
// minimization. If true after the worker fails during minimization, this
// indicates that an unrecoverable error occurred, and the region can be
// used to retrieve the raw bytes that caused the error.
rawInMem bool
}
// sharedMemSize returns the size needed for a shared memory buffer that can
// contain values of the given size.
func sharedMemSize( int) int {
// TODO(jayconrod): set a reasonable maximum size per platform.
return int(unsafe.Sizeof(sharedMemHeader{})) +
}
// sharedMemTempFile creates a new temporary file of the given size, then maps
// it into memory. The file will be removed when the Close method is called.
func sharedMemTempFile( int) ( *sharedMem, error) {
// Create a temporary file.
, := os.CreateTemp("", "fuzz-*")
if != nil {
return nil,
}
defer func() {
if != nil {
.Close()
os.Remove(.Name())
}
}()
// Resize it to the correct size.
:= sharedMemSize()
if := .Truncate(int64()); != nil {
return nil,
}
// Map the file into memory.
:= true
return sharedMemMapFile(, , )
}
// header returns a pointer to metadata within the shared memory region.
func ( *sharedMem) () *sharedMemHeader {
return (*sharedMemHeader)(unsafe.Pointer(&.region[0]))
}
// valueRef returns the value currently stored in shared memory. The returned
// slice points to shared memory; it is not a copy.
func ( *sharedMem) () []byte {
:= .header().valueLen
:= int(unsafe.Sizeof(sharedMemHeader{}))
return .region[ : +]
}
// valueCopy returns a copy of the value stored in shared memory.
func ( *sharedMem) () []byte {
:= .valueRef()
return bytes.Clone()
}
// setValue copies the data in b into the shared memory buffer and sets
// the length. len(b) must be less than or equal to the capacity of the buffer
// (as returned by cap(m.value())).
func ( *sharedMem) ( []byte) {
:= .valueRef()
if len() > cap() {
panic(fmt.Sprintf("value length %d larger than shared memory capacity %d", len(), cap()))
}
.header().valueLen = len()
copy([:cap()], )
}
// setValueLen sets the length of the shared memory buffer returned by valueRef
// to n, which may be at most the cap of that slice.
//
// Note that we can only store the length in the shared memory header. The full
// slice header contains a pointer, which is likely only valid for one process,
// since each process can map shared memory at a different virtual address.
func ( *sharedMem) ( int) {
:= .valueRef()
if > cap() {
panic(fmt.Sprintf("length %d larger than shared memory capacity %d", , cap()))
}
.header().valueLen =
}
// TODO(jayconrod): add method to resize the buffer. We'll need that when the
// mutator can increase input length. Only the coordinator will be able to
// do it, since we'll need to send a message to the worker telling it to
// remap the file.
The pages are generated with Golds v0.7.0-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |