about summary refs log tree commit diff
path: root/pkg/lang/vm/mem/mem.go
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-05-28 01:22:17 +0000
committerGitHub <noreply@github.com>2022-05-28 01:22:17 +0000
commit0a7700112f82e634a957685bee0cbaa3458f4945 (patch)
tree847c397970d7d852bc988a7a01f4625eae443edb /pkg/lang/vm/mem/mem.go
parent83d1dc87f3336d70ccda476627c70c282b7b6e11 (diff)
downloadjinx-0a7700112f82e634a957685bee0cbaa3458f4945.tar.zst
jinx-0a7700112f82e634a957685bee0cbaa3458f4945.zip
Harden VM Mem
Diffstat (limited to 'pkg/lang/vm/mem/mem.go')
-rw-r--r--pkg/lang/vm/mem/mem.go74
1 files changed, 53 insertions, 21 deletions
diff --git a/pkg/lang/vm/mem/mem.go b/pkg/lang/vm/mem/mem.go
index 4cb6fc4..bdcf01f 100644
--- a/pkg/lang/vm/mem/mem.go
+++ b/pkg/lang/vm/mem/mem.go
@@ -2,7 +2,7 @@ package mem
 
 type Mem struct {
 	cells []cell
-	free  []int
+	free  []Ptr
 }
 
 func New() Mem {
@@ -13,69 +13,101 @@ func New() Mem {
 
 	return Mem{
 		cells: cells,
-		free:  make([]int, 0),
+		free:  make([]Ptr, 0),
 	}
 }
 
-func (m *Mem) Allocate(kind CellKind) Ptr {
+func (m *Mem) Allocate(kind CellKind) (Ptr, error) {
 	if len(m.free) > 0 {
 		idx := m.free[len(m.free)-1]
 		m.free = m.free[:len(m.free)-1]
 
 		if m.cells[idx].kind != CellKindEmpty {
-			panic("invalid free cell")
+			return NullPtr, ErrFatalNonFreeCell
 		}
 
 		m.cells[idx].kind = kind
-		return Ptr(idx)
+		return Ptr(idx), nil
 	} else {
+		if len(m.cells) > 10000 {
+			return NullPtr, ErrMemOverflow
+		}
+
 		idx := len(m.cells)
 		m.cells = append(m.cells, cell{kind: kind, refs: 1})
-		return Ptr(idx)
+		return Ptr(idx), nil
 	}
 
 }
 
-func (m *Mem) Set(ptr Ptr, v any) {
-	if ptr >= Ptr(len(m.cells)) {
-		panic("out of bounds")
+func (m *Mem) Set(ptr Ptr, v CellData) error {
+	if err := m.validPtr(ptr); err != nil {
+		return err
 	}
 
 	m.cells[ptr].data = v
+	return nil
 }
 
-func (m *Mem) Get(ptr Ptr) any {
-	if ptr >= Ptr(len(m.cells)) {
-		panic("out of bounds")
+func (m *Mem) Get(ptr Ptr) (CellData, error) {
+	if err := m.validPtr(ptr); err != nil {
+		return nil, err
 	}
 
-	return m.cells[ptr].data
+	return m.cells[ptr].data, nil
 }
 
 func (m *Mem) Is(ptr Ptr, kind CellKind) bool {
 	if ptr >= Ptr(len(m.cells)) {
-		panic("out of bounds")
+		return false
 	}
 
 	return m.cells[ptr].kind == kind
 }
 
-func (m *Mem) Retain(ptr Ptr) {
+func (m *Mem) Kind(ptr Ptr) CellKind {
 	if ptr >= Ptr(len(m.cells)) {
-		panic("out of bounds")
+		return CellKindForbidden
+	}
+
+	return m.cells[ptr].kind
+}
+
+func (m *Mem) Retain(ptr Ptr) error {
+	if err := m.validPtr(ptr); err != nil {
+		return err
 	}
 
 	m.cells[ptr].refs++
+	return nil
 }
 
-func (m *Mem) Release(ptr Ptr) {
-	if ptr >= Ptr(len(m.cells)) {
-		panic("out of bounds")
+func (m *Mem) Release(ptr Ptr) error {
+	if err := m.validPtr(ptr); err != nil {
+		return err
 	}
 
 	m.cells[ptr].refs--
 	if m.cells[ptr].refs == 0 {
-		m.cells[ptr].kind = CellKindEmpty
-		m.free = append(m.free, int(ptr))
+		c := m.cells[ptr].data
+		c.DropCell(m)
+
+		m.cells[ptr] = cell{}
+		m.free = append(m.free, ptr)
 	}
+
+	return nil
+}
+
+func (m *Mem) validPtr(ptr Ptr) error {
+	if ptr >= Ptr(len(m.cells)) {
+		return ErrInvalidMemAccess{ptr}
+	}
+
+	kind := m.cells[ptr].kind
+	if kind == CellKindForbidden || kind == CellKindEmpty {
+		return ErrInvalidMemAccess{ptr}
+	}
+
+	return nil
 }