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(n int) []byte { 25 1 : if n == 0 { 26 0 : return make([]byte, 0) 27 0 : } 28 : // We need to be conscious of the Cgo pointer passing rules: 29 : // 30 : // https://golang.org/cmd/cgo/#hdr-Passing_pointers 31 : // 32 : // ... 33 : // Note: the current implementation has a bug. While Go code is permitted 34 : // to write nil or a C pointer (but not a Go pointer) to C memory, the 35 : // current implementation may sometimes cause a runtime error if the 36 : // contents of the C memory appear to be a Go pointer. Therefore, avoid 37 : // passing uninitialized C memory to Go code if the Go code is going to 38 : // store pointer values in it. Zero out the memory in C before passing it 39 : // to Go. 40 1 : ptr := C.calloc(C.size_t(n), 1) 41 1 : if ptr == nil { 42 0 : // NB: throw is like panic, except it guarantees the process will be 43 0 : // terminated. The call below is exactly what the Go runtime invokes when 44 0 : // it cannot allocate memory. 45 0 : throw("out of memory") 46 0 : } 47 : // Interpret the C pointer as a pointer to a Go array, then slice. 48 1 : return (*[MaxArrayLen]byte)(unsafe.Pointer(ptr))[:n:n] 49 : } 50 : 51 : // Free frees the specified slice. 52 1 : func Free(b []byte) { 53 1 : if cap(b) != 0 { 54 1 : if len(b) == 0 { 55 1 : b = b[:cap(b)] 56 1 : } 57 1 : ptr := unsafe.Pointer(&b[0]) 58 1 : C.free(ptr) 59 : } 60 : }