Skip to content

Commit abbd452

Browse files
committed
Use a variable-length integer for many serialization wrappers
The lightning protocol uses u16s for lengths in most cases. As our serialization framework primarily targets that, we must as well. However, because we may serialize objects that have more than 65K entries, we want to be able to store larger values. Thus, we define a variable length integer here which is backwards-compatible but treats 0xffff as "read eight more bytes". This doesn't address any specific known issue, but feels like good practice just in case.
1 parent b75a558 commit abbd452

File tree

1 file changed

+52
-18
lines changed

1 file changed

+52
-18
lines changed

lightning/src/util/ser.rs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,35 @@ impl Readable for BigSize {
383383
}
384384
}
385385

386+
/// The lightning protocol uses u16s for lengths in most cases. As our serialization framework
387+
/// primarily targets that, we must as well. However, because we may serialize objects that have
388+
/// more than 65K entries, we need to be able to store larger values. Thus, we define a variable
389+
/// length integer here which is backwards-compatible but treats 0xffff as "read eight more bytes".
390+
struct U16Or64(pub u64);
391+
impl Writeable for U16Or64 {
392+
#[inline]
393+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
394+
if self.0 < 0xffff {
395+
(self.0 as u16).write(writer)
396+
} else {
397+
0xffffu16.write(writer)?;
398+
(self.0 - 0xfffe).write(writer)
399+
}
400+
}
401+
}
402+
403+
impl Readable for U16Or64 {
404+
#[inline]
405+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
406+
let mut val: u64 = <u16 as Readable>::read(r)? as u64;
407+
if val == 0xffff {
408+
val = <u64 as Readable>::read(r)?
409+
.checked_add(0xfffe).ok_or(DecodeError::InvalidValue)?;
410+
}
411+
Ok(U16Or64(val))
412+
}
413+
}
414+
386415
/// In TLV we occasionally send fields which only consist of, or potentially end with, a
387416
/// variable-length integer which is simply truncated by skipping high zero bytes. This type
388417
/// encapsulates such integers implementing [`Readable`]/[`Writeable`] for them.
@@ -597,7 +626,7 @@ macro_rules! impl_for_map {
597626
{
598627
#[inline]
599628
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
600-
(self.len() as u16).write(w)?;
629+
U16Or64(self.len() as u64).write(w)?;
601630
for (key, value) in self.iter() {
602631
key.write(w)?;
603632
value.write(w)?;
@@ -611,9 +640,9 @@ macro_rules! impl_for_map {
611640
{
612641
#[inline]
613642
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
614-
let len: u16 = Readable::read(r)?;
615-
let mut ret = $constr(len as usize);
616-
for _ in 0..len {
643+
let len: U16Or64 = Readable::read(r)?;
644+
let mut ret = $constr(len.0 as usize);
645+
for _ in 0..len.0 {
617646
let k = K::read(r)?;
618647
let v_opt = V::read(r)?;
619648
if let Some(v) = v_opt {
@@ -637,7 +666,7 @@ where T: Writeable + Eq + Hash
637666
{
638667
#[inline]
639668
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
640-
(self.len() as u16).write(w)?;
669+
U16Or64(self.len() as u64).write(w)?;
641670
for item in self.iter() {
642671
item.write(w)?;
643672
}
@@ -650,9 +679,9 @@ where T: Readable + Eq + Hash
650679
{
651680
#[inline]
652681
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
653-
let len: u16 = Readable::read(r)?;
654-
let mut ret = HashSet::with_capacity(len as usize);
655-
for _ in 0..len {
682+
let len: U16Or64 = Readable::read(r)?;
683+
let mut ret = HashSet::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<T>()));
684+
for _ in 0..len.0 {
656685
if !ret.insert(T::read(r)?) {
657686
return Err(DecodeError::InvalidValue)
658687
}
@@ -667,7 +696,7 @@ macro_rules! impl_for_vec {
667696
impl<$($name : Writeable),*> Writeable for Vec<$ty> {
668697
#[inline]
669698
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
670-
(self.len() as u16).write(w)?;
699+
U16Or64(self.len() as u64).write(w)?;
671700
for elem in self.iter() {
672701
elem.write(w)?;
673702
}
@@ -678,9 +707,9 @@ macro_rules! impl_for_vec {
678707
impl<$($name : Readable),*> Readable for Vec<$ty> {
679708
#[inline]
680709
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
681-
let len: u16 = Readable::read(r)?;
682-
let mut ret = Vec::with_capacity(cmp::min(len as usize, MAX_BUF_SIZE / core::mem::size_of::<$ty>()));
683-
for _ in 0..len {
710+
let len: U16Or64 = Readable::read(r)?;
711+
let mut ret = Vec::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<$ty>()));
712+
for _ in 0..len.0 {
684713
if let Some(val) = MaybeReadable::read(r)? {
685714
ret.push(val);
686715
}
@@ -694,18 +723,23 @@ macro_rules! impl_for_vec {
694723
impl Writeable for Vec<u8> {
695724
#[inline]
696725
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
697-
(self.len() as u16).write(w)?;
726+
U16Or64(self.len() as u64).write(w)?;
698727
w.write_all(&self)
699728
}
700729
}
701730

702731
impl Readable for Vec<u8> {
703732
#[inline]
704733
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
705-
let len: u16 = Readable::read(r)?;
706-
let mut ret = Vec::with_capacity(len as usize);
707-
ret.resize(len as usize, 0);
708-
r.read_exact(&mut ret)?;
734+
let mut len: U16Or64 = Readable::read(r)?;
735+
let mut ret = Vec::new();
736+
while len.0 > 0 {
737+
let readamt = cmp::min(len.0 as usize, MAX_BUF_SIZE);
738+
let readstart = ret.len();
739+
ret.resize(readstart + readamt, 0);
740+
r.read_exact(&mut ret[readstart..])?;
741+
len.0 -= readamt as u64;
742+
}
709743
Ok(ret)
710744
}
711745
}
@@ -1040,7 +1074,7 @@ impl Readable for () {
10401074
impl Writeable for String {
10411075
#[inline]
10421076
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1043-
(self.len() as u16).write(w)?;
1077+
U16Or64(self.len() as u64).write(w)?;
10441078
w.write_all(self.as_bytes())
10451079
}
10461080
}

0 commit comments

Comments
 (0)