diff --git a/src/codec/mod.rs b/src/codec/mod.rs index 5c0d493..179347c 100644 --- a/src/codec/mod.rs +++ b/src/codec/mod.rs @@ -50,6 +50,9 @@ impl TryFrom<&[u8]> for ExceptionResponse { type Error = Error; fn try_from(bytes: &[u8]) -> Result { + if bytes.is_empty() { + return Err(Error::BufferSize); + } let fn_err_code = bytes[0]; if fn_err_code < 0x80 { return Err(Error::ExceptionFnCode(fn_err_code)); @@ -156,7 +159,9 @@ impl<'r> TryFrom<&'r [u8]> for Response<'r> { fn try_from(bytes: &'r [u8]) -> Result { use FunctionCode as F; - + if bytes.is_empty() { + return Err(Error::BufferSize); + } let fn_code = bytes[0]; if bytes.len() < min_response_pdu_len(FunctionCode::new(fn_code)) { return Err(Error::BufferSize); @@ -327,6 +332,9 @@ impl<'r> Encode for RequestPdu<'r> { impl<'r> Encode for ResponsePdu<'r> { fn encode(&self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Err(Error::BufferSize); + } match self.0 { Ok(res) => res.encode(buf), Err(e) => e.encode(buf), @@ -336,6 +344,9 @@ impl<'r> Encode for ResponsePdu<'r> { impl Encode for ExceptionResponse { fn encode(&self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Err(Error::BufferSize); + } let [code, ex]: [u8; 2] = (*self).into(); buf[0] = code; buf[1] = ex; diff --git a/src/codec/rtu/mod.rs b/src/codec/rtu/mod.rs index 4c94e55..b719865 100644 --- a/src/codec/rtu/mod.rs +++ b/src/codec/rtu/mod.rs @@ -34,6 +34,10 @@ pub fn decode( use DecoderType::{Request, Response}; let mut drop_cnt = 0; + if buf.is_empty() { + return Err(Error::BufferSize); + } + loop { let mut retry = false; if drop_cnt + 1 >= buf.len() { @@ -89,6 +93,10 @@ pub fn decode( /// Extract a PDU frame out of a buffer. #[allow(clippy::similar_names)] pub fn extract_frame(buf: &[u8], pdu_len: usize) -> Result> { + if buf.is_empty() { + return Err(Error::BufferSize); + } + let adu_len = 1 + pdu_len; if buf.len() >= adu_len + 2 { let (adu_buf, buf) = buf.split_at(adu_len); diff --git a/src/codec/rtu/server.rs b/src/codec/rtu/server.rs index f5a6afe..743a27b 100644 --- a/src/codec/rtu/server.rs +++ b/src/codec/rtu/server.rs @@ -3,6 +3,9 @@ use super::*; /// Decode an RTU request. pub fn decode_request(buf: &[u8]) -> Result> { + if buf.is_empty() { + return Ok(None); + } decode(DecoderType::Request, buf) .and_then(|frame| { let Some((DecodedFrame { slave, pdu }, _frame_pos)) = frame else { diff --git a/src/codec/tcp/mod.rs b/src/codec/tcp/mod.rs index e2fd60c..7c4bb19 100644 --- a/src/codec/tcp/mod.rs +++ b/src/codec/tcp/mod.rs @@ -35,6 +35,10 @@ pub fn decode( use DecoderType::{Request, Response}; let mut drop_cnt = 0; + if buf.is_empty() { + return Err(Error::BufferSize); + } + loop { let mut retry = false; if drop_cnt + 1 >= buf.len() { @@ -90,6 +94,9 @@ pub fn decode( /// Extract a PDU frame out of a buffer. pub fn extract_frame(buf: &[u8], pdu_len: usize) -> Result> { + if buf.is_empty() { + return Err(Error::BufferSize); + } let adu_len = 7 + pdu_len; if buf.len() >= adu_len { let (adu_buf, _next_frame) = buf.split_at(adu_len); diff --git a/src/codec/tcp/server.rs b/src/codec/tcp/server.rs index af22792..e2e3a7e 100644 --- a/src/codec/tcp/server.rs +++ b/src/codec/tcp/server.rs @@ -3,6 +3,9 @@ use super::*; /// Decode an TCP request. pub fn decode_request(buf: &[u8]) -> Result> { + if buf.is_empty() { + return Ok(None); + } let frame = decode(DecoderType::Request, buf)?; let Some((decoded_frame, _frame_pos)) = frame else { return Ok(None); @@ -31,6 +34,9 @@ pub fn decode_request(buf: &[u8]) -> Result> { // Decode a TCP response pub fn decode_response(buf: &[u8]) -> Result> { + if buf.is_empty() { + return Err(Error::BufferSize); + } decode(DecoderType::Response, buf) .and_then(|frame| { let Some((decoded_frame, _frame_pos)) = frame else { diff --git a/src/frame/coils.rs b/src/frame/coils.rs index 6031de7..85e65eb 100644 --- a/src/frame/coils.rs +++ b/src/frame/coils.rs @@ -11,6 +11,9 @@ pub struct Coils<'c> { impl<'c> Coils<'c> { /// Pack coils defined by an bool slice into a byte buffer. pub fn from_bools(bools: &[bool], target: &'c mut [u8]) -> Result { + if bools.is_empty() { + return Err(Error::BufferSize); + } pack_coils(bools, target)?; Ok(Coils { data: target, diff --git a/src/frame/data.rs b/src/frame/data.rs index da78247..56930b7 100644 --- a/src/frame/data.rs +++ b/src/frame/data.rs @@ -11,7 +11,7 @@ pub struct Data<'d> { impl<'d> Data<'d> { /// Pack words (u16 values) into a byte buffer. pub fn from_words(words: &[u16], target: &'d mut [u8]) -> Result { - if words.len() * 2 > target.len() { + if (words.len() * 2 > target.len()) || words.is_empty() { return Err(Error::BufferSize); } for (i, w) in words.iter().enumerate() {