C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Extend std::type_info with more information

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Wed, 10 Apr 2024 16:47:51 +0100
On Wed, Apr 10, 2024 at 5:12 AM Thiago Macieira wrote:
>
> We're still missing the motivation. Why have this information?


We want to add a method called "get_base" to "std::any" to check if
the contained object has a particular base class. That's one use case
that more than one person has asked for. But in order to implement
"get_base" in "std::any" without causing an ABI break, we need to get
all the required info from the 'std::type_info'. So we need to beef
out 'std::type_info' with what's available on Itanium and Microsoft.
Itanium's well documented and I already made a Godbolt for it:

    https://godbolt.org/z/dcvGP5cjn

Than you to Sebastian for all the links you gave me, I was able to
learn a lot about how Microsoft implements 'std::type_info'. Having
looked at all those Microsoft links though, and having emailed one or
two people, there's a missing link -- we can get the
RTTICompleteObjectLocator from the std::type_info, but I haven't seen
where anyone can get the RTTICompleteObjectLocator from the
std::type_info. So just now I've written a function that I think will
work in every case (see code below).

So now I'm going to find the commonalities between Itanium and
Microsoft, and write them into my paper. By the way both ABI's can
give you a list of the type_info's of all the base classes.

    _RTTICompleteObjectLocator const *GetLocator(std::type_info const
*const pti) noexcept
    {
        using std::int32_t, std::uintptr_t;

        // Just in case 'pti' is an unaligned
        // address, subtract bytes to align it
        uintptr_t addr = reinterpret_cast<uintptr_t>(static_cast<void
const*>(pti));
        addr -= addr % alignof(uint32_t);

        // Now we have an aligned address
        int32_t const *p = static_cast<int32_t*>(reinterpret_cast<void*>(addr));

        for ( --p; ; --p )
        {
            // If we have found the _RTTICompleteObjectLocator,
            // the pointer is pointing to its last element,
            // so we subtract 20 bytes to bring the pointer
            // to the beginning of the _RTTICompleteObjectLocator
            _RTTICompleteObjectLocator const &locator
                = *(_RTTICompleteObjectLocator*)(p - 5);

            // If we have found the _RTTICompleteObjectLocator,
            // we can calculate where we expect the type_info
            // to be located at:
            char const *const p_expected_type_info =
                  (char*)&locator + locator.pTypeDescriptor - locator.pSelf;

            // Now let's see if we've really found it
            if ( (char*)pti != p_expected_type_info ) continue;

            // Looks like we found it! But let's just
            // perform a few more checks to be sure:
            if ( COL_SIG_REV1 != locator.signature ) continue;

            // Let's make sure the hierarchy struct
            // is where it's supposed to be
            _RTTIClassHierarchyDescriptor const &classdesc =
*(_RTTIClassHierarchyDescriptor*)(
                (char*)&locator
                + locator.pClassDescriptor
                - locator.pSelf);

            // Hierarchy struct should always have
            // a signature set to 0
            if ( 0u != classdesc.signature ) continue;

            // The hierarchy attributes are limited
            // in what they can be set to
            switch ( classdesc.attributes )
            {
            default: continue;
            case 0u:
            case CHD_MULTINH:
            case CHD_VIRTINH:
            case CHD_AMBIGUOUS: ;
            }

            // Ok we've done enough checking, we've found the RTTI
            return &locator;
        }
    }

Received on 2024-04-10 15:48:05