Skip to content

Commit d0c8b14

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 d0c8b14

File tree

1 file changed

+56
-18
lines changed

1 file changed

+56
-18
lines changed

lightning/src/util/ser.rs

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,39 @@ 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 but treats 0xffff as "read eight more bytes".
390+
///
391+
/// To ensure we only have one valid encoding per value, we add 0xffff to values written as eight
392+
/// bytes. Thus, 0xfffe is serialized as 0xfffe, whereas 0xffff is serialized as
393+
/// 0xffff0000000000000000 (i.e. read-eight-bytes then zero).
394+
struct U16OrU64(pub u64);
395+
impl Writeable for U16OrU64 {
396+
#[inline]
397+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
398+
if self.0 < 0xffff {
399+
(self.0 as u16).write(writer)
400+
} else {
401+
0xffffu16.write(writer)?;
402+
(self.0 - 0xffff).write(writer)
403+
}
404+
}
405+
}
406+
407+
impl Readable for U16OrU64 {
408+
#[inline]
409+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
410+
let mut val: u64 = <u16 as Readable>::read(r)? as u64;
411+
if val == 0xffff {
412+
val = <u64 as Readable>::read(r)?
413+
.checked_add(0xffff).ok_or(DecodeError::InvalidValue)?;
414+
}
415+
Ok(U16OrU64(val))
416+
}
417+
}
418+
386419
/// In TLV we occasionally send fields which only consist of, or potentially end with, a
387420
/// variable-length integer which is simply truncated by skipping high zero bytes. This type
388421
/// encapsulates such integers implementing [`Readable`]/[`Writeable`] for them.
@@ -597,7 +630,7 @@ macro_rules! impl_for_map {
597630
{
598631
#[inline]
599632
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
600-
(self.len() as u16).write(w)?;
633+
U16OrU64(self.len() as u64).write(w)?;
601634
for (key, value) in self.iter() {
602635
key.write(w)?;
603636
value.write(w)?;
@@ -611,9 +644,9 @@ macro_rules! impl_for_map {
611644
{
612645
#[inline]
613646
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 {
647+
let len: U16OrU64 = Readable::read(r)?;
648+
let mut ret = $constr(len.0 as usize);
649+
for _ in 0..len.0 {
617650
let k = K::read(r)?;
618651
let v_opt = V::read(r)?;
619652
if let Some(v) = v_opt {
@@ -637,7 +670,7 @@ where T: Writeable + Eq + Hash
637670
{
638671
#[inline]
639672
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
640-
(self.len() as u16).write(w)?;
673+
U16OrU64(self.len() as u64).write(w)?;
641674
for item in self.iter() {
642675
item.write(w)?;
643676
}
@@ -650,9 +683,9 @@ where T: Readable + Eq + Hash
650683
{
651684
#[inline]
652685
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 {
686+
let len: U16OrU64 = Readable::read(r)?;
687+
let mut ret = HashSet::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<T>()));
688+
for _ in 0..len.0 {
656689
if !ret.insert(T::read(r)?) {
657690
return Err(DecodeError::InvalidValue)
658691
}
@@ -667,7 +700,7 @@ macro_rules! impl_for_vec {
667700
impl<$($name : Writeable),*> Writeable for Vec<$ty> {
668701
#[inline]
669702
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
670-
(self.len() as u16).write(w)?;
703+
U16OrU64(self.len() as u64).write(w)?;
671704
for elem in self.iter() {
672705
elem.write(w)?;
673706
}
@@ -678,9 +711,9 @@ macro_rules! impl_for_vec {
678711
impl<$($name : Readable),*> Readable for Vec<$ty> {
679712
#[inline]
680713
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 {
714+
let len: U16OrU64 = Readable::read(r)?;
715+
let mut ret = Vec::with_capacity(cmp::min(len.0 as usize, MAX_BUF_SIZE / core::mem::size_of::<$ty>()));
716+
for _ in 0..len.0 {
684717
if let Some(val) = MaybeReadable::read(r)? {
685718
ret.push(val);
686719
}
@@ -694,18 +727,23 @@ macro_rules! impl_for_vec {
694727
impl Writeable for Vec<u8> {
695728
#[inline]
696729
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
697-
(self.len() as u16).write(w)?;
730+
U16OrU64(self.len() as u64).write(w)?;
698731
w.write_all(&self)
699732
}
700733
}
701734

702735
impl Readable for Vec<u8> {
703736
#[inline]
704737
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)?;
738+
let mut len: U16OrU64 = Readable::read(r)?;
739+
let mut ret = Vec::new();
740+
while len.0 > 0 {
741+
let readamt = cmp::min(len.0 as usize, MAX_BUF_SIZE);
742+
let readstart = ret.len();
743+
ret.resize(readstart + readamt, 0);
744+
r.read_exact(&mut ret[readstart..])?;
745+
len.0 -= readamt as u64;
746+
}
709747
Ok(ret)
710748
}
711749
}
@@ -1040,7 +1078,7 @@ impl Readable for () {
10401078
impl Writeable for String {
10411079
#[inline]
10421080
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1043-
(self.len() as u16).write(w)?;
1081+
U16OrU64(self.len() as u64).write(w)?;
10441082
w.write_all(self.as_bytes())
10451083
}
10461084
}

0 commit comments

Comments
 (0)