Skip to content

Fix iter_blocks on oddly sized or unaligned blocks#21

Closed
jannic wants to merge 1 commit intoyvt:mainfrom
jannic-dev-forks:fix-iter_blocks-unaligned
Closed

Fix iter_blocks on oddly sized or unaligned blocks#21
jannic wants to merge 1 commit intoyvt:mainfrom
jannic-dev-forks:fix-iter_blocks-unaligned

Conversation

@jannic
Copy link

@jannic jannic commented Jan 28, 2026

If len < GRANULARITY * 2, insert_free_block_ptr doesn't insert another block:

          let len = if let Some(x) = len
              .checked_sub((start as usize).wrapping_sub(unaligned_start as usize))
              .filter(|&x| x >= GRANULARITY * 2)
          {
              // Round down
              x & !(GRANULARITY - 1)
          } else {
              // The block is too small
              return None;
          };

This can happen if the block being added has an odd size (not a multiple of GRANULARITY * 2) or is unaligned.

Therefore, iter_blocks must also skip remaining lengths smaller than this.

I think this is the root cause for a panic we observed in rust-embedded/embedded-alloc#121

If len < GRANULARITY * 2, insert_free_block_ptr doesn't insert another block:

```
          let len = if let Some(x) = len
              .checked_sub((start as usize).wrapping_sub(unaligned_start as usize))
              .filter(|&x| x >= GRANULARITY * 2)
          {
              // Round down
              x & !(GRANULARITY - 1)
          } else {
              // The block is too small
              return None;
          };
```

This can happen if the block being added has an odd size (not a multiple
of GRANULARITY * 2) or is unaligned.

Therefore, iter_blocks must also skip remaining lengths smaller than this.

I think this is the root cause for a panic we observed in
rust-embedded/embedded-alloc#121
jannic added a commit to jannic-dev-forks/embedded-alloc that referenced this pull request Jan 28, 2026
@yvt
Copy link
Owner

yvt commented Jan 29, 2026

The length of the slice passed to iter_blocks must match the size returned by insert_free_block_ptr, which excludes the misaligned tail.

iter_blocks:

rlsf/crates/rlsf/src/tlsf.rs

Lines 1482 to 1485 in 03664d5

/// passed to [`Self::insert_free_block_ptr`], and its length must be the
/// sum of the return values of that call to `insert_free_block_ptr` and
/// all subsequent calls to [`Self::append_free_block_ptr`] that have been
/// made to expand this memory pool.

insert_free_block_ptr:

/// Returns the actual number of bytes (counted from the beginning of
/// `block`) used to create the memory pool. This value is necessary to

@jannic
Copy link
Author

jannic commented Jan 29, 2026

Interesting, seems like I missed that detail (and the author of https://github.com/rust-embedded/embedded-alloc/blob/master/src/tlsf.rs#L82-L83 as well).
So the correct solution would be for embedded-alloc to store the value returned from insert_free_block_ptr and use that when calling iter_blocks.

@yvt
Copy link
Owner

yvt commented Jan 30, 2026

That is correct.

@jannic
Copy link
Author

jannic commented Feb 3, 2026

Thanks, I provided a PR for fixing the bug in embedded-alloc. I no longer think there is a bug in rlsf, so I'll close this ticket.

@jannic jannic closed this Feb 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants