Skip to content

Commit e9ed5cd

Browse files
committed
fix: replace silent narrowing casts and eliminate per-byte allocation
- AMQPValue::try_from: replace `as` truncation casts with try_from().ok() for all integer types narrower than i64/u64, returning None on out-of-range values instead of wrapping silently - AMQPFlags::from_bytes: replace per-byte Vec<bool> allocation with an allocation-free range iterator - gen_short_string / gen_long_string / gen_byte_array / gen_content_body_frame: add debug_assert! guards for length-prefix overflow
1 parent bb05479 commit e9ed5cd

4 files changed

Lines changed: 41 additions & 13 deletions

File tree

protocol/src/frame/generation.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ fn gen_content_body_frame<'a, W: Write + 'a>(
8585
channel_id: ChannelId,
8686
content: &'a [u8],
8787
) -> impl SerializeFn<W> + 'a {
88+
debug_assert!(
89+
content.len() <= ChunkSize::MAX as usize,
90+
"content body exceeds frame size limit"
91+
);
8892
tuple((
8993
gen_short_short_uint(constants::FRAME_BODY),
9094
gen_id(channel_id),

types/src/flags.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,11 @@ impl AMQPFlags {
3737
let flags = names
3838
.iter()
3939
.map(ToString::to_string)
40-
.zip(bytes.iter_elements().flat_map(|b| {
41-
let mut v = Vec::new();
42-
for s in 0..8 {
43-
v.push(((b & (1 << s)) >> s) == 1)
44-
}
45-
v
46-
}))
40+
.zip(
41+
bytes
42+
.iter_elements()
43+
.flat_map(|b| (0..8u8).map(move |s| ((b >> s) & 1) == 1)),
44+
)
4745
.collect();
4846

4947
AMQPFlags { flags }

types/src/generation.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ pub fn gen_decimal_value<W: Write>(d: DecimalValue) -> impl SerializeFn<W> {
129129

130130
/// Generate the [ShortString](../type.ShortString.html) in the given buffer (x)
131131
pub fn gen_short_string<'a, W: Write + 'a>(s: &'a str) -> impl SerializeFn<W> + 'a {
132+
debug_assert!(
133+
s.len() <= ShortShortUInt::MAX as usize,
134+
"short string exceeds 255 bytes"
135+
);
132136
pair(
133137
gen_short_short_uint(s.len() as ShortShortUInt),
134138
slice(s.as_bytes()),
@@ -137,6 +141,10 @@ pub fn gen_short_string<'a, W: Write + 'a>(s: &'a str) -> impl SerializeFn<W> +
137141

138142
/// Generate the [LongString](../type.LongString.html) in the given buffer (x)
139143
pub fn gen_long_string<'a, W: Write + 'a>(s: &'a [u8]) -> impl SerializeFn<W> + 'a {
144+
debug_assert!(
145+
s.len() <= LongUInt::MAX as usize,
146+
"long string exceeds 4 GiB"
147+
);
140148
pair(gen_long_uint(s.len() as LongUInt), slice(s))
141149
}
142150

@@ -167,6 +175,10 @@ fn gen_field_entry<'a, W: Write + BackToTheBuffer + 'a>(
167175

168176
/// Generate the [ByteArray](../type.ByteArray.html) in the given buffer (x)
169177
pub fn gen_byte_array<'a, W: Write + 'a>(a: &'a ByteArray) -> impl SerializeFn<W> + 'a {
178+
debug_assert!(
179+
a.len() <= LongUInt::MAX as usize,
180+
"byte array exceeds 4 GiB"
181+
);
170182
pair(gen_long_uint(a.len() as LongUInt), slice(a.as_slice()))
171183
}
172184

types/src/value.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,28 @@ impl AMQPValue {
7575
AMQPType::Boolean => value.as_bool().map(AMQPValue::Boolean),
7676
AMQPType::ShortShortInt => value
7777
.as_i64()
78-
.map(|i| AMQPValue::ShortShortInt(i as ShortShortInt)),
78+
.and_then(|i| ShortShortInt::try_from(i).ok())
79+
.map(AMQPValue::ShortShortInt),
7980
AMQPType::ShortShortUInt => value
8081
.as_u64()
81-
.map(|u| AMQPValue::ShortShortUInt(u as ShortShortUInt)),
82-
AMQPType::ShortInt => value.as_i64().map(|i| AMQPValue::ShortInt(i as ShortInt)),
83-
AMQPType::ShortUInt => value.as_u64().map(|u| AMQPValue::ShortUInt(u as ShortUInt)),
84-
AMQPType::LongInt => value.as_i64().map(|i| AMQPValue::LongInt(i as LongInt)),
85-
AMQPType::LongUInt => value.as_u64().map(|u| AMQPValue::LongUInt(u as LongUInt)),
82+
.and_then(|u| ShortShortUInt::try_from(u).ok())
83+
.map(AMQPValue::ShortShortUInt),
84+
AMQPType::ShortInt => value
85+
.as_i64()
86+
.and_then(|i| ShortInt::try_from(i).ok())
87+
.map(AMQPValue::ShortInt),
88+
AMQPType::ShortUInt => value
89+
.as_u64()
90+
.and_then(|u| ShortUInt::try_from(u).ok())
91+
.map(AMQPValue::ShortUInt),
92+
AMQPType::LongInt => value
93+
.as_i64()
94+
.and_then(|i| LongInt::try_from(i).ok())
95+
.map(AMQPValue::LongInt),
96+
AMQPType::LongUInt => value
97+
.as_u64()
98+
.and_then(|u| LongUInt::try_from(u).ok())
99+
.map(AMQPValue::LongUInt),
86100
AMQPType::LongLongInt => value
87101
.as_i64()
88102
.map(|i| AMQPValue::LongLongInt(i as LongLongInt)),

0 commit comments

Comments
 (0)