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

Add early length checks to TryParse implementations #491

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions generator/src/generator/namespace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2560,6 +2560,22 @@ impl<'ns, 'c> NamespaceGenerator<'ns, 'c> {
if parse_size_constraint != StructSizeConstraint::None {
outln!(out, "let remaining = initial_value;");
}
// Get the minimum size that this struct can have
let mut minimum_size: u32 = fields.iter()
.map(|field| field.size().unwrap_or(0))
.sum();
if let Some(size) = match parse_size_constraint {
StructSizeConstraint::None => None,
StructSizeConstraint::Fixed(size) => Some(size),
StructSizeConstraint::EmbeddedLength { minimum } => Some(minimum),
} {
minimum_size = minimum_size.max(size.into());
}
outln!(out, "// Check that enough bytes for the minimum possible size is available.");
outln!(out, "// This allows the compiler to optimise away some length checks.");
outln!(out, "if remaining.len() < {} {{", minimum_size);
outln!(out.indent(), "return Err(ParseError::ParseError);");
outln!(out, "}}");
Self::emit_let_value_for_dynamic_align(fields, out);
for field in fields.iter() {
self.emit_field_parse(
Expand Down
5 changes: 5 additions & 0 deletions src/protocol/bigreq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ pub struct EnableReply {
impl TryParse for EnableReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down
10 changes: 10 additions & 0 deletions src/protocol/composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ pub struct QueryVersionReply {
impl TryParse for QueryVersionReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -692,6 +697,11 @@ pub struct GetOverlayWindowReply {
impl TryParse for GetOverlayWindowReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down
15 changes: 15 additions & 0 deletions src/protocol/damage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ pub struct BadDamageError {
impl TryParse for BadDamageError {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let (error_code, remaining) = u8::try_parse(remaining)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -261,6 +266,11 @@ pub struct QueryVersionReply {
impl TryParse for QueryVersionReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -588,6 +598,11 @@ pub struct NotifyEvent {
impl TryParse for NotifyEvent {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let (level, remaining) = u8::try_parse(remaining)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down
20 changes: 20 additions & 0 deletions src/protocol/dpms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ pub struct GetVersionReply {
impl TryParse for GetVersionReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -188,6 +193,11 @@ pub struct CapableReply {
impl TryParse for CapableReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -270,6 +280,11 @@ pub struct GetTimeoutsReply {
impl TryParse for GetTimeoutsReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -650,6 +665,11 @@ pub struct InfoReply {
impl TryParse for InfoReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down
75 changes: 75 additions & 0 deletions src/protocol/dri2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,11 @@ pub struct DRI2Buffer {
}
impl TryParse for DRI2Buffer {
fn try_parse(remaining: &[u8]) -> Result<(Self, &[u8]), ParseError> {
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 20 {
return Err(ParseError::ParseError);
}
let (attachment, remaining) = u32::try_parse(remaining)?;
let (name, remaining) = u32::try_parse(remaining)?;
let (pitch, remaining) = u32::try_parse(remaining)?;
Expand Down Expand Up @@ -334,6 +339,11 @@ pub struct AttachFormat {
}
impl TryParse for AttachFormat {
fn try_parse(remaining: &[u8]) -> Result<(Self, &[u8]), ParseError> {
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 8 {
return Err(ParseError::ParseError);
}
let (attachment, remaining) = u32::try_parse(remaining)?;
let (format, remaining) = u32::try_parse(remaining)?;
let attachment = attachment.try_into()?;
Expand Down Expand Up @@ -448,6 +458,11 @@ pub struct QueryVersionReply {
impl TryParse for QueryVersionReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -551,6 +566,11 @@ pub struct ConnectReply {
impl TryParse for ConnectReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -686,6 +706,11 @@ pub struct AuthenticateReply {
impl TryParse for AuthenticateReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -928,6 +953,11 @@ pub struct GetBuffersReply {
impl TryParse for GetBuffersReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -1063,6 +1093,11 @@ pub struct CopyRegionReply {
impl TryParse for CopyRegionReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -1186,6 +1221,11 @@ pub struct GetBuffersWithFormatReply {
impl TryParse for GetBuffersWithFormatReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -1350,6 +1390,11 @@ pub struct SwapBuffersReply {
impl TryParse for SwapBuffersReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -1446,6 +1491,11 @@ pub struct GetMSCReply {
impl TryParse for GetMSCReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -1600,6 +1650,11 @@ pub struct WaitMSCReply {
impl TryParse for WaitMSCReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -1718,6 +1773,11 @@ pub struct WaitSBCReply {
impl TryParse for WaitSBCReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -1892,6 +1952,11 @@ pub struct GetParamReply {
impl TryParse for GetParamReply {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let (is_param_recognized, remaining) = bool::try_parse(remaining)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -1932,6 +1997,11 @@ pub struct BufferSwapCompleteEvent {
impl TryParse for BufferSwapCompleteEvent {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down Expand Up @@ -2021,6 +2091,11 @@ pub struct InvalidateBuffersEvent {
impl TryParse for InvalidateBuffersEvent {
fn try_parse(initial_value: &[u8]) -> Result<(Self, &[u8]), ParseError> {
let remaining = initial_value;
// Check that enough bytes for the minimum possible size is available.
// This allows the compiler to optimise away some length checks.
if remaining.len() < 32 {
return Err(ParseError::ParseError);
}
let (response_type, remaining) = u8::try_parse(remaining)?;
let remaining = remaining.get(1..).ok_or(ParseError::ParseError)?;
let (sequence, remaining) = u16::try_parse(remaining)?;
Expand Down
Loading