intermixing c++ exception handling and SEH (windows)
Asked Answered
E

3

7

I have a function in which I call getaddrinfo() to get an sockaddr* which targets memory is allocated by the system. As many may know, you need to call freeaddrinfo() to free the memory allocated by getaddrinfo().

Now, in my function, there are a few places, where I may throw an exception, because some function failed. My first solution was to incorporate the freeaddrinfo() into every if-block. But that did look ugly for me, because I would have had to call it anyways before my function returns, so I came up with SEH`s try-finally...

But the problem I encountered is, that it is not allowed to code the throw-statements into the __try-block

Then, I read on the msdn and tried to swap the throw-statements into the helper function called from within the __try-block... and voila, the compiler didn´t moan it anymore...

Why is that? And is this safe? This does not make sense to me :/

Code:

void function()
{
    //...
    addrinfo* pFinal;
    __try
    {
        getaddrinfo(..., &pFinal);

        //if(DoSomething1() == FAILED)
        //  throw(exception);           //error C2712: Cannot use __try in functions that require object unwinding

        //but this works
        Helper();


        //...

    }
    __finally
    {
        freeaddrinfo();
    }
}


void Helper()
{
    throw(Exception);
}

EDIT:

tried the following and it works with throwing an integer, but does not when i use a class as an exception:

class X
{
public:
    X(){};
    ~X(){};
};


void Helper()
{
    throw(X());
}


void base()
{
    __try
        {
            std::cout << "entering __try\n";

            Helper();

            std::cout << "leaving __try\n";
        }
        __finally
        {
            std::cout << "in __finally\n";
        }
};


int _tmain(int argc, _TCHAR* argv[])
{
    try
    {
        base();
    }
    catch(int& X)
    {
        std::cout << "caught a X" << std::endl;
    }

    std::cin.get();
    return 0;
}

Why? :/

Ephraimite answered 15/7, 2011 at 14:52 Comment(0)
C
3

You could wrap the addrinfo in a class that calls getaddrinfo in the constructor and freeaddrinfo in its destructor.

That way it will always be freed, whether there is an exception thrown or not.

Commutate answered 15/7, 2011 at 15:30 Comment(0)
S
10

You can't mix the two exception types. Under the covers, C++ exceptions use SEH and your SEH exception handler could mess up the exception propogation logic. As a result, the C++ compiler won't allow you to mix them.

PS: Structured Exception Handling is almost always a VERY bad idea. Internally Microsoft has banned the use of SEH except in very limited circumstances. Any component that does use structured exception handling is automatically subject to intense code reviews (we have tools that scan code looking for its use to ensure that no cases are missed).

The problem with SEH is that it's extremely easy to accidentally introduce security vulnerabilities when using SEH.

Stillborn answered 15/7, 2011 at 15:30 Comment(4)
I have great respect for you and the great explanations you always have on your blog, but I have to disagree here. Visual C++ does mix the two types, when /EHa is used. catch (...) catches SEH and __finally executes for C++ exceptions. I'd like to know, though, are SEH handlers banned or just code that uses SEH for flow control (i.e. it synthesizes an SEH exception)? .NET code handles SEH exceptions everywhere.Eutectoid
Enabling /EHa has potential security consequences. It also disables most compiler optimizations because the compiler has to disable all code flow analysis (when /EHa is set, it tells the compiler that any instruction can cause an exception, not just method calls). Some of the legal SEH handlers are: kernel argument probing (where SEH handlers are mandatory), C++ exception handling, .Net exception handling, RPC's exception handlers and a small set of others. All of these cases are reviewed intensively.Stillborn
Do you have a reference to a blog article or the like that describes these security consequences?Eutectoid
Look for some of the articles written about the .ani vulnerability a few years ago, Michael Howard and David LeBlanc have written about it. Remember that these are potential security consequences, not direct consequences. It's possible to use /EHa properly. But it's very hard and you have to seriously know what you're doing. The biggest issue with /EHa is the performance consequences associated with the switch (and the reliability consequences associated with using SEH at all).Stillborn
C
3

You could wrap the addrinfo in a class that calls getaddrinfo in the constructor and freeaddrinfo in its destructor.

That way it will always be freed, whether there is an exception thrown or not.

Commutate answered 15/7, 2011 at 15:30 Comment(0)
E
0
catch(int& X)
{
    std::cout << "caught a X" << std::endl;
}

That doesn't catch an X, it catches an int&. Since there is no matching catch block, the exception is uncaught, stack unwinding doesn't occur, and __finally handlers don't run.

You can put catch (...) in your thread entrypoint (which is main() for the primary thread) in order to make sure that stack unwinding occurs, although some exceptions are unrecoverable, that's never true of a C++ exception.

Eutectoid answered 16/7, 2011 at 1:25 Comment(1)
I think You did not understand, or maybe I did not write it clear enough: FIRST i tried with throwing an int, AFTER that with an X... I may have intermixed the second code while handwriting it in here, pardon for thatEphraimite

© 2022 - 2024 — McMap. All rights reserved.