Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/crates/fuzzing/tests/oom.rs
3068 views
1
use cranelift_bitset::CompoundBitSet;
2
use std::{
3
alloc::{Layout, alloc},
4
fmt::{self, Write},
5
iter,
6
sync::atomic::{AtomicU32, Ordering::SeqCst},
7
};
8
use wasmtime::{error::OutOfMemory, *};
9
use wasmtime_core::alloc::TryCollect;
10
use wasmtime_environ::{PrimaryMap, SecondaryMap, collections::*};
11
use wasmtime_fuzzing::oom::{OomTest, OomTestAllocator};
12
13
#[global_allocator]
14
static GLOBAL_ALOCATOR: OomTestAllocator = OomTestAllocator::new();
15
16
#[test]
17
fn smoke_test_ok() -> Result<()> {
18
OomTest::new().test(|| Ok(()))
19
}
20
21
#[test]
22
fn smoke_test_missed_oom() -> Result<()> {
23
let err = OomTest::new()
24
.test(|| {
25
let _ = unsafe { alloc(Layout::new::<u64>()) };
26
Ok(())
27
})
28
.unwrap_err();
29
let err = format!("{err:?}");
30
assert!(
31
err.contains("OOM test function missed an OOM"),
32
"should have missed an OOM, got: {err}"
33
);
34
Ok(())
35
}
36
37
#[test]
38
#[cfg(arc_try_new)]
39
fn try_new_arc() -> Result<()> {
40
use std::sync::Arc;
41
42
OomTest::new().test(|| {
43
let _arc = try_new::<Arc<u32>>(42)?;
44
Ok(())
45
})
46
}
47
48
#[test]
49
fn try_new_box() -> Result<()> {
50
OomTest::new().test(|| {
51
let _box = try_new::<Box<u32>>(36)?;
52
Ok(())
53
})
54
}
55
56
#[test]
57
fn compound_bit_set_try_with_capacity() -> Result<()> {
58
OomTest::new().test(|| {
59
let _bitset = CompoundBitSet::<usize>::try_with_capacity(32)?;
60
Ok(())
61
})
62
}
63
64
#[test]
65
fn compound_bit_set_try_ensure_capacity() -> Result<()> {
66
OomTest::new().test(|| {
67
let mut bitset = CompoundBitSet::new();
68
bitset.try_ensure_capacity(100)?;
69
Ok(())
70
})
71
}
72
73
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
74
struct Key(u32);
75
wasmtime_environ::entity_impl!(Key);
76
77
#[test]
78
fn primary_map_try_with_capacity() -> Result<()> {
79
OomTest::new().test(|| {
80
let _map = PrimaryMap::<Key, u32>::try_with_capacity(32)?;
81
Ok(())
82
})
83
}
84
85
#[test]
86
fn primary_map_try_reserve() -> Result<()> {
87
OomTest::new().test(|| {
88
let mut map = PrimaryMap::<Key, u32>::new();
89
map.try_reserve(100)?;
90
Ok(())
91
})
92
}
93
94
#[test]
95
fn primary_map_try_reserve_exact() -> Result<()> {
96
OomTest::new().test(|| {
97
let mut map = PrimaryMap::<Key, u32>::new();
98
map.try_reserve_exact(13)?;
99
Ok(())
100
})
101
}
102
103
#[test]
104
fn secondary_map_try_with_capacity() -> Result<()> {
105
OomTest::new().test(|| {
106
let _map = SecondaryMap::<Key, u32>::try_with_capacity(32)?;
107
Ok(())
108
})
109
}
110
111
#[test]
112
fn secondary_map_try_resize() -> Result<()> {
113
OomTest::new().test(|| {
114
let mut map = SecondaryMap::<Key, u32>::new();
115
map.try_resize(100)?;
116
Ok(())
117
})
118
}
119
120
#[test]
121
fn secondary_map_try_insert() -> Result<()> {
122
OomTest::new().test(|| {
123
let mut map = SecondaryMap::<Key, u32>::new();
124
map.try_insert(Key::from_u32(42), 100)?;
125
Ok(())
126
})
127
}
128
129
#[test]
130
fn entity_set_ensure_capacity() -> Result<()> {
131
OomTest::new().test(|| {
132
let mut set = EntitySet::<Key>::new();
133
set.ensure_capacity(100)?;
134
Ok(())
135
})
136
}
137
138
#[test]
139
fn entity_set_insert() -> Result<()> {
140
OomTest::new().test(|| {
141
let mut set = EntitySet::<Key>::new();
142
set.insert(Key::from_u32(256))?;
143
Ok(())
144
})
145
}
146
147
#[test]
148
fn hash_set_with_capacity() -> Result<()> {
149
OomTest::new().test(|| {
150
let _s = HashSet::<usize>::with_capacity(100)?;
151
Ok(())
152
})
153
}
154
155
#[test]
156
fn hash_set_reserve() -> Result<()> {
157
OomTest::new().test(|| {
158
let mut set = HashSet::<usize>::new();
159
set.reserve(100)?;
160
Ok(())
161
})
162
}
163
164
#[test]
165
fn hash_set_insert() -> Result<()> {
166
OomTest::new().test(|| {
167
let mut set = HashSet::<usize>::new();
168
for i in 0..1024 {
169
set.insert(i)?;
170
}
171
for i in 0..1024 {
172
set.insert(i)?;
173
}
174
Ok(())
175
})
176
}
177
178
#[test]
179
fn hash_map_with_capacity() -> Result<()> {
180
OomTest::new().test(|| {
181
let _s = HashMap::<usize, usize>::with_capacity(100)?;
182
Ok(())
183
})
184
}
185
186
#[test]
187
fn hash_map_reserve() -> Result<()> {
188
OomTest::new().test(|| {
189
let mut map = HashMap::<usize, usize>::new();
190
map.reserve(100)?;
191
Ok(())
192
})
193
}
194
195
#[test]
196
fn hash_map_insert() -> Result<()> {
197
OomTest::new().test(|| {
198
let mut map = HashMap::<usize, usize>::new();
199
for i in 0..1024 {
200
map.insert(i, i * 2)?;
201
}
202
for i in 0..1024 {
203
map.insert(i, i * 2)?;
204
}
205
Ok(())
206
})
207
}
208
209
#[test]
210
fn hash_map_try_clone() -> Result<()> {
211
OomTest::new().test(|| {
212
let mut map = HashMap::new();
213
for i in 0..10 {
214
map.insert(i, i * 2)?;
215
}
216
let map2 = map.try_clone()?;
217
assert_eq!(map, map2);
218
Ok(())
219
})
220
}
221
222
#[test]
223
fn vec_with_capacity() -> Result<()> {
224
OomTest::new().test(|| {
225
let _v = wasmtime_environ::collections::Vec::<usize>::with_capacity(100)?;
226
Ok(())
227
})
228
}
229
230
#[test]
231
fn vec_reserve() -> Result<()> {
232
OomTest::new().test(|| {
233
let mut v = wasmtime_environ::collections::Vec::<usize>::new();
234
v.reserve(10)?;
235
Ok(())
236
})
237
}
238
239
#[test]
240
fn vec_reserve_exact() -> Result<()> {
241
OomTest::new().test(|| {
242
let mut v = wasmtime_environ::collections::Vec::<usize>::new();
243
v.reserve_exact(3)?;
244
Ok(())
245
})
246
}
247
248
#[test]
249
fn vec_push() -> Result<()> {
250
OomTest::new().test(|| {
251
let mut v = wasmtime_environ::collections::Vec::new();
252
v.push(42)?;
253
Ok(())
254
})
255
}
256
257
#[test]
258
fn string_with_capacity() -> Result<()> {
259
OomTest::new().test(|| {
260
let _s = String::with_capacity(100)?;
261
Ok(())
262
})
263
}
264
265
#[test]
266
fn string_reserve() -> Result<()> {
267
OomTest::new().test(|| {
268
let mut s = String::new();
269
s.reserve(10)?;
270
Ok(())
271
})
272
}
273
274
#[test]
275
fn string_reserve_exact() -> Result<()> {
276
OomTest::new().test(|| {
277
let mut s = String::new();
278
s.reserve_exact(3)?;
279
Ok(())
280
})
281
}
282
283
#[test]
284
fn string_push() -> Result<()> {
285
OomTest::new().test(|| {
286
let mut s = String::new();
287
s.push('c')?;
288
Ok(())
289
})
290
}
291
292
#[test]
293
fn string_push_str() -> Result<()> {
294
OomTest::new().test(|| {
295
let mut s = String::new();
296
s.push_str("hello")?;
297
Ok(())
298
})
299
}
300
301
#[test]
302
fn string_shrink_to_fit() -> Result<()> {
303
OomTest::new().test(|| {
304
// len == cap == 0
305
let mut s = String::new();
306
s.shrink_to_fit()?;
307
308
// len == 0 < cap
309
let mut s = String::with_capacity(4)?;
310
s.shrink_to_fit()?;
311
312
// 0 < len < cap
313
let mut s = String::with_capacity(4)?;
314
s.push('a')?;
315
s.shrink_to_fit()?;
316
317
// 0 < len == cap
318
let mut s = String::new();
319
s.reserve_exact(2)?;
320
s.push('a')?;
321
s.push('a')?;
322
s.shrink_to_fit()?;
323
324
Ok(())
325
})
326
}
327
328
#[test]
329
fn string_into_boxed_str() -> Result<()> {
330
OomTest::new().test(|| {
331
// len == cap == 0
332
let s = String::new();
333
let _ = s.into_boxed_str()?;
334
335
// len == 0 < cap
336
let s = String::with_capacity(4)?;
337
let _ = s.into_boxed_str()?;
338
339
// 0 < len < cap
340
let mut s = String::with_capacity(4)?;
341
s.push('a')?;
342
let _ = s.into_boxed_str()?;
343
344
// 0 < len == cap
345
let mut s = String::new();
346
s.reserve_exact(2)?;
347
s.push('a')?;
348
s.push('a')?;
349
let _ = s.into_boxed_str()?;
350
351
Ok(())
352
})
353
}
354
355
#[test]
356
fn config_new() -> Result<()> {
357
OomTest::new().test(|| {
358
let mut config = Config::new();
359
config.enable_compiler(false);
360
Ok(())
361
})
362
}
363
364
#[test]
365
#[cfg(arc_try_new)]
366
fn engine_new() -> Result<()> {
367
OomTest::new().test(|| {
368
let mut config = Config::new();
369
config.enable_compiler(false);
370
let _ = Engine::new(&config)?;
371
Ok(())
372
})
373
}
374
375
#[test]
376
#[cfg(arc_try_new)]
377
fn func_type_try_new() -> Result<()> {
378
let mut config = Config::new();
379
config.enable_compiler(false);
380
let engine = Engine::new(&config)?;
381
382
// Run this OOM test a few times to make sure that we leave the engine's
383
// type registry in a good state when failing to register new types.
384
for i in 1..6 {
385
OomTest::new().test(|| {
386
let ty1 = FuncType::try_new(
387
&engine,
388
std::iter::repeat(ValType::ANYREF).take(i),
389
std::iter::repeat(ValType::ANYREF).take(i),
390
)?;
391
assert_eq!(ty1.params().len(), i);
392
assert_eq!(ty1.results().len(), i);
393
394
let ty2 = FuncType::try_new(
395
&engine,
396
std::iter::repeat(ValType::ANYREF).take(i),
397
std::iter::repeat(ValType::ANYREF).take(i),
398
)?;
399
assert_eq!(ty2.params().len(), i);
400
assert_eq!(ty2.results().len(), i);
401
402
let ty3 = FuncType::try_new(&engine, [], [])?;
403
assert_eq!(ty3.params().len(), 0);
404
assert_eq!(ty3.results().len(), 0);
405
406
assert!(
407
!FuncType::eq(&ty2, &ty3),
408
"{ty2:?} should not be equal to {ty3:?}"
409
);
410
411
Ok(())
412
})?;
413
}
414
415
Ok(())
416
}
417
418
#[test]
419
#[cfg(arc_try_new)]
420
fn linker_new() -> Result<()> {
421
OomTest::new().test(|| {
422
let mut config = Config::new();
423
config.enable_compiler(false);
424
let engine = Engine::new(&config)?;
425
let _linker = Linker::<()>::new(&engine);
426
Ok(())
427
})
428
}
429
430
#[test]
431
#[cfg(arc_try_new)]
432
fn linker_func_wrap() -> Result<()> {
433
OomTest::new().test(|| {
434
let mut config = Config::new();
435
config.enable_compiler(false);
436
let engine = Engine::new(&config)?;
437
let mut linker = Linker::<()>::new(&engine);
438
linker.func_wrap("module", "func", |x: i32| x * 2)?;
439
Ok(())
440
})
441
}
442
443
#[test]
444
#[cfg(arc_try_new)]
445
fn store_try_new() -> Result<()> {
446
let mut config = Config::new();
447
config.enable_compiler(false);
448
config.concurrency_support(false);
449
let engine = Engine::new(&config)?;
450
OomTest::new().test(|| {
451
let _ = Store::try_new(&engine, ())?;
452
Ok(())
453
})
454
}
455
456
fn ok_if_not_oom(error: Error) -> Result<()> {
457
if error.is::<OutOfMemory>() {
458
Err(error)
459
} else {
460
Ok(())
461
}
462
}
463
464
#[test]
465
fn error_new() -> Result<()> {
466
OomTest::new().test(|| {
467
let error = Error::new(u8::try_from(u32::MAX).unwrap_err());
468
ok_if_not_oom(error)
469
})
470
}
471
472
#[test]
473
fn error_msg() -> Result<()> {
474
OomTest::new().test(|| {
475
let error = Error::msg("ouch");
476
ok_if_not_oom(error)
477
})
478
}
479
480
static X: AtomicU32 = AtomicU32::new(42);
481
482
#[test]
483
fn error_fmt() -> Result<()> {
484
OomTest::new().test(|| {
485
let x = X.load(SeqCst);
486
let error = format_err!("ouch: {x}");
487
ok_if_not_oom(error)
488
})
489
}
490
491
#[test]
492
fn error_context() -> Result<()> {
493
OomTest::new().test(|| {
494
let error = Error::msg("hello");
495
let error = error.context("goodbye");
496
ok_if_not_oom(error)
497
})
498
}
499
500
#[test]
501
fn error_chain() -> Result<()> {
502
OomTest::new().test(|| {
503
let error = Error::msg("hello");
504
let error = error.context("goodbye");
505
for _ in error.chain() {
506
// Nothing to do here, just exercising the iteration.
507
}
508
ok_if_not_oom(error)
509
})
510
}
511
512
struct Null;
513
impl Write for Null {
514
fn write_str(&mut self, _s: &str) -> fmt::Result {
515
Ok(())
516
}
517
}
518
519
#[test]
520
fn display_fmt_error() -> Result<()> {
521
OomTest::new().test(|| {
522
let error = Error::msg("hello");
523
let error = error.context("goodbye");
524
write!(&mut Null, "{error}").unwrap();
525
ok_if_not_oom(error)
526
})
527
}
528
529
#[test]
530
fn alternate_display_fmt_error() -> Result<()> {
531
OomTest::new().test(|| {
532
let error = Error::msg("hello");
533
let error = error.context("goodbye");
534
write!(&mut Null, "{error:?}").unwrap();
535
ok_if_not_oom(error)
536
})
537
}
538
539
#[test]
540
fn debug_fmt_error() -> Result<()> {
541
OomTest::new().test(|| {
542
let error = Error::msg("hello");
543
let error = error.context("goodbye");
544
write!(&mut Null, "{error:?}").unwrap();
545
ok_if_not_oom(error)
546
})
547
}
548
549
#[test]
550
fn alternate_debug_fmt_error() -> Result<()> {
551
OomTest::new().test(|| {
552
let error = Error::msg("hello");
553
let error = error.context("goodbye");
554
write!(&mut Null, "{error:#?}").unwrap();
555
ok_if_not_oom(error)
556
})
557
}
558
559
#[test]
560
fn vec_and_boxed_slice() -> Result<()> {
561
use wasmtime_core::alloc::Vec;
562
563
OomTest::new().test(|| {
564
// Nonzero-sized type.
565
let mut vec = Vec::new();
566
vec.push(1)?;
567
let slice = vec.into_boxed_slice()?; // len > 0, cap > 0
568
569
let mut vec = Vec::from(slice);
570
vec.pop();
571
let slice = vec.into_boxed_slice()?; // len = 0, cap > 0
572
573
let vec = Vec::from(slice);
574
let _slice = vec.into_boxed_slice()?; // len = 0, cap = 0
575
576
let mut vec = Vec::new();
577
vec.reserve_exact(3)?;
578
vec.push(2)?;
579
vec.push(2)?;
580
vec.push(2)?;
581
let _slice = vec.into_boxed_slice()?; // len = cap, len > 0
582
583
for i in 0..12 {
584
let mut vec = Vec::new();
585
for j in 0..i {
586
vec.push(j)?;
587
}
588
let _slice = vec.into_boxed_slice()?; // len ?= cap
589
}
590
591
// Zero-sized type.
592
let mut vec = Vec::new();
593
vec.push(())?;
594
let slice = vec.into_boxed_slice()?; // len > 0, cap > 0
595
let mut vec = Vec::from(slice);
596
vec.pop();
597
let slice = vec.into_boxed_slice()?; // len = 0, cap > 0
598
let vec = Vec::from(slice);
599
let _ = vec.into_boxed_slice()?; // len = 0, cap = 0
600
601
Ok(())
602
})
603
}
604
605
#[test]
606
fn vec_shrink_to_fit() -> Result<()> {
607
use wasmtime_core::alloc::Vec;
608
609
#[derive(Default)]
610
struct ZeroSized;
611
612
#[derive(Default)]
613
struct NonZeroSized {
614
_unused: usize,
615
}
616
617
fn do_test<T: Default>() -> Result<()> {
618
// len == cap == 0
619
let mut v = Vec::<T>::new();
620
v.shrink_to_fit()?;
621
622
// len == 0 < cap
623
let mut v = Vec::<T>::with_capacity(4)?;
624
v.shrink_to_fit()?;
625
626
// 0 < len < cap
627
let mut v = Vec::with_capacity(4)?;
628
v.push(T::default())?;
629
v.shrink_to_fit()?;
630
631
// 0 < len == cap
632
let mut v = Vec::new();
633
v.reserve_exact(2)?;
634
v.push(T::default())?;
635
v.push(T::default())?;
636
v.shrink_to_fit()?;
637
638
Ok(())
639
}
640
641
OomTest::new().test(|| do_test::<ZeroSized>())?;
642
OomTest::new().test(|| do_test::<NonZeroSized>())?;
643
Ok(())
644
}
645
646
#[test]
647
fn vec_try_collect() -> Result<()> {
648
OomTest::new().test(|| {
649
iter::repeat(1).take(0).try_collect::<Vec<_>, _>()?;
650
iter::repeat(1).take(1).try_collect::<Vec<_>, _>()?;
651
iter::repeat(1).take(100).try_collect::<Vec<_>, _>()?;
652
iter::repeat(()).take(100).try_collect::<Vec<_>, _>()?;
653
Ok(())
654
})
655
}
656
657
#[test]
658
fn vec_extend() -> Result<()> {
659
use wasmtime_core::alloc::{TryExtend, Vec};
660
OomTest::new().test(|| {
661
let mut vec = Vec::new();
662
vec.try_extend([])?;
663
vec.try_extend([1])?;
664
vec.try_extend([1, 2, 3, 4])?;
665
666
let mut vec = Vec::new();
667
vec.try_extend([])?;
668
vec.try_extend([()])?;
669
vec.try_extend([(), (), ()])?;
670
Ok(())
671
})
672
}
673
674