Skip to content

Double borrow in TlsfHeap::used #119

@fko-kuptec

Description

@fko-kuptec

The current implementation of TlsfHeap::used panics because of a double borrow:

/// Get the amount of bytes used by the allocator.
pub fn used(&self) -> usize {
    critical_section::with(|cs| {
        self.heap.borrow_ref_mut(cs).raw_block_size - self.free_with_cs(cs)
    })
}

fn free_with_cs(&self, cs: critical_section::CriticalSection) -> usize {
    let inner_mut = self.heap.borrow_ref_mut(cs);
    if !inner_mut.initialized {
        return 0;
    }
    // Safety: We pass the memory block we previously initialized the heap with
    // to the `iter_blocks` method.
    unsafe {
        inner_mut
            .tlsf
            .iter_blocks(inner_mut.raw_block.unwrap())
            .filter(|block_info| !block_info.is_occupied())
            .map(|block_info| block_info.max_payload_size())
            .sum::<usize>()
    }
}

There seems to be a specific way of evaluating an expression that results in the second borrow guard getting acquired without releasing the first. Splitting the subtraction into two statements should solve the issue:

let available = self.heap.borrow_ref_mut(cs).raw_block_size;
available - self.free_with_cs(cs)

I recreated the general issue with locking twice in a statement in this playground.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions