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

Safe access to buffer via .get(index)? #138

Closed

Conversation

geonnave
Copy link
Collaborator

@geonnave geonnave commented Nov 15, 2023

@malishav as discussed, this is a proposal for safely accessing the received buffer. Added a partial implementation to enable a quick first-pass review.

@geonnave geonnave requested a review from malishav November 15, 2023 16:03
Copy link
Contributor

@malishav malishav left a comment

Choose a reason for hiding this comment

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

I think this is a good way forward. See inline two small comments.


fn get(self, index: usize) -> Result<u8, AccessError> {
if index >= self.len {
return Err(AccessError::OutOfBounds);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you use return?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Normally I prefer to halt and early-return upon errors, but I think in this case the function is small enough to use an else. Updated.

impl From<AccessError> for EDHOCError {
fn from(error: AccessError) -> Self {
match error {
AccessError::OutOfBounds => EDHOCError::ParsingError,
Copy link
Contributor

Choose a reason for hiding this comment

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

So we are basically mapping all OutOfBounds errors to EDHOCError:ParsingError. This may result in ParsingError for non-parsing, i.e. encoding routines when accidentally trying to access the buffer content, right?

In the case of parsing routines when unsanitized input is received, this will properly return ParsingError.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, will add a TODO to think of a way to handle it in a more general case. For now it is fine since encoding routines are expected to always work (they return the value itself, and not Ok/Err).

Copy link
Contributor

Choose a reason for hiding this comment

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

But note that you then won't be able to use the ? syntax and propagate the error.

@geonnave geonnave force-pushed the safe-buffer-access-via-get branch from 3aeb5c4 to 4016e8e Compare November 15, 2023 16:24
@@ -172,6 +187,8 @@ impl Default for EdhocMessageBuffer {

pub trait MessageBufferTrait {
fn new() -> Self;
fn get(self, index: usize) -> Result<u8, AccessError>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The common pattern in the standard library is that fallible access just returns an Option (eg. the slice get function). Why deviate here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

By returning AccessError, I can automatically cast it to EDHOCError and then use the ? operator in a clean way in any parse_* function.

On the other hand, I now realize that all parse_* functions only ever return 1 type of error (ParsingError). If I make them return Option then the standard way could work.

Copy link
Collaborator

Choose a reason for hiding this comment

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

That is indeed an inconvenience. The means of making ? just turn into a Result<..., MyError> are not stable yet (if they even work that way). If you still want to take up the suggestion, there is a pattern that allows using foo.get(10).or_parse_error()? in the parsing code -- although it's really just a very small enhancement over simply writing foo.get(10).ok_or(Error::ParseError)? every time.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I am working on an alternative parsing mechanism, inspired by minicbor, which should solve this in the parsing functions.

@@ -172,6 +187,8 @@ impl Default for EdhocMessageBuffer {

pub trait MessageBufferTrait {
fn new() -> Self;
fn get(self, index: usize) -> Result<u8, AccessError>;
fn get_slice<'a>(&'a self, start: usize, len: usize) -> Result<&'a [u8], AccessError>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The standard library uses a single get function that utilizes the SliceIndex trait. Could we do this here as well?

(Those two items combined might pave the way toward plugging in more widespread buffer implementations for production builds, and/or working with anything that is DerefMut<[u8]>).

@geonnave
Copy link
Collaborator Author

This was superseded by #140 and #153.

@geonnave geonnave closed this Nov 21, 2023
@geonnave geonnave deleted the safe-buffer-access-via-get branch November 21, 2023 12:49
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