Repository: paritytech/substrate
File: client/allocator/src/freeing_bump.rs (Rust)

Code before:
	/// NOTE: Once the allocator has returned an error all subsequent requests will return an error.
	///
	/// # Arguments
	///
	/// - `mem` - a slice representing the linear memory on which this allocator operates.
	/// - `size` - size in bytes of the allocation request
	pub fn allocate(
		&mut self,
		mem: &mut impl Memory,
		size: WordSize,
	) -> Result<Pointer<u8>, Error> {
		if self.poisoned {
			return Err(error("the allocator has been poisoned"))
		}

		let bomb = PoisonBomb { poisoned: &mut self.poisoned };

		Self::observe_memory_size(&mut self.last_observed_memory_size, mem)?;
		let order = Order::from_size(size)?;

		let header_ptr: u32 = match self.free_lists[order] {
			Link::Ptr(header_ptr) => {
				assert!(
					u64::from(header_ptr + order.size() + HEADER_SIZE) <= mem.size(),
					"Pointer is looked up in list of free entries, into which
					only valid values are inserted; qed"
				);

				// Remove this header from the free list.
				let next_free = Header::read_from(mem, header_ptr)?
					.into_free()
					.ok_or_else(|| error("free list points to a occupied header"))?;
				self.free_lists[order] = next_free;

				header_ptr
			},
			Link::Nil => {
				// Corresponding free list is empty. Allocate a new item.
				Self::bump(&mut self.bumper, order.size() + HEADER_SIZE, mem)?
			},
		};

		// Write the order in the occupied header.
		Header::Occupied(order).write_into(mem, header_ptr)?;

		self.stats.bytes_allocated += order.size() + HEADER_SIZE;
		self.stats.bytes_allocated_sum += u128::from(order.size() + HEADER_SIZE);
		self.stats.bytes_allocated_peak =
			max(self.stats.bytes_allocated_peak, self.stats.bytes_allocated);
		self.stats.address_space_used = self.bumper - self.original_heap_base;


Review comment (suggestion):
This will poison the heap now. Could you please add this to the test?

I assume this is intended as per doc: `Once the allocator has returned an error all subsequent requests will return an error.`.

Code after:
	/// NOTE: Once the allocator has returned an error all subsequent requests will return an error.
	///
	/// # Arguments
	///
	/// - `mem` - a slice representing the linear memory on which this allocator operates.
	/// - `size` - size in bytes of the allocation request
	pub fn allocate(
		&mut self,
		mem: &mut impl Memory,
		size: WordSize,
	) -> Result<Pointer<u8>, Error> {
		if self.poisoned {
			return Err(error("the allocator has been poisoned"))
		}

		let bomb = PoisonBomb { poisoned: &mut self.poisoned };

		Self::observe_memory_size(&mut self.last_observed_memory_size, mem)?;
		let order = Order::from_size(size)?;

		let header_ptr: u32 = match self.free_lists[order] {
			Link::Ptr(header_ptr) => {
				if (u64::from(header_ptr) + u64::from(order.size()) + u64::from(HEADER_SIZE)) >
					mem.size()
				{
					return Err(error("Invalid header pointer detected"))
				}

				// Remove this header from the free list.
				let next_free = Header::read_from(mem, header_ptr)?
					.into_free()
					.ok_or_else(|| error("free list points to a occupied header"))?;
				self.free_lists[order] = next_free;

				header_ptr
			},
			Link::Nil => {
				// Corresponding free list is empty. Allocate a new item.
				Self::bump(&mut self.bumper, order.size() + HEADER_SIZE, mem)?
			},
		};

		// Write the order in the occupied header.
		Header::Occupied(order).write_into(mem, header_ptr)?;

		self.stats.bytes_allocated += order.size() + HEADER_SIZE;
		self.stats.bytes_allocated_sum += u128::from(order.size() + HEADER_SIZE);
		self.stats.bytes_allocated_peak =
			max(self.stats.bytes_allocated_peak, self.stats.bytes_allocated);
		self.stats.address_space_used = self.bumper - self.original_heap_base;