C++ Logo

std-proposals

Advanced search

Re: [std-proposals] std::typeid_except ( Paper Attached )

From: Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>
Date: Mon, 4 Mar 2024 10:19:40 +0000
On Sun, Mar 3, 2024 at 11:07 PM Sebastian Wittmeier wrote:
>
> The question is, whether "Microsoft could do it" and change the default
> for C structured exceptions under C++: Existing programs and libraries
> possibly rely on the current behaviour.
>
> It is a runtime setting per thread and not a setting per translation unit.
> So changing the default for a new C++ standard version would possibly
> lead to incompatibilities, when mixing standard version of TUs or
> incorporating static or dynamic libraries.
>
> The other question is, whether changing the behaviour of C structured
> exceptions is necessary at all for the proposal.


I have Microsoft Visual Studio 2022 installed here on my work laptop.
I compiled the following source file with:

    cl /std:c++20 /EHa source_file.cpp

and the executable prints out:

    Caught an unknown exception
    We have an valid exception_ptr
    0xc0000094

Here's the code:

    // compile with: /EHa
    #include <exception> // exception
    #include <iomanip> // hex, setfill, setw
    #include <iostream> // cout, endl

    void DivideByZero(void) // Throws a SEH exception
    {
        int x, y = 0;
        x = 5 / y;
    }

    int main(void)
    {
        using std::cout, std::endl, std::hex, std::setfill, std::setw;

        try
        {
            DivideByZero();
        }
        catch(std::exception const &e)
        {
            cout << e.what() << endl;
        }
        catch(...)
        {
            cout << "Caught an unknown exception" << endl;

            auto const ep = std::current_exception();

            if ( false == static_cast<bool>(ep) )
            {
                cout << "We have an invalid exception_ptr" << endl;
                return 0;
            }

            cout << "We have an valid exception_ptr" << endl;

            unsigned const &n = **(unsigned**)&ep;

            cout << "0x" << hex << setfill('0') << setw(8u) << n << endl;
        }
    }

So far, so good. So when you catch an SEH exception, the
'exception_ptr' is valid and you can get the SEH number from it. Now
let me try a more complicated program to also get the 'type_info'. The
following program is able to get the 'type_info' when you throw an
intrinsic such as "throw 58.2L", but it cannot get the 'type_info'
when an SEH exception is thrown. Therefore I think my proposed new
function 'std::typeid_except' would have to return "typeid(void)" when
it an SEH exception is caught inside a "catch(...)".

// compile with: /EHa
#include <exception> // exception
#include <iomanip> // hex, setfill, setw
#include <iostream> // cout, endl

#include <Windows.h> // AddVectoredExceptionHandler
#include <ehdata.h> // ThrowInfo

namespace std {
    namespace detail {
        thread_local std::type_info const *tl_ti = &typeid(void);
    }
    std::type_info const &current_exception_typeid(void) noexcept
    {
        return *detail::tl_ti;
    }
}

void DivideByZero(void) // Throws a SEH exception
{
    int x, y = 0;
    x = 5 / y;
}

int main(void)
{
    using std::cout, std::endl, std::hex, std::setfill, std::setw;

    try
    {
        DivideByZero();
    }
    catch(std::exception const &e)
    {
        cout << e.what() << endl;
    }
    catch(...)
    {
        cout << "Caught an unknown exception" << endl;

        auto const ep = std::current_exception();

        if ( false == static_cast<bool>(ep) )
        {
            cout << "We have an invalid exception_ptr" << endl;
            return 0;
        }

        cout << "We have an valid exception_ptr" << endl;

        unsigned const &n = **(unsigned**)&ep;

        cout << "SEH 0x" << hex << setfill('0') << setw(8u) << n << endl;

        auto &ti = std::current_exception_typeid();

        cout << "Name of type: " << ti.name() << endl;
    }

    cout << "==========================\n";

    try
    {
        throw 58.2L;
    }
    catch(std::exception const &e)
    {
        cout << e.what() << endl;
    }
    catch(...)
    {
        cout << "Caught an unknown exception" << endl;

        auto const ep = std::current_exception();

        if ( false == static_cast<bool>(ep) )
        {
            cout << "We have an invalid exception_ptr" << endl;
            return 0;
        }

        cout << "We have an valid exception_ptr" << endl;

        auto const &ti = std::current_exception_typeid();

        cout << "Name of type: " << ti.name() << endl;
    }
}

namespace detail {

using std::type_info;

type_info const *VectoredExceptionHandler_Proper(EXCEPTION_POINTERS
const *const arg)
{
    using std::uintptr_t;

    if ( nullptr == arg ) return nullptr;

    EXCEPTION_RECORD const *const pexc = arg->ExceptionRecord;

    if ( nullptr == pexc ) return nullptr;

    switch ( pexc->ExceptionCode )
    {
    case 0x40010006 /*EXCEPTION_OUTPUT_DEBUG_STRING*/:
    case 0x406D1388 /*EXCEPTION_THREAD_NAME */:
        return nullptr;
    }

    if ( 0x19930520 /* magic number */ != pexc->ExceptionInformation[0] )
        return nullptr;

    if ( pexc->NumberParameters < 3u ) return nullptr;

    uintptr_t const module = (pexc->NumberParameters >= 4u)
                             ? pexc->ExceptionInformation[3u]
                             : 0u;

    ThrowInfo const *const pthri =
        static_cast<ThrowInfo const*>(
            reinterpret_cast<void const*>(
                static_cast<uintptr_t>(pexc->ExceptionInformation[2u])));

    if ( nullptr == pthri ) return nullptr;

    if ( 0 == pthri->pCatchableTypeArray ) return nullptr;

    if ( 0u == (0xFFFFFFFFu & pthri->pCatchableTypeArray) ) return nullptr;

    _CatchableTypeArray const *const pcarr =
      static_cast<_CatchableTypeArray const *>(
        reinterpret_cast<void const*>(
          static_cast<uintptr_t>(module + (0xFFFFFFFFu &
pthri->pCatchableTypeArray))));

    if ( 0u == ( 0xFFFFFFFFu &
        reinterpret_cast<uintptr_t>(pcarr->arrayOfCatchableTypes[0u]) ) )
           return nullptr;

    CatchableType const *const pct =
      static_cast<CatchableType const*>(
        reinterpret_cast<void const*>(
          static_cast<uintptr_t>(module +
            (0xFFFFFFFFu & reinterpret_cast<uintptr_t>(
              pcarr->arrayOfCatchableTypes[0u])))));

    if ( 0u == (0xFFFFFFFFu & pct->pType) ) return nullptr;

    type_info const *const pti =
        static_cast<type_info const *>(
            reinterpret_cast<void const*>(
                static_cast<uintptr_t>(module + (0xFFFFFFFFu & pct->pType))));

    return pti;
}

long WINAPI VectoredExceptionHandler(EXCEPTION_POINTERS *const pointers)
{
    type_info const *const retval = VectoredExceptionHandler_Proper(pointers);

    if ( nullptr == retval ) std::detail::tl_ti = &typeid(void);
                        else std::detail::tl_ti = retval;

    return EXCEPTION_CONTINUE_SEARCH;
}

void *const dummy = ::AddVectoredExceptionHandler(1u, VectoredExceptionHandler);

} // close namespace 'detail'

Received on 2024-03-04 10:19:53