Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/wiggle/tests/strings.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/strings.witx"],
7
});
8
9
impl_errno!(types::Errno);
10
11
impl<'a> strings::Strings for WasiCtx<'a> {
12
fn hello_string(
13
&mut self,
14
memory: &mut GuestMemory<'_>,
15
a_string: GuestPtr<str>,
16
) -> Result<u32, types::Errno> {
17
let s = memory
18
.as_str(a_string)
19
.expect("should be valid string")
20
.expect("expected non-shared memory");
21
println!("a_string='{}'", &*s);
22
Ok(s.len() as u32)
23
}
24
25
fn multi_string(
26
&mut self,
27
memory: &mut GuestMemory<'_>,
28
a: GuestPtr<str>,
29
b: GuestPtr<str>,
30
c: GuestPtr<str>,
31
) -> Result<u32, types::Errno> {
32
let sa = memory
33
.as_str(a)
34
.expect("A should be valid string")
35
.expect("expected non-shared memory");
36
let sb = memory
37
.as_str(b)
38
.expect("B should be valid string")
39
.expect("expected non-shared memory");
40
let sc = memory
41
.as_str(c)
42
.expect("C should be valid string")
43
.expect("expected non-shared memory");
44
let total_len = sa.len() + sb.len() + sc.len();
45
println!(
46
"len={}, a='{}', b='{}', c='{}'",
47
total_len, &*sa, &*sb, &*sc
48
);
49
Ok(total_len as u32)
50
}
51
}
52
53
fn unicode_string_strategy() -> impl Strategy<Value = String> {
54
"\\p{Greek}{1,256}"
55
}
56
fn ascii_string_strategy() -> impl Strategy<Value = String> {
57
"[a-zA-Z0..9]{1,256}"
58
}
59
60
#[derive(Debug)]
61
struct HelloStringExercise {
62
test_word: String,
63
string_ptr_loc: MemArea,
64
return_ptr_loc: MemArea,
65
}
66
67
impl HelloStringExercise {
68
pub fn strat() -> BoxedStrategy<Self> {
69
(unicode_string_strategy(),)
70
.prop_flat_map(|(test_word,)| {
71
(
72
Just(test_word.clone()),
73
HostMemory::mem_area_strat(test_word.len() as u32),
74
HostMemory::mem_area_strat(4),
75
)
76
})
77
.prop_map(|(test_word, string_ptr_loc, return_ptr_loc)| Self {
78
test_word,
79
string_ptr_loc,
80
return_ptr_loc,
81
})
82
.prop_filter("non-overlapping pointers", |e| {
83
MemArea::non_overlapping_set(&[e.string_ptr_loc, e.return_ptr_loc])
84
})
85
.boxed()
86
}
87
88
pub fn test(&self) {
89
let mut ctx = WasiCtx::new();
90
let mut host_memory = HostMemory::new();
91
let mut memory = host_memory.guest_memory();
92
93
// Populate string in guest's memory
94
let ptr = GuestPtr::<str>::new((self.string_ptr_loc.ptr, self.test_word.len() as u32));
95
for (slot, byte) in ptr.as_bytes().iter().zip(self.test_word.bytes()) {
96
memory
97
.write(slot.expect("should be valid pointer"), byte)
98
.expect("failed to write");
99
}
100
101
let res = strings::hello_string(
102
&mut ctx,
103
&mut memory,
104
self.string_ptr_loc.ptr as i32,
105
self.test_word.len() as i32,
106
self.return_ptr_loc.ptr as i32,
107
)
108
.unwrap();
109
assert_eq!(res, types::Errno::Ok as i32, "hello string errno");
110
111
let given = memory
112
.read(GuestPtr::<u32>::new(self.return_ptr_loc.ptr))
113
.expect("deref ptr to return value");
114
assert_eq!(self.test_word.len() as u32, given);
115
}
116
}
117
proptest! {
118
#[test]
119
fn hello_string(e in HelloStringExercise::strat()) {
120
e.test()
121
}
122
}
123
124
#[derive(Debug)]
125
struct MultiStringExercise {
126
a: String,
127
b: String,
128
c: String,
129
sa_ptr_loc: MemArea,
130
sb_ptr_loc: MemArea,
131
sc_ptr_loc: MemArea,
132
return_ptr_loc: MemArea,
133
}
134
135
impl MultiStringExercise {
136
pub fn strat() -> BoxedStrategy<Self> {
137
(
138
unicode_string_strategy(),
139
unicode_string_strategy(),
140
unicode_string_strategy(),
141
HostMemory::mem_area_strat(4),
142
)
143
.prop_flat_map(|(a, b, c, return_ptr_loc)| {
144
(
145
Just(a.clone()),
146
Just(b.clone()),
147
Just(c.clone()),
148
HostMemory::byte_slice_strat(
149
a.len() as u32,
150
1,
151
&MemAreas::from([return_ptr_loc]),
152
),
153
Just(return_ptr_loc),
154
)
155
})
156
.prop_flat_map(|(a, b, c, sa_ptr_loc, return_ptr_loc)| {
157
(
158
Just(a.clone()),
159
Just(b.clone()),
160
Just(c.clone()),
161
Just(sa_ptr_loc),
162
HostMemory::byte_slice_strat(
163
b.len() as u32,
164
1,
165
&MemAreas::from([sa_ptr_loc, return_ptr_loc]),
166
),
167
Just(return_ptr_loc),
168
)
169
})
170
.prop_flat_map(|(a, b, c, sa_ptr_loc, sb_ptr_loc, return_ptr_loc)| {
171
(
172
Just(a.clone()),
173
Just(b.clone()),
174
Just(c.clone()),
175
Just(sa_ptr_loc),
176
Just(sb_ptr_loc),
177
HostMemory::byte_slice_strat(
178
c.len() as u32,
179
1,
180
&MemAreas::from([sa_ptr_loc, sb_ptr_loc, return_ptr_loc]),
181
),
182
Just(return_ptr_loc),
183
)
184
})
185
.prop_map(
186
|(a, b, c, sa_ptr_loc, sb_ptr_loc, sc_ptr_loc, return_ptr_loc)| {
187
MultiStringExercise {
188
a,
189
b,
190
c,
191
sa_ptr_loc,
192
sb_ptr_loc,
193
sc_ptr_loc,
194
return_ptr_loc,
195
}
196
},
197
)
198
.boxed()
199
}
200
201
pub fn test(&self) {
202
let mut ctx = WasiCtx::new();
203
let mut host_memory = HostMemory::new();
204
let mut memory = host_memory.guest_memory();
205
206
let mut write_string = |val: &str, loc: MemArea| {
207
let ptr = GuestPtr::<str>::new((loc.ptr, val.len() as u32));
208
for (slot, byte) in ptr.as_bytes().iter().zip(val.bytes()) {
209
memory
210
.write(slot.expect("should be valid pointer"), byte)
211
.expect("failed to write");
212
}
213
};
214
215
write_string(&self.a, self.sa_ptr_loc);
216
write_string(&self.b, self.sb_ptr_loc);
217
write_string(&self.c, self.sc_ptr_loc);
218
219
let res = strings::multi_string(
220
&mut ctx,
221
&mut memory,
222
self.sa_ptr_loc.ptr as i32,
223
self.a.len() as i32,
224
self.sb_ptr_loc.ptr as i32,
225
self.b.len() as i32,
226
self.sc_ptr_loc.ptr as i32,
227
self.c.len() as i32,
228
self.return_ptr_loc.ptr as i32,
229
)
230
.unwrap();
231
assert_eq!(res, types::Errno::Ok as i32, "multi string errno");
232
233
let given = memory
234
.read(GuestPtr::<u32>::new(self.return_ptr_loc.ptr))
235
.expect("deref ptr to return value");
236
assert_eq!((self.a.len() + self.b.len() + self.c.len()) as u32, given);
237
}
238
}
239
proptest! {
240
#[test]
241
fn multi_string(e in MultiStringExercise::strat()) {
242
e.test()
243
}
244
}
245
246
#[derive(Debug)]
247
struct OverlappingStringExercise {
248
a: String,
249
sa_ptr_loc: MemArea,
250
offset_b: u32,
251
offset_c: u32,
252
return_ptr_loc: MemArea,
253
}
254
255
impl OverlappingStringExercise {
256
pub fn strat() -> BoxedStrategy<Self> {
257
// using ascii so we can window into it without worrying about codepoints
258
(ascii_string_strategy(), HostMemory::mem_area_strat(4))
259
.prop_flat_map(|(a, return_ptr_loc)| {
260
(
261
Just(a.clone()),
262
HostMemory::mem_area_strat(a.len() as u32),
263
0..(a.len() as u32),
264
0..(a.len() as u32),
265
Just(return_ptr_loc),
266
)
267
})
268
.prop_map(|(a, sa_ptr_loc, offset_b, offset_c, return_ptr_loc)| Self {
269
a,
270
sa_ptr_loc,
271
offset_b,
272
offset_c,
273
return_ptr_loc,
274
})
275
.prop_filter("non-overlapping pointers", |e| {
276
MemArea::non_overlapping_set(&[e.sa_ptr_loc, e.return_ptr_loc])
277
})
278
.boxed()
279
}
280
281
pub fn test(&self) {
282
let mut ctx = WasiCtx::new();
283
let mut host_memory = HostMemory::new();
284
let mut memory = host_memory.guest_memory();
285
286
let mut write_string = |val: &str, loc: MemArea| {
287
let ptr = GuestPtr::<str>::new((loc.ptr, val.len() as u32));
288
for (slot, byte) in ptr.as_bytes().iter().zip(val.bytes()) {
289
memory
290
.write(slot.expect("should be valid pointer"), byte)
291
.expect("failed to write");
292
}
293
};
294
295
write_string(&self.a, self.sa_ptr_loc);
296
297
let a_len = self.a.as_bytes().len() as i32;
298
let res = strings::multi_string(
299
&mut ctx,
300
&mut memory,
301
self.sa_ptr_loc.ptr as i32,
302
a_len,
303
(self.sa_ptr_loc.ptr + self.offset_b) as i32,
304
a_len - self.offset_b as i32,
305
(self.sa_ptr_loc.ptr + self.offset_c) as i32,
306
a_len - self.offset_c as i32,
307
self.return_ptr_loc.ptr as i32,
308
)
309
.unwrap();
310
assert_eq!(res, types::Errno::Ok as i32, "multi string errno");
311
312
let given = memory
313
.read(GuestPtr::<u32>::new(self.return_ptr_loc.ptr))
314
.expect("deref ptr to return value");
315
assert_eq!(
316
((3 * a_len) - (self.offset_b as i32 + self.offset_c as i32)) as u32,
317
given
318
);
319
}
320
}
321
322
proptest! {
323
#[test]
324
fn overlapping_string(e in OverlappingStringExercise::strat()) {
325
e.test()
326
}
327
}
328
329