From ffb85a8f0e872141054262c8c17e3367233582cb Mon Sep 17 00:00:00 2001 From: arvidn Date: Sat, 6 Jan 2024 14:54:09 +0100 Subject: [PATCH] make the upper limit of allocated atoms and pairs hard coded instead of configurable. Now that the 1.8.0 soft-fork has activated, all blocks are validated with these limits. --- Cargo.lock | 2 +- src/allocator.rs | 55 +++++++++++++++++++++++------------------------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f25aeac8..ca091e3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -269,7 +269,7 @@ dependencies = [ [[package]] name = "clvmr" -version = "0.3.2" +version = "0.3.3" dependencies = [ "chia-bls", "clvm-traits", diff --git a/src/allocator.rs b/src/allocator.rs index 1bb63420..8cee6839 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -56,14 +56,11 @@ pub struct Allocator { // the atom_vec may not grow past this heap_limit: usize, - - // the pair_vec may not grow past this - pair_limit: usize, - - // the atom_vec may not grow past this - atom_limit: usize, } +const MAX_NUM_ATOMS: usize = 62500000; +const MAX_NUM_PAIRS: usize = 62500000; + impl Default for Allocator { fn default() -> Self { Self::new() @@ -72,29 +69,18 @@ impl Default for Allocator { impl Allocator { pub fn new() -> Self { - Self::new_limited( - u32::MAX as usize, - i32::MAX as usize, - (i32::MAX - 1) as usize, - ) + Self::new_limited(u32::MAX as usize) } - pub fn new_limited(heap_limit: usize, pair_limit: usize, atom_limit: usize) -> Self { + pub fn new_limited(heap_limit: usize) -> Self { // we have a maximum of 4 GiB heap, because pointers are 32 bit unsigned assert!(heap_limit <= u32::MAX as usize); - // the atoms and pairs share a single 32 bit address space, where - // negative numbers are atoms and positive numbers are pairs. That's why - // we have one more slot for pairs than atoms - assert!(pair_limit <= i32::MAX as usize); - assert!(atom_limit < i32::MAX as usize); let mut r = Self { u8_vec: Vec::new(), pair_vec: Vec::new(), atom_vec: Vec::new(), heap_limit, - pair_limit, - atom_limit, }; r.u8_vec.reserve(1024 * 1024); r.atom_vec.reserve(256); @@ -136,7 +122,7 @@ impl Allocator { if (self.heap_limit - start as usize) < v.len() { return err(self.null(), "out of memory"); } - if self.atom_vec.len() == self.atom_limit { + if self.atom_vec.len() == MAX_NUM_ATOMS { return err(self.null(), "too many atoms"); } self.u8_vec.extend_from_slice(v); @@ -159,7 +145,7 @@ impl Allocator { pub fn new_pair(&mut self, first: NodePtr, rest: NodePtr) -> Result { let r = self.pair_vec.len() as i32; - if self.pair_vec.len() == self.pair_limit { + if self.pair_vec.len() == MAX_NUM_PAIRS { return err(self.null(), "too many pairs"); } self.pair_vec.push(IntPair { first, rest }); @@ -170,7 +156,7 @@ impl Allocator { if node.0 >= 0 { return err(node, "(internal error) substr expected atom, got pair"); } - if self.atom_vec.len() == self.atom_limit { + if self.atom_vec.len() == MAX_NUM_ATOMS { return err(self.null(), "too many atoms"); } let atom = self.atom_vec[(-node.0 - 1) as usize]; @@ -192,7 +178,7 @@ impl Allocator { } pub fn new_concat(&mut self, new_size: usize, nodes: &[NodePtr]) -> Result { - if self.atom_vec.len() == self.atom_limit { + if self.atom_vec.len() == MAX_NUM_ATOMS { return err(self.null(), "too many atoms"); } let start = self.u8_vec.len(); @@ -471,7 +457,7 @@ fn test_allocate_pair() { #[test] fn test_allocate_heap_limit() { - let mut a = Allocator::new_limited(6, i32::MAX as usize, (i32::MAX - 1) as usize); + let mut a = Allocator::new_limited(6); // we can't allocate 6 bytes assert_eq!(a.new_atom(b"foobar").unwrap_err().1, "out of memory"); // but 5 is OK @@ -480,7 +466,7 @@ fn test_allocate_heap_limit() { #[test] fn test_allocate_atom_limit() { - let mut a = Allocator::new_limited(u32::MAX as usize, i32::MAX as usize, 5); + let mut a = Allocator::new(); // we can allocate 5 atoms total // keep in mind that we always have 2 pre-allocated atoms for null and one, // so with a limit of 5, we only have 3 slots left at this point. @@ -490,17 +476,28 @@ fn test_allocate_atom_limit() { // the 4th fails and ensure not to append atom to the stack assert_eq!(a.u8_vec.len(), 10); + for _ in 3..MAX_NUM_ATOMS-2 { + // exhaust the numebr of atoms allowed to be allocated + let _ = a.new_atom(b"foo").unwrap(); + } assert_eq!(a.new_atom(b"foobar").unwrap_err().1, "too many atoms"); - assert_eq!(a.u8_vec.len(), 10); + + // the pre-allocated null() and one() also count against the limit, and they + // use 0 and 1 bytes respectively + assert_eq!(a.u8_vec.len(), MAX_NUM_ATOMS * 3 - 3 - 2); } #[test] fn test_allocate_pair_limit() { - let mut a = Allocator::new_limited(u32::MAX as usize, 1, (i32::MAX - 1) as usize); + let mut a = Allocator::new(); let atom = a.new_atom(b"foo").unwrap(); // one pair is OK let _pair1 = a.new_pair(atom, atom).unwrap(); - // but not 2 + for _ in 1..MAX_NUM_PAIRS { + // exhaust the numebr of pairs allowed to be allocated + let _ = a.new_pair(atom, atom).unwrap(); + } + assert_eq!(a.new_pair(atom, atom).unwrap_err().1, "too many pairs"); } @@ -601,7 +598,7 @@ fn test_sexp() { #[test] fn test_concat_limit() { - let mut a = Allocator::new_limited(9, i32::MAX as usize, (i32::MAX - 1) as usize); + let mut a = Allocator::new_limited(9); let atom1 = a.new_atom(b"f").unwrap(); let atom2 = a.new_atom(b"o").unwrap(); let atom3 = a.new_atom(b"o").unwrap();