Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

buffer_manager: Implement Generic Buffer Management with Ownership Validation #844

Open
wants to merge 16 commits into
base: main
Choose a base branch
from

Conversation

bhargavshah1988
Copy link
Contributor

This PR introduces a generic buffer management system that ensures memory safety and proper ownership tracking. It prevents accidental or malicious freeing of buffers allocated by a different instance using a signature-based validation mechanism. The design maintains a sorted free list, minimizes fragmentation by merging adjacent free blocks, and ensures unique allocation IDs.

@bhargavshah1988 bhargavshah1988 marked this pull request as ready for review February 12, 2025 19:16
@bhargavshah1988 bhargavshah1988 requested a review from a team as a code owner February 12, 2025 19:16
@bhargavshah1988 bhargavshah1988 requested a review from a team as a code owner February 12, 2025 19:27
@bhargavshah1988 bhargavshah1988 changed the title Implement Generic Buffer Management with Ownership Validation buffer_manager: Implement Generic Buffer Management with Ownership Validation Feb 12, 2025
@@ -0,0 +1,259 @@
// Copyright (c) Microsoft Corporation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like our formatter doesn't quite catch duplicate copyright directives. Please remove one :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can never be too safe when it comes to IP.

}
}

pub struct BufferManager {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that this is a new generic utility component, please add usage documentation for the BufferManager class.

Some things that are useful to include are any intended limitations, performance characteristics, etc. Please also include comments when a routine would PANIC (for example: in the case of external corruptions)

impl BufferManager {
pub fn new(size: usize) -> Self {
let mut signature: u64 = 0;
getrandom::getrandom(signature.as_mut_bytes()).expect("crng failure");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you just use let signature = getrandom::u64().expect("failed to allocate random signature"); instead? That would avoid this taking a depending on zerocopy, and is simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like getrandom does not have u64(). Do you have any example for this ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't use getrandom for this, it's expensive. If you really need this, then using a static AtomicU64 to generate unique values.


pub fn free(&mut self, buffer: BufferBlock) {
if buffer.signature != self.signature {
panic!("Attempted to free a buffer from a different allocator");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it instead be preferable for each BufferBlock to maintain a pointer to the BufferManager, and then have the buffer simply remove itself from the correct buffer block?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition, it seems that we allow for safe double frees (that is: you can free a buffer as many times as you want). Is that your intention? What's the use case for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition, it seems that we allow for safe double frees (that is: you can free a buffer as many times as you want). Is that your intention? What's the use case for that?

There is no usecase for double free at hand. Can make it more strict on double free.

}

pub fn malloc(&mut self, size: usize) -> Option<BufferBlock> {
if let Some(pos) = self.free_list.iter().position(|block| block.size >= size) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, we've arrived at a general purpose heap implementation, and this one is pretty slow.

For the use cases we have, do we need a general purpose heap, i.e., do we need to return contiguous buffers? Or can we just have a page allocator?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Even if we do need a general-purpose heap, this O(N) scanning is going to be quite expensive.)

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.

3 participants