cpp_demangle icon indicating copy to clipboard operation
cpp_demangle copied to clipboard

Demangle failure with dragonbox symbol

Open scoopr opened this issue 3 years ago • 4 comments

Hello!

I noticed a case where the demangling fails, but where (llvm/apple) c++filt seems to work, with this beauty: __ZZZN3jkj9dragonbox10to_decimalIfNS0_20default_float_traitsIfEEJNS0_6detail11policy_impl4sign6ignoreENS5_13trailing_zero6removeEEEEDaNS0_23signed_significand_bitsIT_T0_EEjDpT1_ENKUlSC_E_clINS5_26decimal_to_binary_rounding15nearest_to_evenEEESA_SC_ENKUlDpT_E_clIJEEESA_SM_

A self contained test could be

fn main() -> Result<(),std::fmt::Error>{
    let mangled = "__ZZZN3jkj9dragonbox10to_decimalIfNS0_20default_float_traitsIfEEJNS0_6detail11policy_impl4sign6ignoreENS5_13trailing_zero6removeEEEEDaNS0_23signed_significand_bitsIT_T0_EEjDpT1_ENKUlSC_E_clINS5_26decimal_to_binary_rounding15nearest_to_evenEEESA_SC_ENKUlDpT_E_clIJEEESA_SM_";
    let sym = cpp_demangle::Symbol::new(mangled).unwrap();
    let demangled = sym.demangle(&Default::default())?;
    println!("Demangled: {}", demangled);
    Ok(())
}

And that just fails with Error: Error.

c++filt output for me is:

jkj::dragonbox::signed_significand_bits jkj::dragonbox::signed_significand_bits auto jkj::dragonbox::to_decimal<float, jkj::dragonbox::default_float_traits<float>, jkj::dragonbox::detail::policy_impl::sign::ignore, jkj::dragonbox::detail::policy_impl::trailing_zero::remove>(jkj::dragonbox::signed_significand_bits<float, jkj::dragonbox::default_float_traits<float> >, unsigned int, jkj::dragonbox::detail::policy_impl::sign::ignore, jkj::dragonbox::detail::policy_impl::trailing_zero::remove)::'lambda'(jkj::dragonbox::default_float_traits<float>)::operator()<jkj::dragonbox::detail::policy_impl::decimal_to_binary_rounding::nearest_to_even>(jkj::dragonbox::default_float_traits<float>) const::'lambda'(auto...)::operator()<>('lambda'(auto...)) const

And finally attempt to minimise the source of the symbol for proof that I didn't just conjure it up myself. Steps:

git clone https://github.com/jk-jeon/dragonbox.git
vim dragonbox.cpp
clang -std=c++17  -c dragonbox.cpp
nm dragonbox.o | grep __ZZZ

where the dragonbox.cpp contents being:

#include "dragonbox/include/dragonbox/dragonbox.h"

void dragon_test() {
  jkj::dragonbox::float_bits<float> br(0.0f);
  auto const exponent_bits = br.extract_exponent_bits();
  auto const s = br.remove_exponent_bits(exponent_bits);

  auto result = jkj::dragonbox::to_decimal(
      s, exponent_bits, jkj::dragonbox::policy::sign::ignore,
      jkj::dragonbox::policy::trailing_zero::remove);
}

Fiddling with the DemangleOptions didn't seem to affect the outcome.

I wonder if it is possible to make the demangler "fool proof" on valid input, or should there perhaps be some "lossy mode", where it demangles as much as it can, but bails out gracefully giving partial result, for when I don't have too strict needs.

scoopr avatar Jun 10 '22 15:06 scoopr

llvm-cxxfilt (built from rev 82fcd7397a5939a9f0148513cc7b6883a00a16b0) doesn't demangle this for me.

khuey avatar Jun 11 '22 15:06 khuey

Hm, both the tools that come from xcode (xcode 13.4.1, c++filt claims to be 13.1.6), and homebrew installed (llvm/clang 13.0.1) seem to demangle it just fine. And these are the latest "stable" versions that I can easily install right now. I wonder if the mangling has then changed in later versions

scoopr avatar Jun 13 '22 07:06 scoopr

I followed the instructions you provided using clang's tip and the symbol produced now appears to be

_ZZZN3jkj9dragonbox10to_decimalIfNS0_20default_float_traitsIfEEJNS0_6detail11policy_impl4sign6ignoreENS5_13trailing_zero6removeEEEEDaNS0_23signed_significand_bitsIT_T0_EEjDpT1_ENKUlSB_E_clINS5_26decimal_to_binary_rounding15nearest_to_evenEEEDaSB_ENKUlDpT_E_clIJEEEDaSL_

llvm-cxxfilt produces

auto auto auto jkj::dragonbox::to_decimal<float, jkj::dragonbox::default_float_traits<float>, jkj::dragonbox::detail::policy_impl::sign::ignore, jkj::dragonbox::detail::policy_impl::trailing_zero::remove>(jkj::dragonbox::signed_significand_bits<float, jkj::dragonbox::default_float_traits<float>>, unsigned int, jkj::dragonbox::detail::policy_impl::sign::ignore, jkj::dragonbox::detail::policy_impl::trailing_zero::remove)::'lambda'(float)::operator()<jkj::dragonbox::detail::policy_impl::decimal_to_binary_rounding::nearest_to_even>(float) const::'lambda'(auto...)::operator()<>(auto...) const

cpp_demangle produces

auto auto auto jkj::dragonbox::to_decimal<float, jkj::dragonbox::default_float_traits<float>, jkj::dragonbox::detail::policy_impl::sign::ignore, jkj::dragonbox::detail::policy_impl::trailing_zero::remove>(jkj::dragonbox::signed_significand_bits<float, jkj::dragonbox::default_float_traits<float> >, unsigned int, jkj::dragonbox::detail::policy_impl::sign::ignore, jkj::dragonbox::detail::policy_impl::trailing_zero::remove)::{lambda(auto:1)#1}::operator()<jkj::dragonbox::detail::policy_impl::decimal_to_binary_rounding::nearest_to_even>(jkj::dragonbox::detail::policy_impl::decimal_to_binary_rounding::nearest_to_even) const::{lambda(auto:1)#1}::operator()<>() const

(libiberty does not parse this succesfully)

khuey avatar Jun 13 '22 21:06 khuey

Fixing the incorrect lambda parameters here is pretty tricky, I think it's going to require some serious refactoring.

khuey avatar Jun 14 '22 14:06 khuey