Port to Boost.Core demangle()

The port removes some conditional code from pretty_name() implementation. As a side effect, this improves portability (AFAICT, the previous version wouldn't do demangling on clang).

Additionally, the commit fixes a possible buffer overrun if demangle() returns a string equal to cvr_saver_name or cvr_saver_name with trailing spaces.
This commit is contained in:
Andrey Semashev
2014-06-11 23:41:04 +04:00
parent 436ecd0b3e
commit c3a26dff9a

View File

@ -29,6 +29,7 @@
#include <typeinfo>
#include <cstring> // std::strcmp, std::strlen
#include <boost/static_assert.hpp>
#include <boost/core/demangle.hpp>
#include <boost/type_traits/is_const.hpp>
#include <boost/type_traits/is_reference.hpp>
#include <boost/type_traits/is_volatile.hpp>
@ -38,17 +39,6 @@
#include <boost/mpl/or.hpp>
#include <boost/functional/hash_fwd.hpp>
#ifdef __GNUC__
# include <cxxabi.h> // abi::__cxa_demangle
#endif
#if !defined(BOOST_MSVC)
# include <boost/assert.hpp>
# include <cstdlib> // std::free
# include <algorithm> // std::find, std::search
#endif
#if (defined(__EDG_VERSION__) && __EDG_VERSION__ < 245) \
|| (defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 744)
# include <boost/type_traits/is_signed.hpp>
@ -133,60 +123,30 @@ inline const char* stl_type_index::name() const BOOST_NOEXCEPT {
return data_->name();
}
namespace detail {
class free_at_scope_exit {
char* to_free_;
public:
explicit free_at_scope_exit(char* to_free) BOOST_NOEXCEPT
: to_free_(to_free)
{}
~free_at_scope_exit() BOOST_NOEXCEPT {
std::free(to_free_);
}
};
}
inline std::string stl_type_index::pretty_name() const {
static const char cvr_saver_name[] = "boost::typeindex::detail::cvr_saver<";
#if defined(_MSC_VER)
std::string ret = data_->name();
std::string::size_type pos_beg = ret.find(cvr_saver_name);
// In case of MSVC demangle() is a no-op, and name() already returns demangled name.
// In case of GCC and Clang (on non-Windows systems) name() returns mangled name and demangle() undecorates it.
std::string ret = core::demangle(data_->name());
std::string::size_type pos_beg = ret.find(cvr_saver_name, 0, sizeof(cvr_saver_name) - 1);
if (pos_beg == std::string::npos) {
return ret;
}
const char* begin = ret.c_str() + pos_beg + sizeof(cvr_saver_name) - 1;
const char* end = ret.c_str() + ret.size() - 1;
#else
int status = 0;
char* demang = abi::__cxa_demangle(raw_name(), NULL, 0, &status);
detail::free_at_scope_exit scope(demang);
BOOST_ASSERT(!status);
const std::size_t length = std::strlen(demang);
const char* begin = std::search(
demang, demang + length,
cvr_saver_name, cvr_saver_name + sizeof(cvr_saver_name) - 1
);
if (begin == demang + length) {
return std::string(demang, demang + length);
}
begin += sizeof(cvr_saver_name) - 1;
const char* end = demang + length - 1;
#endif
while (*begin == ' ') { // begin is zero terminated
++ begin;
}
while (end != begin && *end != '>') {
while (end > begin && *end != '>') {
-- end;
}
// we have cvr_saver_name somewhere at the start of the end
while (end != begin && *(end - 1) == ' ') {
while (end > begin && *(end - 1) == ' ') {
-- end;
}
@ -286,7 +246,7 @@ inline stl_type_index stl_type_index::type_id_with_cvr() BOOST_NOEXCEPT {
template <class T>
inline stl_type_index stl_type_index::type_id_runtime(const T& value) BOOST_NOEXCEPT {
#ifdef BOOST_NO_RTTI
#ifdef BOOST_NO_RTTI
return value.boost_type_index_type_id_runtime_();
#else
return typeid(value);
@ -295,6 +255,4 @@ inline stl_type_index stl_type_index::type_id_runtime(const T& value) BOOST_NOEX
}} // namespace boost::typeindex
#endif // BOOST_TYPE_INDEX_STL_TYPE_INDEX_HPP