Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wiggle/tests/records.rs
1692 views
1
use proptest::prelude::*;
2
use wiggle::{GuestMemory, GuestPtr};
3
use wiggle_test::{HostMemory, MemArea, MemAreas, WasiCtx, impl_errno};
4
5
wiggle::from_witx!({
6
witx: ["tests/records.witx"],
7
});
8
9
impl_errno!(types::Errno);
10
11
impl<'a> records::Records for WasiCtx<'a> {
12
fn sum_of_pair(
13
&mut self,
14
_memory: &mut GuestMemory<'_>,
15
an_pair: &types::PairInts,
16
) -> Result<i64, types::Errno> {
17
Ok(an_pair.first as i64 + an_pair.second as i64)
18
}
19
20
fn sum_of_pair_of_ptrs(
21
&mut self,
22
memory: &mut GuestMemory<'_>,
23
an_pair: &types::PairIntPtrs,
24
) -> Result<i64, types::Errno> {
25
let first = memory
26
.read(an_pair.first)
27
.expect("dereferencing GuestPtr should succeed");
28
let second = memory
29
.read(an_pair.second)
30
.expect("dereferencing GuestPtr should succeed");
31
Ok(first as i64 + second as i64)
32
}
33
34
fn sum_of_int_and_ptr(
35
&mut self,
36
memory: &mut GuestMemory<'_>,
37
an_pair: &types::PairIntAndPtr,
38
) -> Result<i64, types::Errno> {
39
let first = memory
40
.read(an_pair.first)
41
.expect("dereferencing GuestPtr should succeed");
42
let second = an_pair.second as i64;
43
Ok(first as i64 + second)
44
}
45
46
fn return_pair_ints(
47
&mut self,
48
_memory: &mut GuestMemory<'_>,
49
) -> Result<types::PairInts, types::Errno> {
50
Ok(types::PairInts {
51
first: 10,
52
second: 20,
53
})
54
}
55
56
fn return_pair_of_ptrs(
57
&mut self,
58
_memory: &mut GuestMemory<'_>,
59
first: GuestPtr<i32>,
60
second: GuestPtr<i32>,
61
) -> Result<types::PairIntPtrs, types::Errno> {
62
Ok(types::PairIntPtrs { first, second })
63
}
64
65
fn sum_array(
66
&mut self,
67
memory: &mut GuestMemory<'_>,
68
record_of_list: &types::RecordOfList,
69
) -> Result<u16, types::Errno> {
70
// my kingdom for try blocks
71
fn aux(
72
memory: &mut GuestMemory<'_>,
73
record_of_list: &types::RecordOfList,
74
) -> Result<u16, wiggle::GuestError> {
75
let mut s = 0;
76
for elem in record_of_list.arr.iter() {
77
let v = memory.read(elem?)?;
78
s += v as u16;
79
}
80
Ok(s)
81
}
82
match aux(memory, record_of_list) {
83
Ok(s) => Ok(s),
84
Err(guest_err) => {
85
eprintln!("guest error summing array: {guest_err:?}");
86
Err(types::Errno::PicketLine)
87
}
88
}
89
}
90
}
91
92
#[derive(Debug)]
93
struct SumOfPairExercise {
94
pub input: types::PairInts,
95
pub input_loc: MemArea,
96
pub return_loc: MemArea,
97
}
98
99
impl SumOfPairExercise {
100
pub fn strat() -> BoxedStrategy<Self> {
101
(
102
prop::num::i32::ANY,
103
prop::num::i32::ANY,
104
HostMemory::mem_area_strat(8),
105
HostMemory::mem_area_strat(8),
106
)
107
.prop_map(|(first, second, input_loc, return_loc)| SumOfPairExercise {
108
input: types::PairInts { first, second },
109
input_loc,
110
return_loc,
111
})
112
.prop_filter("non-overlapping pointers", |e| {
113
MemArea::non_overlapping_set(&[e.input_loc, e.return_loc])
114
})
115
.boxed()
116
}
117
118
pub fn test(&self) {
119
let mut ctx = WasiCtx::new();
120
let mut host_memory = HostMemory::new();
121
let mut memory = host_memory.guest_memory();
122
123
memory
124
.write(GuestPtr::new(self.input_loc.ptr), self.input.first)
125
.expect("input ref_mut");
126
memory
127
.write(GuestPtr::new(self.input_loc.ptr + 4), self.input.second)
128
.expect("input ref_mut");
129
let sum_err = records::sum_of_pair(
130
&mut ctx,
131
&mut memory,
132
self.input_loc.ptr as i32,
133
self.return_loc.ptr as i32,
134
)
135
.unwrap();
136
137
assert_eq!(sum_err, types::Errno::Ok as i32, "sum errno");
138
139
let return_val: i64 = memory
140
.read(GuestPtr::new(self.return_loc.ptr))
141
.expect("return ref");
142
143
assert_eq!(
144
return_val,
145
self.input.first as i64 + self.input.second as i64,
146
"sum return value"
147
);
148
}
149
}
150
151
proptest! {
152
#[test]
153
fn sum_of_pair(e in SumOfPairExercise::strat()) {
154
e.test();
155
}
156
}
157
158
#[derive(Debug)]
159
struct SumPairPtrsExercise {
160
input_first: i32,
161
input_second: i32,
162
input_first_loc: MemArea,
163
input_second_loc: MemArea,
164
input_struct_loc: MemArea,
165
return_loc: MemArea,
166
}
167
168
impl SumPairPtrsExercise {
169
pub fn strat() -> BoxedStrategy<Self> {
170
(
171
prop::num::i32::ANY,
172
prop::num::i32::ANY,
173
HostMemory::mem_area_strat(4),
174
HostMemory::mem_area_strat(4),
175
HostMemory::mem_area_strat(8),
176
HostMemory::mem_area_strat(8),
177
)
178
.prop_map(
179
|(
180
input_first,
181
input_second,
182
input_first_loc,
183
input_second_loc,
184
input_struct_loc,
185
return_loc,
186
)| SumPairPtrsExercise {
187
input_first,
188
input_second,
189
input_first_loc,
190
input_second_loc,
191
input_struct_loc,
192
return_loc,
193
},
194
)
195
.prop_filter("non-overlapping pointers", |e| {
196
MemArea::non_overlapping_set(&[
197
e.input_first_loc,
198
e.input_second_loc,
199
e.input_struct_loc,
200
e.return_loc,
201
])
202
})
203
.boxed()
204
}
205
pub fn test(&self) {
206
let mut ctx = WasiCtx::new();
207
let mut host_memory = HostMemory::new();
208
let mut memory = host_memory.guest_memory();
209
210
memory
211
.write(GuestPtr::new(self.input_first_loc.ptr), self.input_first)
212
.expect("input_first ref");
213
memory
214
.write(GuestPtr::new(self.input_second_loc.ptr), self.input_second)
215
.expect("input_second ref");
216
217
memory
218
.write(
219
GuestPtr::new(self.input_struct_loc.ptr),
220
self.input_first_loc.ptr,
221
)
222
.expect("input_struct ref");
223
memory
224
.write(
225
GuestPtr::new(self.input_struct_loc.ptr + 4),
226
self.input_second_loc.ptr,
227
)
228
.expect("input_struct ref");
229
230
let res = records::sum_of_pair_of_ptrs(
231
&mut ctx,
232
&mut memory,
233
self.input_struct_loc.ptr as i32,
234
self.return_loc.ptr as i32,
235
)
236
.unwrap();
237
238
assert_eq!(res, types::Errno::Ok as i32, "sum of pair of ptrs errno");
239
240
let doubled: i64 = memory
241
.read(GuestPtr::new(self.return_loc.ptr))
242
.expect("return ref");
243
244
assert_eq!(
245
doubled,
246
(self.input_first as i64) + (self.input_second as i64),
247
"sum of pair of ptrs return val"
248
);
249
}
250
}
251
proptest! {
252
#[test]
253
fn sum_of_pair_of_ptrs(e in SumPairPtrsExercise::strat()) {
254
e.test()
255
}
256
}
257
258
#[derive(Debug)]
259
struct SumIntAndPtrExercise {
260
input_first: i32,
261
input_second: i32,
262
input_first_loc: MemArea,
263
input_struct_loc: MemArea,
264
return_loc: MemArea,
265
}
266
267
impl SumIntAndPtrExercise {
268
pub fn strat() -> BoxedStrategy<Self> {
269
(
270
prop::num::i32::ANY,
271
prop::num::i32::ANY,
272
HostMemory::mem_area_strat(4),
273
HostMemory::mem_area_strat(8),
274
HostMemory::mem_area_strat(8),
275
)
276
.prop_map(
277
|(input_first, input_second, input_first_loc, input_struct_loc, return_loc)| {
278
SumIntAndPtrExercise {
279
input_first,
280
input_second,
281
input_first_loc,
282
input_struct_loc,
283
return_loc,
284
}
285
},
286
)
287
.prop_filter("non-overlapping pointers", |e| {
288
MemArea::non_overlapping_set(&[e.input_first_loc, e.input_struct_loc, e.return_loc])
289
})
290
.boxed()
291
}
292
pub fn test(&self) {
293
let mut ctx = WasiCtx::new();
294
let mut host_memory = HostMemory::new();
295
let mut memory = host_memory.guest_memory();
296
297
memory
298
.write(GuestPtr::new(self.input_first_loc.ptr), self.input_first)
299
.expect("input_first ref");
300
memory
301
.write(
302
GuestPtr::new(self.input_struct_loc.ptr),
303
self.input_first_loc.ptr,
304
)
305
.expect("input_struct ref");
306
memory
307
.write(
308
GuestPtr::new(self.input_struct_loc.ptr + 4),
309
self.input_second,
310
)
311
.expect("input_struct ref");
312
313
let res = records::sum_of_int_and_ptr(
314
&mut ctx,
315
&mut memory,
316
self.input_struct_loc.ptr as i32,
317
self.return_loc.ptr as i32,
318
)
319
.unwrap();
320
321
assert_eq!(res, types::Errno::Ok as i32, "sum of int and ptr errno");
322
323
let doubled: i64 = memory
324
.read(GuestPtr::new(self.return_loc.ptr))
325
.expect("return ref");
326
327
assert_eq!(
328
doubled,
329
(self.input_first as i64) + (self.input_second as i64),
330
"sum of pair of ptrs return val"
331
);
332
}
333
}
334
proptest! {
335
#[test]
336
fn sum_of_int_and_ptr(e in SumIntAndPtrExercise::strat()) {
337
e.test()
338
}
339
}
340
341
#[derive(Debug)]
342
struct ReturnPairInts {
343
pub return_loc: MemArea,
344
}
345
346
impl ReturnPairInts {
347
pub fn strat() -> BoxedStrategy<Self> {
348
HostMemory::mem_area_strat(8)
349
.prop_map(|return_loc| ReturnPairInts { return_loc })
350
.boxed()
351
}
352
353
pub fn test(&self) {
354
let mut ctx = WasiCtx::new();
355
let mut host_memory = HostMemory::new();
356
let mut memory = host_memory.guest_memory();
357
358
let err =
359
records::return_pair_ints(&mut ctx, &mut memory, self.return_loc.ptr as i32).unwrap();
360
361
assert_eq!(err, types::Errno::Ok as i32, "return struct errno");
362
363
let return_struct: types::PairInts = memory
364
.read(GuestPtr::new(self.return_loc.ptr))
365
.expect("return ref");
366
367
assert_eq!(
368
return_struct,
369
types::PairInts {
370
first: 10,
371
second: 20
372
},
373
"return_pair_ints return value"
374
);
375
}
376
}
377
378
proptest! {
379
#[test]
380
fn return_pair_ints(e in ReturnPairInts::strat()) {
381
e.test();
382
}
383
}
384
385
#[derive(Debug)]
386
struct ReturnPairPtrsExercise {
387
input_first: i32,
388
input_second: i32,
389
input_first_loc: MemArea,
390
input_second_loc: MemArea,
391
return_loc: MemArea,
392
}
393
394
impl ReturnPairPtrsExercise {
395
pub fn strat() -> BoxedStrategy<Self> {
396
(
397
prop::num::i32::ANY,
398
prop::num::i32::ANY,
399
HostMemory::mem_area_strat(4),
400
HostMemory::mem_area_strat(4),
401
HostMemory::mem_area_strat(8),
402
)
403
.prop_map(
404
|(input_first, input_second, input_first_loc, input_second_loc, return_loc)| {
405
ReturnPairPtrsExercise {
406
input_first,
407
input_second,
408
input_first_loc,
409
input_second_loc,
410
return_loc,
411
}
412
},
413
)
414
.prop_filter("non-overlapping pointers", |e| {
415
MemArea::non_overlapping_set(&[e.input_first_loc, e.input_second_loc, e.return_loc])
416
})
417
.boxed()
418
}
419
pub fn test(&self) {
420
let mut ctx = WasiCtx::new();
421
let mut host_memory = HostMemory::new();
422
let mut memory = host_memory.guest_memory();
423
424
memory
425
.write(GuestPtr::new(self.input_first_loc.ptr), self.input_first)
426
.expect("input_first ref");
427
memory
428
.write(GuestPtr::new(self.input_second_loc.ptr), self.input_second)
429
.expect("input_second ref");
430
431
let res = records::return_pair_of_ptrs(
432
&mut ctx,
433
&mut memory,
434
self.input_first_loc.ptr as i32,
435
self.input_second_loc.ptr as i32,
436
self.return_loc.ptr as i32,
437
)
438
.unwrap();
439
440
assert_eq!(res, types::Errno::Ok as i32, "return pair of ptrs errno");
441
442
let ptr_pair_int_ptrs: types::PairIntPtrs = memory
443
.read(GuestPtr::new(self.return_loc.ptr))
444
.expect("failed to read return location");
445
let ret_first_ptr = ptr_pair_int_ptrs.first;
446
let ret_second_ptr = ptr_pair_int_ptrs.second;
447
assert_eq!(
448
self.input_first,
449
memory
450
.read(ret_first_ptr)
451
.expect("deref extracted ptr to first element")
452
);
453
assert_eq!(
454
self.input_second,
455
memory
456
.read(ret_second_ptr)
457
.expect("deref extracted ptr to second element")
458
);
459
}
460
}
461
proptest! {
462
#[test]
463
fn return_pair_of_ptrs(e in ReturnPairPtrsExercise::strat()) {
464
e.test()
465
}
466
}
467
468
#[derive(Debug)]
469
struct SumArrayExercise {
470
inputs: Vec<u8>,
471
input_array_loc: MemArea,
472
input_struct_loc: MemArea,
473
output_loc: MemArea,
474
}
475
476
impl SumArrayExercise {
477
pub fn strat() -> BoxedStrategy<Self> {
478
(0..256u32)
479
.prop_flat_map(|len| {
480
let len_usize = len as usize;
481
(
482
prop::collection::vec(prop::num::u8::ANY, len_usize..=len_usize),
483
HostMemory::mem_area_strat(8), // Input struct is 8 bytes - ptr and len
484
HostMemory::mem_area_strat(4), // Output is 4 bytes - stores a u16, but abi requires 4 byte alignment
485
)
486
})
487
.prop_filter(
488
"non-overlapping input struct and output pointers",
489
|(_inputs, input_struct_loc, output_loc)| {
490
MemArea::non_overlapping_set(&[*input_struct_loc, *output_loc])
491
},
492
)
493
.prop_flat_map(|(inputs, input_struct_loc, output_loc)| {
494
(
495
Just(inputs.clone()),
496
HostMemory::byte_slice_strat(
497
inputs.len() as u32,
498
1,
499
&MemAreas::from([input_struct_loc, output_loc]),
500
),
501
Just(input_struct_loc),
502
Just(output_loc),
503
)
504
})
505
.prop_map(
506
|(inputs, input_array_loc, input_struct_loc, output_loc)| SumArrayExercise {
507
inputs,
508
input_array_loc,
509
input_struct_loc,
510
output_loc,
511
},
512
)
513
.boxed()
514
}
515
pub fn test(&self) {
516
let mut ctx = WasiCtx::new();
517
let mut host_memory = HostMemory::new();
518
let mut memory = host_memory.guest_memory();
519
520
// Write inputs to memory as an array
521
for (ix, val) in self.inputs.iter().enumerate() {
522
let ix = ix as u32;
523
memory
524
.write(GuestPtr::new(self.input_array_loc.ptr + ix), *val)
525
.expect("write val to array memory");
526
}
527
528
// Write struct that contains the array
529
memory
530
.write(
531
GuestPtr::new(self.input_struct_loc.ptr),
532
self.input_array_loc.ptr,
533
)
534
.expect("write ptr to struct memory");
535
memory
536
.write(
537
GuestPtr::new(self.input_struct_loc.ptr + 4),
538
self.inputs.len() as u32,
539
)
540
.expect("write len to struct memory");
541
542
// Call wiggle-generated func
543
let res = records::sum_array(
544
&mut ctx,
545
&mut memory,
546
self.input_struct_loc.ptr as i32,
547
self.output_loc.ptr as i32,
548
)
549
.unwrap();
550
551
// should be no error - if hostcall did a GuestError it should eprintln it.
552
assert_eq!(res, types::Errno::Ok as i32, "reduce excuses errno");
553
554
// Sum is inputs upcasted to u16
555
let expected: u16 = self.inputs.iter().map(|v| *v as u16).sum();
556
557
// Wiggle stored output value in memory as u16
558
let given: u16 = memory
559
.read(GuestPtr::new(self.output_loc.ptr))
560
.expect("deref ptr to returned value");
561
562
// Assert the two calculations match
563
assert_eq!(expected, given, "sum_array return val");
564
}
565
}
566
proptest! {
567
#[test]
568
fn sum_of_array(e in SumArrayExercise::strat()) {
569
e.test()
570
}
571
}
572
573
#[test]
574
fn pair_ints_offsets() {
575
assert_eq!(types::PairInts::offset_of_first(), 0);
576
assert_eq!(types::PairInts::offset_of_second(), 4);
577
}
578
579
#[test]
580
fn pair_different_ints_offsets() {
581
assert_eq!(types::PairDifferentInts::offset_of_first(), 0);
582
assert_eq!(types::PairDifferentInts::offset_of_second(), 8);
583
assert_eq!(types::PairDifferentInts::offset_of_third(), 10);
584
assert_eq!(types::PairDifferentInts::offset_of_fourth(), 12);
585
}
586
587
#[test]
588
fn pair_int_ptrs_offsets() {
589
assert_eq!(types::PairIntPtrs::offset_of_first(), 0);
590
assert_eq!(types::PairIntPtrs::offset_of_second(), 4);
591
}
592
593
#[test]
594
fn pair_int_and_ptr_offsets() {
595
assert_eq!(types::PairIntAndPtr::offset_of_first(), 0);
596
assert_eq!(types::PairIntAndPtr::offset_of_second(), 4);
597
}
598
599
#[test]
600
fn pair_record_of_list_offset() {
601
assert_eq!(types::RecordOfList::offset_of_arr(), 0);
602
}
603
604