Line data Source code
1 : // Copyright 2020 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 : // of this source code is governed by a BSD-style license that can be found in 3 : // the LICENSE file. 4 : 5 : package manual 6 : 7 : // #include <stdlib.h> 8 : import "C" 9 : import "unsafe" 10 : 11 : // The go:linkname directives provides backdoor access to private functions in 12 : // the runtime. Below we're accessing the throw function. 13 : 14 : //go:linkname throw runtime.throw 15 : func throw(s string) 16 : 17 : // TODO(peter): Rather than relying an C malloc/free, we could fork the Go 18 : // runtime page allocator and allocate large chunks of memory using mmap or 19 : // similar. 20 : 21 : // New allocates a slice of size n. The returned slice is from manually managed 22 : // memory and MUST be released by calling Free. Failure to do so will result in 23 : // a memory leak. 24 1 : func New(purpose Purpose, n int) []byte { 25 1 : if n == 0 { 26 0 : return make([]byte, 0) 27 0 : } 28 1 : recordAlloc(purpose, n) 29 1 : // We need to be conscious of the Cgo pointer passing rules: 30 1 : // 31 1 : // https://golang.org/cmd/cgo/#hdr-Passing_pointers 32 1 : // 33 1 : // ... 34 1 : // Note: the current implementation has a bug. While Go code is permitted 35 1 : // to write nil or a C pointer (but not a Go pointer) to C memory, the 36 1 : // current implementation may sometimes cause a runtime error if the 37 1 : // contents of the C memory appear to be a Go pointer. Therefore, avoid 38 1 : // passing uninitialized C memory to Go code if the Go code is going to 39 1 : // store pointer values in it. Zero out the memory in C before passing it 40 1 : // to Go. 41 1 : ptr := C.calloc(C.size_t(n), 1) 42 1 : if ptr == nil { 43 0 : // NB: throw is like panic, except it guarantees the process will be 44 0 : // terminated. The call below is exactly what the Go runtime invokes when 45 0 : // it cannot allocate memory. 46 0 : throw("out of memory") 47 0 : } 48 : // Interpret the C pointer as a pointer to a Go array, then slice. 49 1 : return (*[MaxArrayLen]byte)(unsafe.Pointer(ptr))[:n:n] 50 : } 51 : 52 : // Free frees the specified slice. It has to be exactly the slice that was 53 : // returned by New. 54 1 : func Free(purpose Purpose, b []byte) { 55 1 : if cap(b) != 0 { 56 1 : recordFree(purpose, cap(b)) 57 1 : if len(b) == 0 { 58 0 : b = b[:cap(b)] 59 0 : } 60 1 : ptr := unsafe.Pointer(&b[0]) 61 1 : C.free(ptr) 62 : } 63 : }