Skip to content

Commit 3e9727b

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 3e9727b

File tree

1 file changed

+57
-18
lines changed

1 file changed

+57
-18
lines changed

lightning/src/util/ser.rs

+57-18
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,40 @@ 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 that is backwards-compatible for values < 0xffff. We treat 0xffff as
390+
/// "read eight more bytes".
391+
///
392+
/// To ensure we only have one valid encoding per value, we add 0xffff to values written as eight
393+
/// bytes. Thus, 0xfffe is serialized as 0xfffe, whereas 0xffff is serialized as
394+
/// 0xffff0000000000000000 (i.e. read-eight-bytes then zero).
395+
struct CollectionLength(pub u64);
396+
impl Writeable for CollectionLength {
397+
#[inline]
398+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
399+
if self.0 < 0xffff {
400+
(self.0 as u16).write(writer)
401+
} else {
402+
0xffffu16.write(writer)?;
403+
(self.0 - 0xffff).write(writer)
404+
}
405+
}
406+
}
407+
408+
impl Readable for CollectionLength {
409+
#[inline]
410+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
411+
let mut val: u64 = <u16 as Readable>::read(r)? as u64;
412+
if val == 0xffff {
413+
val = <u64 as Readable>::read(r)?
414+
.checked_add(0xffff).ok_or(DecodeError::InvalidValue)?;
415+
}
416+
Ok(CollectionLength(val))
417+
}
418+
}
419+
386420
/// In TLV we occasionally send fields which only consist of, or potentially end with, a
387421
/// variable-length integer which is simply truncated by skipping high zero bytes. This type
388422
/// encapsulates such integers implementing [`Readable`]/[`Writeable`] for them.
@@ -597,7 +631,7 @@ macro_rules! impl_for_map {
597631
{
598632
#[inline]
599633
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
600-
(self.len() as u16).write(w)?;
634+
CollectionLength(self.len() as u64).write(w)?;
601635
for (key, value) in self.iter() {
602636
key.write(w)?;
603637
value.write(w)?;
@@ -611,9 +645,9 @@ macro_rules! impl_for_map {
611645
{
612646
#[inline]
613647
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 {
648+
let len: CollectionLength = Readable::read(r)?;
649+
let mut ret = $constr(len.0 as usize);
650+
for _ in 0..len.0 {
617651
let k = K::read(r)?;
618652
let v_opt = V::read(r)?;
619653
if let Some(v) = v_opt {
@@ -637,7 +671,7 @@ where T: Writeable + Eq + Hash
637671
{
638672
#[inline]
639673
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
640-
(self.len() as u16).write(w)?;
674+
CollectionLength(self.len() as u64).write(w)?;
641675
for item in self.iter() {
642676
item.write(w)?;
643677
}
@@ -650,9 +684,9 @@ where T: Readable + Eq + Hash
650684
{
651685
#[inline]
652686
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 {
687+
let len: CollectionLength = Readable::read(r)?;
688+
let mut ret = HashSet::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<T>()));
689+
for _ in 0..len.0 {
656690
if !ret.insert(T::read(r)?) {
657691
return Err(DecodeError::InvalidValue)
658692
}
@@ -667,7 +701,7 @@ macro_rules! impl_for_vec {
667701
impl<$($name : Writeable),*> Writeable for Vec<$ty> {
668702
#[inline]
669703
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
670-
(self.len() as u16).write(w)?;
704+
CollectionLength(self.len() as u64).write(w)?;
671705
for elem in self.iter() {
672706
elem.write(w)?;
673707
}
@@ -678,9 +712,9 @@ macro_rules! impl_for_vec {
678712
impl<$($name : Readable),*> Readable for Vec<$ty> {
679713
#[inline]
680714
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 {
715+
let len: CollectionLength = Readable::read(r)?;
716+
let mut ret = Vec::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<$ty>()));
717+
for _ in 0..len.0 {
684718
if let Some(val) = MaybeReadable::read(r)? {
685719
ret.push(val);
686720
}
@@ -694,18 +728,23 @@ macro_rules! impl_for_vec {
694728
impl Writeable for Vec<u8> {
695729
#[inline]
696730
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
697-
(self.len() as u16).write(w)?;
731+
CollectionLength(self.len() as u64).write(w)?;
698732
w.write_all(&self)
699733
}
700734
}
701735

702736
impl Readable for Vec<u8> {
703737
#[inline]
704738
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)?;
739+
let mut len: CollectionLength = Readable::read(r)?;
740+
let mut ret = Vec::new();
741+
while len.0 > 0 {
742+
let readamt = cmp::min(len.0 as usize, MAX_BUF_SIZE);
743+
let readstart = ret.len();
744+
ret.resize(readstart + readamt, 0);
745+
r.read_exact(&mut ret[readstart..])?;
746+
len.0 -= readamt as u64;
747+
}
709748
Ok(ret)
710749
}
711750
}
@@ -1040,7 +1079,7 @@ impl Readable for () {
10401079
impl Writeable for String {
10411080
#[inline]
10421081
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1043-
(self.len() as u16).write(w)?;
1082+
CollectionLength(self.len() as u64).write(w)?;
10441083
w.write_all(self.as_bytes())
10451084
}
10461085
}

0 commit comments

Comments
 (0)