From 6a96c95c4f4e781732245c2b70670ea645b035e9 Mon Sep 17 00:00:00 2001 From: vthriller Date: Thu, 28 Aug 2025 03:57:02 +0300 Subject: [PATCH 1/3] Explicitly bind lifetimes for NlaBuffer.value() --- src/nla.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/nla.rs b/src/nla.rs index 33c0dfd..9ca13c9 100644 --- a/src/nla.rs +++ b/src/nla.rs @@ -148,9 +148,9 @@ impl + AsMut<[u8]>> NlaBuffer { } } -impl + ?Sized> NlaBuffer<&T> { +impl<'a, T: AsRef<[u8]> + ?Sized> NlaBuffer<&'a T> { /// Return the `value` field - pub fn value(&self) -> &[u8] { + pub fn value(&self) -> &'a [u8] { &self.buffer.as_ref()[VALUE(self.value_length())] } } @@ -374,4 +374,14 @@ mod tests { fn test_align_overflow() { assert_eq!(nla_align!(get_len() - 3), usize::MAX); } + + // compile-time test, should not result in compiler complaints regarding + // lifetimes or returning values allegedly owned by this function + #[allow(dead_code)] + fn nla_buffer_outlives_value(nlas: &[u8]) -> Option<&[u8]> { + for nla in NlasIterator::new(nlas) { + return Some(nla.unwrap().value()) + } + None + } } From ced8f3b1acf11e85705d755eeccb0c85ce6c6bbc Mon Sep 17 00:00:00 2001 From: vthriller Date: Fri, 29 Aug 2025 00:23:40 +0300 Subject: [PATCH 2/3] drop #[allow(dead_code)] by writing a test for NlasIterator, which was missing anyway --- src/nla.rs | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/nla.rs b/src/nla.rs index 9ca13c9..204f9dc 100644 --- a/src/nla.rs +++ b/src/nla.rs @@ -375,13 +375,35 @@ mod tests { assert_eq!(nla_align!(get_len() - 3), usize::MAX); } - // compile-time test, should not result in compiler complaints regarding - // lifetimes or returning values allegedly owned by this function - #[allow(dead_code)] - fn nla_buffer_outlives_value(nlas: &[u8]) -> Option<&[u8]> { - for nla in NlasIterator::new(nlas) { - return Some(nla.unwrap().value()) - } - None + // compile-time test: it should be possible to pass &[u8] through + // NlasIterator and return one of its output &[u8]s without facing + // compiler error about lifetimes and returning borrows from something + // that this funciton owns + fn last_nla_from_buffer(nlas: &[u8]) -> Option> { + NlasIterator::new(nlas).last() + .map(|nla| nla.map(|nla| nla.value())) + } + + #[test] + fn test_nlas_iterator() { + // sample NFTA_LIST_ELEM from nftables, with nested nlas at the end + static NESTED_NLAS: &[u8] = &[ + 0x0c, 0x00, 0x01, 0x00, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x00, + 0x1c, 0x00, 0x02, 0x00, + 0x0c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x47, 0xda, 0x7a, 0x03, + 0x1b, 0x0c, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x14, + 0x56, 0x39 + ]; + let mut iter = NlasIterator::new(NESTED_NLAS); + // DecodeError does not implement PartialEq, hence + // unwrap() and is_none() + assert_eq!(iter.next().unwrap().unwrap().value(), &NESTED_NLAS[4..12]); + assert_eq!(iter.next().unwrap().unwrap().value(), &NESTED_NLAS[16..]); + assert!(iter.next().is_none()); + + // this sholud be an Err() + let truncated = &NESTED_NLAS[ .. NESTED_NLAS.len()-1]; + assert!(last_nla_from_buffer(truncated).unwrap().is_err()); } } From c7610c45acf1afb9a1d82816286db5dc2c115529 Mon Sep 17 00:00:00 2001 From: vthriller Date: Fri, 29 Aug 2025 00:55:11 +0300 Subject: [PATCH 3/3] well, separate function is not required when it comes to triggering lifetime-related compiler errors --- src/nla.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/nla.rs b/src/nla.rs index 204f9dc..b0c860c 100644 --- a/src/nla.rs +++ b/src/nla.rs @@ -375,15 +375,6 @@ mod tests { assert_eq!(nla_align!(get_len() - 3), usize::MAX); } - // compile-time test: it should be possible to pass &[u8] through - // NlasIterator and return one of its output &[u8]s without facing - // compiler error about lifetimes and returning borrows from something - // that this funciton owns - fn last_nla_from_buffer(nlas: &[u8]) -> Option> { - NlasIterator::new(nlas).last() - .map(|nla| nla.map(|nla| nla.value())) - } - #[test] fn test_nlas_iterator() { // sample NFTA_LIST_ELEM from nftables, with nested nlas at the end @@ -404,6 +395,16 @@ mod tests { // this sholud be an Err() let truncated = &NESTED_NLAS[ .. NESTED_NLAS.len()-1]; - assert!(last_nla_from_buffer(truncated).unwrap().is_err()); + assert!(NlasIterator::new(truncated).last().unwrap().is_err()); + + let last = { + // it should be possible to pass &[u8] through + // NlasIterator and return one of its output &[u8]s without facing + // compiler error about lifetimes and returning borrows from + // something is limited to this scope + let last = NlasIterator::new(NESTED_NLAS).last(); + last.unwrap().unwrap().value() + }; + assert_eq!(last, &NESTED_NLAS[16..]); } }