-
Notifications
You must be signed in to change notification settings - Fork 842
Expand file tree
/
Copy pathmemory_unsafe_test.go
More file actions
144 lines (114 loc) · 3.99 KB
/
memory_unsafe_test.go
File metadata and controls
144 lines (114 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package ebpf
import (
"runtime"
"structs"
"sync/atomic"
"testing"
"unsafe"
"github.com/go-quicktest/qt"
"github.com/cilium/ebpf/internal/sys"
)
func TestUnsafeMemoryDisabled(t *testing.T) {
mm, err := mustMmapableArray(t, 0).Memory()
qt.Assert(t, qt.IsNil(err))
_, err = memoryPointer[uint32](mm, 0)
qt.Assert(t, qt.ErrorIs(err, ErrNotSupported))
}
func TestUnsafeMemoryUnmap(t *testing.T) {
mm, err := mustMmapableArray(t, 0).unsafeMemory()
qt.Assert(t, qt.IsNil(err))
// Avoid unmap running twice.
runtime.SetFinalizer(unsafe.SliceData(mm.b), nil)
// unmap panics if the operation fails.
unmap(int(mm.Size()))(unsafe.SliceData(mm.b))
}
func TestUnsafeMemoryPointer(t *testing.T) {
m := mustMmapableArray(t, 0)
mm, err := m.unsafeMemory()
qt.Assert(t, qt.IsNil(err))
// Requesting an unaligned value should fail.
_, err = memoryPointer[uint32](mm, 7)
qt.Assert(t, qt.IsNotNil(err))
u64, err := memoryPointer[uint64](mm, 8)
qt.Assert(t, qt.IsNil(err))
want := uint64(0xf00d)
*u64 = want
qt.Assert(t, qt.Equals(*u64, want))
// Read back the value using the bpf syscall interface.
var got uint64
qt.Assert(t, qt.IsNil(m.Lookup(uint32(1), &got)))
qt.Assert(t, qt.Equals(got, want))
_, err = memoryPointer[*uint32](mm, 0)
qt.Assert(t, qt.ErrorIs(err, ErrInvalidType))
}
func TestUnsafeMemoryReadOnly(t *testing.T) {
rd, err := mustMmapableArray(t, sys.BPF_F_RDONLY_PROG).unsafeMemory()
qt.Assert(t, qt.IsNil(err))
// BPF_F_RDONLY_PROG flag, so the Memory should be read-only.
qt.Assert(t, qt.IsTrue(rd.ReadOnly()))
// Frozen maps can't be mapped rw either.
frozen := mustMmapableArray(t, 0)
qt.Assert(t, qt.IsNil(frozen.Freeze()))
fz, err := frozen.Memory()
qt.Assert(t, qt.IsNil(err))
qt.Assert(t, qt.IsTrue(fz.ReadOnly()))
_, err = fz.WriteAt([]byte{1}, 0)
qt.Assert(t, qt.ErrorIs(err, ErrReadOnly))
_, err = memoryPointer[uint32](fz, 0)
qt.Assert(t, qt.ErrorIs(err, ErrReadOnly))
}
func TestCheckUnsafeMemory(t *testing.T) {
mm, err := mustMmapableArray(t, 0).unsafeMemory()
qt.Assert(t, qt.IsNil(err))
// Primitive types
qt.Assert(t, qt.IsNil(checkUnsafeMemory[bool](mm, 0)))
qt.Assert(t, qt.IsNil(checkUnsafeMemory[uint32](mm, 0)))
// Arrays
qt.Assert(t, qt.IsNil(checkUnsafeMemory[[4]byte](mm, 0)))
qt.Assert(t, qt.IsNil(checkUnsafeMemory[[2]struct {
_ structs.HostLayout
A uint32
B uint64
}](mm, 0)))
// Structs
qt.Assert(t, qt.IsNil(checkUnsafeMemory[struct {
_ structs.HostLayout
_ uint32
}](mm, 0)))
qt.Assert(t, qt.IsNil(checkUnsafeMemory[struct {
_ structs.HostLayout
_ [4]byte
}](mm, 0)))
// Atomics
qt.Assert(t, qt.IsNil(checkUnsafeMemory[atomic.Uint32](mm, 0)))
qt.Assert(t, qt.IsNil(checkUnsafeMemory[struct {
_ structs.HostLayout
_ atomic.Uint32
}](mm, 0)))
// Special cases
qt.Assert(t, qt.IsNil(checkUnsafeMemory[uintptr](mm, 0)))
qt.Assert(t, qt.IsNil(checkUnsafeMemory[atomic.Uintptr](mm, 0)))
qt.Assert(t, qt.IsNil(checkUnsafeMemory[struct {
_ structs.HostLayout
_ uintptr
}](mm, 0)))
// No pointers
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[*uint32](mm, 0), ErrInvalidType))
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[**uint32](mm, 0), ErrInvalidType))
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[[1]*uint8](mm, 0), ErrInvalidType))
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[struct {
_ structs.HostLayout
_ *uint8
}](mm, 0), ErrInvalidType))
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[atomic.Pointer[uint64]](mm, 0), ErrInvalidType))
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[atomic.Value](mm, 0), ErrInvalidType))
// No variable-sized types
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[int](mm, 0), ErrInvalidType))
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[uint](mm, 0), ErrInvalidType))
// No interface types
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[any](mm, 0), ErrInvalidType))
// No zero-sized types
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[struct{ _ structs.HostLayout }](mm, 0), ErrInvalidType))
// No structs without HostLayout
qt.Assert(t, qt.ErrorIs(checkUnsafeMemory[struct{ _ uint32 }](mm, 0), ErrInvalidType))
}