From 11f63e83c536806dfe0ad32789bf3a8caa7ffe37 Mon Sep 17 00:00:00 2001 From: arvidn Date: Tue, 13 Feb 2024 12:07:00 +0100 Subject: [PATCH] add fuzzer for Allocator, specifically handling of atom, small_number and number --- fuzz/Cargo.toml | 6 ++++ fuzz/fuzz_targets/allocator.rs | 54 ++++++++++++++++++++++++++++++++++ src/allocator.rs | 4 ++- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 fuzz/fuzz_targets/allocator.rs diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 87480146..5eca6b99 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -68,3 +68,9 @@ name = "operators" path = "fuzz_targets/operators.rs" test = false doc = false + +[[bin]] +name = "allocator" +path = "fuzz_targets/allocator.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/allocator.rs b/fuzz/fuzz_targets/allocator.rs new file mode 100644 index 00000000..6c23b88c --- /dev/null +++ b/fuzz/fuzz_targets/allocator.rs @@ -0,0 +1,54 @@ +#![no_main] +use libfuzzer_sys::fuzz_target; + +use clvmr::{Allocator, NodePtr}; + +fn run_tests(a: &mut Allocator, atom1: NodePtr, data: &[u8]) { + assert_eq!(a.atom(atom1).as_ref(), data); + assert_eq!(a.atom_len(atom1), data.len()); + + let canonical = data != [0] + && (data.len() < 2 || data[0] != 0 || (data[1] & 0x80) != 0) + && (data.len() < 2 || data[0] != 0xff || (data[1] & 0x80) == 0); + + // small_number + if let Some(val) = a.small_number(atom1) { + let atom2 = a.new_small_number(val).expect("new_small_number()"); + assert_eq!(a.atom(atom1), a.atom(atom2)); + assert_eq!(a.atom(atom2).as_ref(), data); + assert!(a.atom_eq(atom1, atom2)); + assert_eq!(a.number(atom1), val.into()); + assert_eq!(a.number(atom2), val.into()); + assert_eq!(a.atom_len(atom2), data.len()); + assert!(canonical); + } + + // number + let val = a.number(atom1); + + let atom3 = a.new_number(val.clone()).expect("new_number()"); + + assert_eq!(a.number(atom3), val); + // if the atom is not in canonical integer form we don't expect it to stay + // the same once we "launder" it through a BigInt. + if !canonical { + assert!(a.atom(atom3).as_ref() != data); + assert!(a.atom_len(atom3) < data.len()); + assert!(!a.atom_eq(atom1, atom3)); + } else { + assert_eq!(a.atom(atom3).as_ref(), data); + assert_eq!(a.atom_len(atom3), data.len()); + assert!(a.atom_eq(atom1, atom3)); + } +} + +fuzz_target!(|data: &[u8]| { + let mut a = Allocator::new(); + let atom1 = a.new_atom(data).expect("new_atom()"); + run_tests(&mut a, atom1, data); + + let atom1 = a + .new_concat(data.len(), &[a.nil(), atom1, a.nil()]) + .expect("new_concat()"); + run_tests(&mut a, atom1, data); +}); diff --git a/src/allocator.rs b/src/allocator.rs index 7f722cb4..92fc610e 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1082,7 +1082,9 @@ fn test_concat_launder_small_number() { // this "launders" the small number into actually being allocated on the // heap - let atom2 = a.new_concat(1, &[atom1]).expect("new_substr"); + let atom2 = a + .new_concat(1, &[a.nil(), atom1, a.nil()]) + .expect("new_substr"); // even though this atom is allocated on the heap (and not stored as a small // int), we can still retrieve it as one. The CLVM interpreter depends on