-
Notifications
You must be signed in to change notification settings - Fork 15
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 panic when accessing union from invalid input #100
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,9 +13,9 @@ impl<'buf> Table<'buf> { | |
buffer: SliceWithStartOffset<'buf>, | ||
field_offset: usize, | ||
) -> Result<Self, ErrorKind> { | ||
let field_value = u32::from_buffer(buffer, field_offset)?; | ||
let object_size = u32::from_buffer(buffer, field_offset)?; | ||
let object_offset = field_offset | ||
.checked_add(field_value as usize) | ||
.checked_add(object_size as usize) | ||
.ok_or(ErrorKind::InvalidOffset)?; | ||
let object = buffer.advance(object_offset)?; | ||
|
||
|
@@ -92,12 +92,6 @@ impl<'buf> Table<'buf> { | |
type_: &'static str, | ||
method: &'static str, | ||
) -> crate::Result<Option<T>> { | ||
let offset = self | ||
.vtable | ||
.get(2 * vtable_offset..2 * (vtable_offset + 2)) | ||
.expect("IMPOSSIBLE: trying to access invalid vtable offset for union"); | ||
let tag_offset = u16::from_le_bytes(offset[..2].try_into().unwrap()) as usize; | ||
let value_offset = u16::from_le_bytes(offset[2..].try_into().unwrap()) as usize; | ||
let make_error = |error_kind| crate::errors::Error { | ||
source_location: crate::errors::ErrorLocation { | ||
type_, | ||
|
@@ -106,6 +100,15 @@ impl<'buf> Table<'buf> { | |
}, | ||
error_kind, | ||
}; | ||
|
||
let offset = self | ||
.vtable | ||
.get(2 * vtable_offset..2 * (vtable_offset + 2)) | ||
.ok_or_else(|| make_error(ErrorKind::InvalidOffset))?; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While looking into adding a few extra tests for this, I found out that this should only sometimes be considered an error. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks a lot! Awesome! Yeap feel free to close this one and focus on the improved version. 🚀 |
||
|
||
let tag_offset = u16::from_le_bytes(offset[..2].try_into().unwrap()) as usize; | ||
let value_offset = u16::from_le_bytes(offset[2..].try_into().unwrap()) as usize; | ||
|
||
let tag = u8::from_buffer(self.object, tag_offset).map_err(make_error)?; | ||
if tag_offset != 0 && value_offset != 0 && tag != 0 { | ||
T::from_buffer(self.object, value_offset, tag) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
use planus::{SliceWithStartOffset, TableReadUnion}; | ||
|
||
#[derive(Debug, PartialEq, Eq)] | ||
struct A { | ||
tag: u8, | ||
offset: usize, | ||
} | ||
|
||
impl<'buf> TableReadUnion<'buf> for A { | ||
fn from_buffer( | ||
_: SliceWithStartOffset<'buf>, | ||
offset: usize, | ||
tag: u8, | ||
) -> core::result::Result<Self, planus::errors::ErrorKind> { | ||
Ok(Self { tag, offset }) | ||
} | ||
} | ||
|
||
#[test] | ||
fn access_union() { | ||
use planus::table_reader::Table; | ||
let data: Vec<u8> = vec![ | ||
8, 0, 0, 0, // vtable size | ||
4, 0, 1, 0, // vtable with tag offset (u16) and value offset (u16) | ||
4, 0, 0, 0, // object size (u32) | ||
12, 0, 0, 0, // vtable offset (i32) | ||
1, 0, 0, 0, // tag | ||
]; | ||
let data = SliceWithStartOffset { | ||
buffer: &data, | ||
offset_from_start: 0, | ||
}; | ||
let table = Table::from_buffer(data, 8).unwrap(); | ||
|
||
// vtable has 1 entry | ||
// => accessing index 0 must be ok | ||
assert_eq!( | ||
table.access_union::<A>(0, "", "").unwrap(), | ||
Some(A { tag: 1, offset: 1 }) | ||
); | ||
// => accessing index 1 must error | ||
assert!(table.access_union::<A>(1, "", "").is_err()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is run primarily when a table is accessed from another table. The "field value" is an offset to where the actual table is. I would be up for a better name for this variable, but
object_size
is not better.