Skip to content

Commit

Permalink
Add DepthLimiter and adapt to the Read/WriteXDR (#158)
Browse files Browse the repository at this point in the history
* Add `DepthLimiter` and adapt to the Read/WriteXDR

* Remove external depth_limit dependency

* Use global constant default depth limit

* Revert "Use global constant default depth limit"

This reverts commit 6a6a6a4.

* Use pub (non-static) const DEFAULT_MAX_DEPTH_LIMIT

* fixup! Use pub (non-static) const DEFAULT_MAX_DEPTH_LIMIT

* Update test files

* Add comments

* fixup! Add comments

* fixup! Add comments

* Rename `depth` for clarity; add methods for user-passed depth limit

* Rename the constant for better clarity

* fixup! Rename the constant for better clarity

* fixup! Rename the constant for better clarity

* fixup! Rename the constant for better clarity

* Remove `RefCell`; make `leave()` fallible
  • Loading branch information
jayz22 authored Jul 14, 2023
1 parent 80e38ef commit 3113f99
Show file tree
Hide file tree
Showing 12 changed files with 5,499 additions and 2,603 deletions.
148 changes: 81 additions & 67 deletions lib/xdrgen/generators/rust.rb
Original file line number Diff line number Diff line change
Expand Up @@ -166,21 +166,21 @@ def render_enum_of_all_types(out, types)
#[cfg(feature = "std")]
#[allow(clippy::too_many_lines)]
pub fn read_xdr(v: TypeVariant, r: &mut impl Read) -> Result<Self> {
pub fn read_xdr<R: Read>(v: TypeVariant, r: &mut DepthLimitedRead<R>) -> Result<Self> {
match v {
#{types.map { |t| "TypeVariant::#{t} => Ok(Self::#{t}(Box::new(#{t}::read_xdr(r)?)))," }.join("\n")}
#{types.map { |t| "TypeVariant::#{t} => r.with_limited_depth(|r| Ok(Self::#{t}(Box::new(#{t}::read_xdr(r)?))))," }.join("\n")}
}
}
#[cfg(feature = "base64")]
pub fn read_xdr_base64(v: TypeVariant, r: &mut impl Read) -> Result<Self> {
let mut dec = base64::read::DecoderReader::new(r, base64::STANDARD);
pub fn read_xdr_base64<R: Read>(v: TypeVariant, r: &mut DepthLimitedRead<R>) -> Result<Self> {
let mut dec = DepthLimitedRead::new(base64::read::DecoderReader::new(&mut r.inner, base64::STANDARD), r.depth_remaining);
let t = Self::read_xdr(v, &mut dec)?;
Ok(t)
}
#[cfg(feature = "std")]
pub fn read_xdr_to_end(v: TypeVariant, r: &mut impl Read) -> Result<Self> {
pub fn read_xdr_to_end<R: Read>(v: TypeVariant, r: &mut DepthLimitedRead<R>) -> Result<Self> {
let s = Self::read_xdr(v, r)?;
// Check that any further reads, such as this read of one byte, read no
// data, indicating EOF. If a byte is read the data is invalid.
Expand All @@ -192,48 +192,48 @@ def render_enum_of_all_types(out, types)
}
#[cfg(feature = "base64")]
pub fn read_xdr_base64_to_end(v: TypeVariant, r: &mut impl Read) -> Result<Self> {
let mut dec = base64::read::DecoderReader::new(r, base64::STANDARD);
pub fn read_xdr_base64_to_end<R: Read>(v: TypeVariant, r: &mut DepthLimitedRead<R>) -> Result<Self> {
let mut dec = DepthLimitedRead::new(base64::read::DecoderReader::new(&mut r.inner, base64::STANDARD), r.depth_remaining);
let t = Self::read_xdr_to_end(v, &mut dec)?;
Ok(t)
}
#[cfg(feature = "std")]
#[allow(clippy::too_many_lines)]
pub fn read_xdr_iter<R: Read>(v: TypeVariant, r: &mut R) -> Box<dyn Iterator<Item=Result<Self>> + '_> {
pub fn read_xdr_iter<R: Read>(v: TypeVariant, r: &mut DepthLimitedRead<R>) -> Box<dyn Iterator<Item=Result<Self>> + '_> {
match v {
#{types.map { |t| "TypeVariant::#{t} => Box::new(ReadXdrIter::<_, #{t}>::new(r).map(|r| r.map(|t| Self::#{t}(Box::new(t)))))," }.join("\n")}
#{types.map { |t| "TypeVariant::#{t} => Box::new(ReadXdrIter::<_, #{t}>::new(&mut r.inner, r.depth_remaining).map(|r| r.map(|t| Self::#{t}(Box::new(t)))))," }.join("\n")}
}
}
#[cfg(feature = "std")]
#[allow(clippy::too_many_lines)]
pub fn read_xdr_framed_iter<R: Read>(v: TypeVariant, r: &mut R) -> Box<dyn Iterator<Item=Result<Self>> + '_> {
pub fn read_xdr_framed_iter<R: Read>(v: TypeVariant, r: &mut DepthLimitedRead<R>) -> Box<dyn Iterator<Item=Result<Self>> + '_> {
match v {
#{types.map { |t| "TypeVariant::#{t} => Box::new(ReadXdrIter::<_, Frame<#{t}>>::new(r).map(|r| r.map(|t| Self::#{t}(Box::new(t.0)))))," }.join("\n")}
#{types.map { |t| "TypeVariant::#{t} => Box::new(ReadXdrIter::<_, Frame<#{t}>>::new(&mut r.inner, r.depth_remaining).map(|r| r.map(|t| Self::#{t}(Box::new(t.0)))))," }.join("\n")}
}
}
#[cfg(feature = "base64")]
#[allow(clippy::too_many_lines)]
pub fn read_xdr_base64_iter<R: Read>(v: TypeVariant, r: &mut R) -> Box<dyn Iterator<Item=Result<Self>> + '_> {
let dec = base64::read::DecoderReader::new(r, base64::STANDARD);
pub fn read_xdr_base64_iter<R: Read>(v: TypeVariant, r: &mut DepthLimitedRead<R>) -> Box<dyn Iterator<Item=Result<Self>> + '_> {
let dec = base64::read::DecoderReader::new(&mut r.inner, base64::STANDARD);
match v {
#{types.map { |t| "TypeVariant::#{t} => Box::new(ReadXdrIter::<_, #{t}>::new(dec).map(|r| r.map(|t| Self::#{t}(Box::new(t)))))," }.join("\n")}
#{types.map { |t| "TypeVariant::#{t} => Box::new(ReadXdrIter::<_, #{t}>::new(dec, r.depth_remaining).map(|r| r.map(|t| Self::#{t}(Box::new(t)))))," }.join("\n")}
}
}
#[cfg(feature = "std")]
pub fn from_xdr<B: AsRef<[u8]>>(v: TypeVariant, bytes: B) -> Result<Self> {
let mut cursor = Cursor::new(bytes.as_ref());
let mut cursor = DepthLimitedRead::new(Cursor::new(bytes.as_ref()), DEFAULT_XDR_RW_DEPTH_LIMIT);
let t = Self::read_xdr_to_end(v, &mut cursor)?;
Ok(t)
}
#[cfg(feature = "base64")]
pub fn from_xdr_base64(v: TypeVariant, b64: String) -> Result<Self> {
let mut b64_reader = Cursor::new(b64);
let mut dec = base64::read::DecoderReader::new(&mut b64_reader, base64::STANDARD);
let mut dec = DepthLimitedRead::new(base64::read::DecoderReader::new(&mut b64_reader, base64::STANDARD), DEFAULT_XDR_RW_DEPTH_LIMIT);
let t = Self::read_xdr_to_end(v, &mut dec)?;
Ok(t)
}
Expand Down Expand Up @@ -356,22 +356,26 @@ def render_struct(out, struct)
out.puts <<-EOS.strip_heredoc
impl ReadXdr for #{name struct} {
#[cfg(feature = "std")]
fn read_xdr(r: &mut impl Read) -> Result<Self> {
Ok(Self{
#{struct.members.map do |m|
"#{field_name(m)}: #{reference_to_call(struct, m.declaration.type)}::read_xdr(r)?,"
end.join("\n")}
fn read_xdr<R: Read>(r: &mut DepthLimitedRead<R>) -> Result<Self> {
r.with_limited_depth(|r| {
Ok(Self{
#{struct.members.map do |m|
"#{field_name(m)}: #{reference_to_call(struct, m.declaration.type)}::read_xdr(r)?,"
end.join("\n")}
})
})
}
}
impl WriteXdr for #{name struct} {
#[cfg(feature = "std")]
fn write_xdr(&self, w: &mut impl Write) -> Result<()> {
#{struct.members.map do |m|
"self.#{field_name(m)}.write_xdr(w)?;"
end.join("\n")}
Ok(())
fn write_xdr<W: Write>(&self, w: &mut DepthLimitedWrite<W>) -> Result<()> {
w.with_limited_depth(|w| {
#{struct.members.map do |m|
"self.#{field_name(m)}.write_xdr(w)?;"
end.join("\n")}
Ok(())
})
}
}
EOS
Expand Down Expand Up @@ -455,18 +459,22 @@ def render_enum(out, enum)
impl ReadXdr for #{name enum} {
#[cfg(feature = "std")]
fn read_xdr(r: &mut impl Read) -> Result<Self> {
let e = i32::read_xdr(r)?;
let v: Self = e.try_into()?;
Ok(v)
fn read_xdr<R: Read>(r: &mut DepthLimitedRead<R>) -> Result<Self> {
r.with_limited_depth(|r| {
let e = i32::read_xdr(r)?;
let v: Self = e.try_into()?;
Ok(v)
})
}
}
impl WriteXdr for #{name enum} {
#[cfg(feature = "std")]
fn write_xdr(&self, w: &mut impl Write) -> Result<()> {
let i: i32 = (*self).into();
i.write_xdr(w)
fn write_xdr<W: Write>(&self, w: &mut DepthLimitedWrite<W>) -> Result<()> {
w.with_limited_depth(|w| {
let i: i32 = (*self).into();
i.write_xdr(w)
})
}
}
EOS
Expand Down Expand Up @@ -583,39 +591,43 @@ def render_union(out, union)
impl ReadXdr for #{name union} {
#[cfg(feature = "std")]
fn read_xdr(r: &mut impl Read) -> Result<Self> {
let dv: #{discriminant_type} = <#{discriminant_type} as ReadXdr>::read_xdr(r)?;
#[allow(clippy::match_same_arms, clippy::match_wildcard_for_single_variants)]
let v = match dv {
#{union_cases(union) do |case_name, arm, value|
"#{
value.nil? ? "#{discriminant_type}::#{case_name}" : "#{value}"
} => #{
arm.void? ? "Self::#{case_name}" : "Self::#{case_name}(#{reference_to_call(union, arm.type)}::read_xdr(r)?)"
},"
end.join("\n")}
#[allow(unreachable_patterns)]
_ => return Err(Error::Invalid),
};
Ok(v)
fn read_xdr<R: Read>(r: &mut DepthLimitedRead<R>) -> Result<Self> {
r.with_limited_depth(|r| {
let dv: #{discriminant_type} = <#{discriminant_type} as ReadXdr>::read_xdr(r)?;
#[allow(clippy::match_same_arms, clippy::match_wildcard_for_single_variants)]
let v = match dv {
#{union_cases(union) do |case_name, arm, value|
"#{
value.nil? ? "#{discriminant_type}::#{case_name}" : "#{value}"
} => #{
arm.void? ? "Self::#{case_name}" : "Self::#{case_name}(#{reference_to_call(union, arm.type)}::read_xdr(r)?)"
},"
end.join("\n")}
#[allow(unreachable_patterns)]
_ => return Err(Error::Invalid),
};
Ok(v)
})
}
}
impl WriteXdr for #{name union} {
#[cfg(feature = "std")]
fn write_xdr(&self, w: &mut impl Write) -> Result<()> {
self.discriminant().write_xdr(w)?;
#[allow(clippy::match_same_arms)]
match self {
#{union_cases(union) do |case_name, arm, value|
if arm.void?
"Self::#{case_name} => ().write_xdr(w)?,"
else
"Self::#{case_name}(v) => v.write_xdr(w)?,"
end
end.join("\n")}
};
Ok(())
fn write_xdr<W: Write>(&self, w: &mut DepthLimitedWrite<W>) -> Result<()> {
w.with_limited_depth(|w| {
self.discriminant().write_xdr(w)?;
#[allow(clippy::match_same_arms)]
match self {
#{union_cases(union) do |case_name, arm, value|
if arm.void?
"Self::#{case_name} => ().write_xdr(w)?,"
else
"Self::#{case_name}(v) => v.write_xdr(w)?,"
end
end.join("\n")}
};
Ok(())
})
}
}
EOS
Expand Down Expand Up @@ -694,17 +706,19 @@ def render_typedef(out, typedef)
impl ReadXdr for #{name typedef} {
#[cfg(feature = "std")]
fn read_xdr(r: &mut impl Read) -> Result<Self> {
let i = #{reference_to_call(typedef, typedef.type)}::read_xdr(r)?;
let v = #{name typedef}(i);
Ok(v)
fn read_xdr<R: Read>(r: &mut DepthLimitedRead<R>) -> Result<Self> {
r.with_limited_depth(|r| {
let i = #{reference_to_call(typedef, typedef.type)}::read_xdr(r)?;
let v = #{name typedef}(i);
Ok(v)
})
}
}
impl WriteXdr for #{name typedef} {
#[cfg(feature = "std")]
fn write_xdr(&self, w: &mut impl Write) -> Result<()> {
self.0.write_xdr(w)
fn write_xdr<W: Write>(&self, w: &mut DepthLimitedWrite<W>) -> Result<()> {
w.with_limited_depth(|w|{ self.0.write_xdr(w) })
}
}
EOS
Expand Down
63 changes: 63 additions & 0 deletions lib/xdrgen/generators/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions lib/xdrgen/generators/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ version = "0.0.0"
edition = "2021"

[dependencies]
base64 = "0.13.0"
base64 = { version = "0.13.0", optional = true }
arbitrary = { version = "1.1.3", features = ["derive"] }
hex = { version = "0.4.3", optional = true }

[features]
default = ["std"]
std = ["alloc", "base64/std"]
alloc = []
alloc = ["dep:hex"]
base64 = ["std", "dep:base64"]
Loading

0 comments on commit 3113f99

Please sign in to comment.