Skip to content

Commit

Permalink
libc: safer realloc implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
dennwc committed Jun 2, 2022
1 parent 187be2c commit d57c260
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 9 deletions.
36 changes: 28 additions & 8 deletions runtime/libc/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"unsafe"
)

var allocs syncMap[unsafe.Pointer, []byte]

// makePad creates a slice with a given size, but adds padding before and after the slice.
// It is required to make some unsafe C code work, e.g. indexing elements after the slice end.
func makePad(sz int, pad int) []byte {
Expand All @@ -19,10 +21,17 @@ func makePad(sz int, pad int) []byte {
return p
}

func malloc(sz int) []byte {
b := makePad(sz, 0)
p := unsafe.Pointer(&b[0])
allocs.Store(p, b)
return b
}

// Malloc allocates a region of memory.
func Malloc(sz int) unsafe.Pointer {
p := makePad(sz, 0)
return unsafe.Pointer(&p[0])
b := malloc(sz)
return unsafe.Pointer(&b[0])
}

// Calloc allocates a region of memory for num elements of size sz.
Expand All @@ -33,22 +42,33 @@ func Calloc(num, sz int) unsafe.Pointer {
if sz <= 0 {
panic("size should be > 0")
}
p := makePad(num*sz, sz)
return unsafe.Pointer(&p[0])
b := makePad(num*sz, sz)
p := unsafe.Pointer(&b[0])
allocs.Store(p, b)
return p
}

func withSize(p unsafe.Pointer) ([]byte, bool) {
return allocs.Load(p)
}

func Realloc(buf unsafe.Pointer, sz int) unsafe.Pointer {
if buf == nil {
return Malloc(sz)
}
p := Malloc(sz)
MemCpy(p, buf, sz)
return p
p := malloc(sz)
src, ok := withSize(buf)
if !ok {
panic("realloc of a pointer not managed by cxgo")
}
copy(p, src)
Free(buf)
return unsafe.Pointer(&p[0])
}

// Free marks the memory as freed. May be a nop in Go.
func Free(p unsafe.Pointer) {
// nop
allocs.Delete(p)
}

// ToPointer converts a uintptr to unsafe.Pointer.
Expand Down
9 changes: 9 additions & 0 deletions runtime/libc/memory_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package libc

import "testing"

func TestRealloc(t *testing.T) {
p := Malloc(1)
p = Realloc(p, 32*1024*1024)
Free(p)
}
26 changes: 25 additions & 1 deletion runtime/libc/sync.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,30 @@
package libc

import "sync/atomic"
import (
"sync"
"sync/atomic"
)

type syncMap[K comparable, V any] struct {
m sync.Map
}

func (m *syncMap[K, V]) Store(k K, v V) {
m.m.Store(k, v)
}

func (m *syncMap[K, V]) Load(k K) (V, bool) {
vi, ok := m.m.Load(k)
if !ok {
var zero V
return zero, false
}
return vi.(V), true
}

func (m *syncMap[K, V]) Delete(k K) {
m.m.Delete(k)
}

// old = *p; *p (op)= val; return old;

Expand Down

0 comments on commit d57c260

Please sign in to comment.