github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/wasm/binary/memory_test.go (about) 1 package binary 2 3 import ( 4 "bytes" 5 "fmt" 6 "testing" 7 8 "github.com/wasilibs/wazerox/api" 9 "github.com/wasilibs/wazerox/experimental" 10 "github.com/wasilibs/wazerox/internal/testing/binaryencoding" 11 "github.com/wasilibs/wazerox/internal/testing/require" 12 "github.com/wasilibs/wazerox/internal/wasm" 13 ) 14 15 func Test_newMemorySizer(t *testing.T) { 16 zero := uint32(0) 17 ten := uint32(10) 18 defaultLimit := wasm.MemoryLimitPages 19 20 tests := []struct { 21 name string 22 memoryCapacityFromMax bool 23 limit uint32 24 min uint32 25 max *uint32 26 expectedMin, expectedCapacity, expectedMax uint32 27 }{ 28 { 29 name: "min 0", 30 limit: defaultLimit, 31 min: zero, 32 max: &defaultLimit, 33 expectedMin: zero, 34 expectedCapacity: zero, 35 expectedMax: defaultLimit, 36 }, 37 { 38 name: "min 0 defaults max to defaultLimit", 39 limit: defaultLimit, 40 min: zero, 41 expectedMin: zero, 42 expectedCapacity: zero, 43 expectedMax: defaultLimit, 44 }, 45 { 46 name: "min 0, max 0", 47 limit: defaultLimit, 48 min: zero, 49 max: &zero, 50 expectedMin: zero, 51 expectedCapacity: zero, 52 expectedMax: zero, 53 }, 54 { 55 name: "min 0, max 10", 56 limit: defaultLimit, 57 min: zero, 58 max: &ten, 59 expectedMin: zero, 60 expectedCapacity: zero, 61 expectedMax: ten, 62 }, 63 { 64 name: "min 0, max 10 memoryCapacityFromMax", 65 limit: defaultLimit, 66 memoryCapacityFromMax: true, 67 min: zero, 68 max: &ten, 69 expectedMin: zero, 70 expectedCapacity: ten, 71 expectedMax: ten, 72 }, 73 { 74 name: "min 10, no max", 75 limit: 200, 76 min: 10, 77 expectedMin: 10, 78 expectedCapacity: 10, 79 expectedMax: 200, 80 }, 81 { 82 name: "min 10, no max memoryCapacityFromMax", 83 memoryCapacityFromMax: true, 84 limit: 200, 85 min: 10, 86 expectedMin: 10, 87 expectedCapacity: 200, 88 expectedMax: 200, 89 }, 90 { 91 name: "min=max", 92 limit: defaultLimit, 93 min: ten, 94 max: &ten, 95 expectedMin: ten, 96 expectedCapacity: ten, 97 expectedMax: ten, 98 }, 99 { 100 name: "max > memoryLimitPages", 101 limit: 5, 102 min: 0, 103 max: &ten, 104 expectedMin: 0, 105 expectedCapacity: 0, 106 expectedMax: 5, 107 }, 108 } 109 110 for _, tt := range tests { 111 tc := tt 112 t.Run(tc.name, func(t *testing.T) { 113 sizer := newMemorySizer(tc.limit, tc.memoryCapacityFromMax) 114 min, capacity, max := sizer(tc.min, tc.max) 115 require.Equal(t, tc.expectedMin, min) 116 require.Equal(t, tc.expectedCapacity, capacity) 117 require.Equal(t, tc.expectedMax, max) 118 }) 119 } 120 } 121 122 func TestMemoryType(t *testing.T) { 123 zero := uint32(0) 124 max := wasm.MemoryLimitPages 125 126 tests := []struct { 127 name string 128 input *wasm.Memory 129 memoryLimitPages uint32 130 expected []byte 131 }{ 132 { 133 name: "min 0", 134 input: &wasm.Memory{Max: max, IsMaxEncoded: true}, 135 expected: []byte{0x1, 0, 0x80, 0x80, 0x4}, 136 }, 137 { 138 name: "min 0 default max", 139 input: &wasm.Memory{Max: max}, 140 expected: []byte{0x0, 0}, 141 }, 142 { 143 name: "min 0, max 0", 144 input: &wasm.Memory{Max: zero, IsMaxEncoded: true}, 145 expected: []byte{0x1, 0, 0}, 146 }, 147 { 148 name: "min=max", 149 input: &wasm.Memory{Min: 1, Cap: 1, Max: 1, IsMaxEncoded: true}, 150 expected: []byte{0x1, 1, 1}, 151 }, 152 { 153 name: "min 0, max largest", 154 input: &wasm.Memory{Max: max, IsMaxEncoded: true}, 155 expected: []byte{0x1, 0, 0x80, 0x80, 0x4}, 156 }, 157 { 158 name: "min largest max largest", 159 input: &wasm.Memory{Min: max, Cap: max, Max: max, IsMaxEncoded: true}, 160 expected: []byte{0x1, 0x80, 0x80, 0x4, 0x80, 0x80, 0x4}, 161 }, 162 { 163 name: "min 0, max largest, wazero limit", 164 input: &wasm.Memory{Max: max, IsMaxEncoded: true}, 165 memoryLimitPages: 512, 166 expected: []byte{0x1, 0, 0x80, 0x80, 0x4}, 167 }, 168 } 169 170 for _, tt := range tests { 171 tc := tt 172 173 b := binaryencoding.EncodeMemory(tc.input) 174 t.Run(fmt.Sprintf("encode %s", tc.name), func(t *testing.T) { 175 require.Equal(t, tc.expected, b) 176 }) 177 178 t.Run(fmt.Sprintf("decode %s", tc.name), func(t *testing.T) { 179 tmax := max 180 expectedDecoded := tc.input 181 if tc.memoryLimitPages != 0 { 182 // If a memory limit exists, then the expected module Max reflects that limit. 183 tmax = tc.memoryLimitPages 184 expectedDecoded.Max = tmax 185 } 186 187 binary, err := decodeMemory(bytes.NewReader(b), api.CoreFeaturesV2, newMemorySizer(tmax, false), tmax) 188 require.NoError(t, err) 189 require.Equal(t, binary, expectedDecoded) 190 }) 191 } 192 } 193 194 func TestDecodeMemoryType_Errors(t *testing.T) { 195 max := wasm.MemoryLimitPages 196 197 tests := []struct { 198 name string 199 input []byte 200 threadsEnabled bool 201 expectedErr string 202 }{ 203 { 204 name: "max < min", 205 input: []byte{0x1, 0x80, 0x80, 0x4, 0}, 206 expectedErr: "min 65536 pages (4 Gi) > max 0 pages (0 Ki)", 207 }, 208 { 209 name: "min > limit", 210 input: []byte{0x0, 0xff, 0xff, 0xff, 0xff, 0xf}, 211 expectedErr: "min 4294967295 pages (3 Ti) over limit of 65536 pages (4 Gi)", 212 }, 213 { 214 name: "max > limit", 215 input: []byte{0x1, 0, 0xff, 0xff, 0xff, 0xff, 0xf}, 216 expectedErr: "max 4294967295 pages (3 Ti) over limit of 65536 pages (4 Gi)", 217 }, 218 { 219 name: "shared but no threads", 220 input: []byte{0x2, 0, 0x80, 0x80, 0x4}, 221 expectedErr: "shared memory requested but threads feature not enabled", 222 }, 223 { 224 name: "shared but no max", 225 input: []byte{0x2, 0, 0x80, 0x80, 0x4}, 226 threadsEnabled: true, 227 expectedErr: "shared memory requires a maximum size to be specified", 228 }, 229 } 230 231 for _, tt := range tests { 232 tc := tt 233 234 t.Run(tc.name, func(t *testing.T) { 235 features := api.CoreFeaturesV2 236 if tc.threadsEnabled { 237 features = features.SetEnabled(experimental.CoreFeaturesThreads, true) 238 } else { 239 // Allow test to work if threads is ever added to default features by explicitly removing threads features 240 features = features.SetEnabled(experimental.CoreFeaturesThreads, false) 241 } 242 _, err := decodeMemory(bytes.NewReader(tc.input), features, newMemorySizer(max, false), max) 243 require.EqualError(t, err, tc.expectedErr) 244 }) 245 } 246 }