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

Fix blob pad #51

Merged
merged 2 commits into from
Mar 13, 2025
Merged

Fix blob pad #51

merged 2 commits into from
Mar 13, 2025

Conversation

edjin
Copy link

@edjin edjin commented May 23, 2024

Hi!

I found the bug while trying to decode messages containing blobs. It happens that when a blob's size is divisible by 4, 4 more bytes than required are skipped.

@klingtnet
Copy link
Owner

Sorry that it took me almost a year to check your PR, and thanks for the contribution! I force-pushed the branch to rebase onto the latest state of master.

@klingtnet
Copy link
Owner

klingtnet commented Mar 6, 2025

Okay, I now understand what was wrong with pad_to_32_bit_boundary. The function returned 4 instead of 0 for inputs whose length was a multiple of 4.
I wonder if we can fix this more generally, like in this patch:

commit 64072a489e0e8aac8dd818fb9bf5e39728f36191
Author: Andreas Linz <klingt.net@gmail.com>
Date:   2025-03-06 11:47:28 +0100

    fixup! Fix blob pad

diff --git a/src/decoder.rs b/src/decoder.rs
index afc5d3b..425ea8a 100644
--- a/src/decoder.rs
+++ b/src/decoder.rs
@@ -152,7 +152,7 @@ fn read_osc_string<'a>(
     map_res(
         terminated(
             take_till(|c| c == 0u8),
-            nullbit_then_pad_to_32_bit_boundary(original_input),
+            pad_to_32_bit_boundary(original_input),
         ),
         |str_buf: &'a [u8]| {
             String::from_utf8(str_buf.into())
@@ -282,17 +282,10 @@ fn pad_to_32_bit_boundary<'a>(
     original_input: &'a [u8],
 ) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], (), OscError> {
     move |input| {
-        let offset = (4 - original_input.offset(input) % 4) % 4;
-        let (input, _) = take(offset)(input)?;
-        Ok((input, ()))
-    }
-}
-
-fn nullbit_then_pad_to_32_bit_boundary<'a>(
-    original_input: &'a [u8],
-) -> impl Fn(&'a [u8]) -> IResult<&'a [u8], (), OscError> {
-    move |input| {
-        let offset = 4 - original_input.offset(input) % 4;
+        let offset = match original_input.offset(input) % 4 {
+            0 => 0,
+            r => 4 - r % 4,
+        };
         let (input, _) = take(offset)(input)?;
         Ok((input, ()))
     }

But, this breaks two existing tests, test_bundle and test_encode_message_with_all_types for which I need to check if their assertions are expecting the right values.

@edjin
Copy link
Author

edjin commented Mar 6, 2025

Yess, I have to duplicate the function because the tests broke, and it doesn't seems the assertions are wrong.

For information, in the spec, string messages must end by the null byte, then completed with the padding, but blob don't end by this null byte.

Feel free to modify this code if you found a more convenient way to do that, ask me if you want me to make some changes.

@klingtnet
Copy link
Owner

In read_osc_string I think we need to take the input until we see a null-byte including the said null-byte, and then pad the matched sequence.
I failed to combine the parsers in a way that they also include the null-byte. Naively I thought that take_till(|c| c == 0u8).and_then(tag(b"\0")) would do the trick, but it doesn't.

This fixes a bug that occurred when the content-length of a string,
excluding the null-byte, was four-byte aligned. In this case we added 4
additional bytes of padding, instead of 3. We now consume the string
including the zero-byte in the parser, and then applying the correct
null-byte padding.

Thanks to @edjin for providing the initial fix this patch is based on.
@klingtnet
Copy link
Owner

I think with 8b6c8be I found a concise solution. There's still some potential for improvement, though.

Fix decoding of four-byte aligned strings

This fixes a bug that occurred when the content-length of a string,
excluding the null-byte, was four-byte aligned. In this case we added 4
additional bytes of padding, instead of 3. We now consume the string
including the zero-byte in the parser, and then apply the correct
null-byte padding.

Thanks to @edjin for providing the initial fix this patch is based on.
@edjin
Copy link
Author

edjin commented Mar 8, 2025

This looks good/better to me, Thanks 👍

@IRSMsoso
Copy link

Awesome, thanks for merging

@klingtnet klingtnet merged commit aa415f8 into klingtnet:master Mar 13, 2025
1 check passed
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