Skip to content

Commit

Permalink
fix: Introduce bounded demangling in an attempt to fix unbounded memo…
Browse files Browse the repository at this point in the history
…ry growth (#481)
  • Loading branch information
Swatinem committed Jan 10, 2022
1 parent b34e232 commit 50a4d2e
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
39 changes: 35 additions & 4 deletions symbolic-demangle/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,33 @@ fn strip_hash_suffix(ident: &str) -> &str {
ident
}

struct BoundedString {
str: String,
bound: usize,
}

impl BoundedString {
fn new(bound: usize) -> Self {
Self {
str: String::new(),
bound,
}
}

pub fn into_inner(self) -> String {
self.str
}
}

impl std::fmt::Write for BoundedString {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
if self.str.len().saturating_add(s.len()) > self.bound {
return Err(std::fmt::Error);
}
self.str.write_str(s)
}
}

fn try_demangle_cpp(ident: &str, opts: DemangleOptions) -> Option<String> {
if is_maybe_msvc(ident) {
return try_demangle_msvc(ident, opts);
Expand Down Expand Up @@ -231,10 +258,14 @@ fn try_demangle_cpp(ident: &str, opts: DemangleOptions) -> Option<String> {
cpp_options = cpp_options.no_return_type();
}

match symbol.demangle(&cpp_options) {
Ok(demangled) => Some(demangled),
Err(_) => None,
}
// Bound the maximum output string, as a huge number of substitutions could potentially
// lead to a "Billion laughs attack".
let mut buf = BoundedString::new(4096);

symbol
.structured_demangle(&mut buf, &cpp_options)
.ok()
.map(|_| buf.into_inner())
}
#[cfg(not(feature = "cpp"))]
{
Expand Down
11 changes: 11 additions & 0 deletions symbolic-demangle/tests/test_cpp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,14 @@ fn test_deep_recursion() {
"boost::variant<int, long long, unsigned int, double, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::basic_string_view<char, std::char_traits<char> >, long, unsigned long, long long, unsigned long long, boost::filesystem::path>::assigner::result_type boost::detail::variant::visitation_impl<mpl_::int_<0>, boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<(long)12>, int, boost::mpl::l_item<mpl_::long_<(long)11>, long long, boost::mpl::l_item<mpl_::long_<(long)10>, unsigned int, boost::mpl::l_item<mpl_::long_<(long)9>, double, boost::mpl::l_item<mpl_::long_<(long)8>, bool, boost::mpl::l_item<mpl_::long_<(long)7>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::mpl::l_item<mpl_::long_<(long)6>, boost::basic_string_view<char, std::char_traits<char> >, boost::mpl::l_item<mpl_::long_<(long)5>, long, boost::mpl::l_item<mpl_::long_<(long)4>, unsigned long, boost::mpl::l_item<mpl_::long_<(long)3>, long long, boost::mpl::l_item<mpl_::long_<(long)2>, unsigned long long, boost::mpl::l_item<mpl_::long_<(long)1>, boost::filesystem::path, boost::mpl::l_end> > > > > > > > > > > > >, boost::mpl::l_iter<boost::mpl::l_end> >, boost::variant<int, long long, unsigned int, double, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::basic_string_view<char, std::char_traits<char> >, long, unsigned long, long long, unsigned long long, boost::filesystem::path>::assigner, void const*, boost::variant<int, long long, unsigned int, double, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::basic_string_view<char, std::char_traits<char> >, long, unsigned long, long long, unsigned long long, boost::filesystem::path>::has_fallback_type_>(int, int, boost::variant<int, long long, unsigned int, double, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::basic_string_view<char, std::char_traits<char> >, long, unsigned long, long long, unsigned long long, boost::filesystem::path>::assigner&, void const*, mpl_::bool_<false>, boost::variant<int, long long, unsigned int, double, bool, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::basic_string_view<char, std::char_traits<char> >, long, unsigned long, long long, unsigned long long, boost::filesystem::path>::has_fallback_type_, mpl_::int_<0>*, boost::detail::variant::visitation_impl_step<boost::mpl::l_iter<boost::mpl::l_item<mpl_::long_<(long)12>, int, boost::mpl::l_item<mpl_::long_<(long)11>, long long, boost::mpl::l_item<mpl_::long_<(long)10>, unsigned int, boost::mpl::l_item<mpl_::long_<(long)9>, double, boost::mpl::l_item<mpl_::long_<(long)8>, bool, boost::mpl::l_item<mpl_::long_<(long)7>, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, boost::mpl::l_item<mpl_::long_<(long)6>, boost::basic_string_view<char, std::char_traits<char> >, boost::mpl::l_item<mpl_::long_<(long)5>, long, boost::mpl::l_item<mpl_::long_<(long)4>, unsigned long, boost::mpl::l_item<mpl_::long_<(long)3>, long long, boost::mpl::l_item<mpl_::long_<(long)2>, unsigned long long, boost::mpl::l_item<mpl_::long_<(long)1>, boost::filesystem::path, boost::mpl::l_end> > > > > > > > > > > > >, boost::mpl::l_iter<boost::mpl::l_end> >*)"
});
}

// See https://github.com/getsentry/symbolic/issues/477
// Not fully fixed, so skip for now :-(
// #[test]
// fn test_bounded_buf() {
// let s = "_ZUlzjjlZZL1zStUlSt7j_Z3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjfjzL4t3kjIIjfjtUlSt7j_Z3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjfjzL4t3kjIIjfjzL4t7IjIjjzjjzSt7j_Z3kjIIjfjzStfjzSt7j_ZA3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjfjzL4t3kjIIjzL4t7IjIjjzjjzSt7j_Z3kjIIjfjzStfjzSt7j_ZA3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjIjL1vfIIEEEjzjjfjzSt7j_Z3kjIIjfjzL4t3kjIIjfjzL4t7IjIjL1vfIIEEEjzjjSI";
// assert_eq!(
// symbolic_demangle::demangle(s),
// std::borrow::Cow::Borrowed(s)
// );
// }

0 comments on commit 50a4d2e

Please sign in to comment.