#So apparently try catch can get completely ignored huh...

65 messages · Page 1 of 1 (latest)

keen raven
polar vineBOT
#

When your question is answered use !solved or the button below to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

polar vineBOT
#

@keen raven

How to Ask a Programming Question

Anyone can ask a question in our programming channels. Following the guide Writing The Perfect Question is recommended.

What to Post

State your problem clearly and provide all necessary details:

  • the relevant portion of your code, or all of it
  • the expected output
  • the actual output (or the full error)
    :trophy: Gold Standard: Minimal Reproducible Example
Where to Post

Provide the relevant code in the message, and format it nicely with a code block*. If it's too much for one message, you can upload it:

  • Compiler Explorer for most C and C++ snippets
  • OnlineGDB for interaction, debugging
    :no_entry: Do not post screenshots, let alone photos of your screen!
carmine halo
#

Try catch isn't being ignored here.

keen raven
# carmine halo Try catch isn't being ignored here.

in the throw statement, after the expression is deep copied, the debugger shows that the program steps into the function I linked, that function
runs __aligned_malloc_with_fallback, and if that allocation fails, we get std::terminate

#

so try-catch can fail to catch what the developer expected

#

how does this make sense?

carmine halo
# keen raven in the throw statement, after the expression is deep copied, the debugger shows ...

An allocation failure is a critical failure. The catch is not being ignored because the throw doesn't actually happen - this failure happens too early on in the exception internals that get triggered when __cxa_throw is called. The best thing for the implementation to do here is exit out, which is what it does. Arguably the implementation should use an abnormal termination, but they choose to go the route of std::terminate so that resources are cleaned up properly.

keen raven
#

if std::bad_alloc is supposed to the thrown and caught to handle out of memory errors, but here throwing std::bad_alloc can lead to std::terminate being called, this is a contradiction

carmine halo
keen raven
carmine halo
#

std::bad_alloc⁩ is tiny, and might not need allocation at all keep in mind (it can be placed in EH storage)

keen raven
carmine halo
#

I'm not sure what you're trying to get from this conversation

keen raven
#

like, can we create a thread-local global buffer of char elements with fixed length to bypass malloc when running throw something?

carmine halo
#

If an implementation needs to allocate space for std::bad_alloc but can't, that's a catestrophic failure that can't be recovered from. This is legal. This is sensible. There is no need to work around it.

carmine halo
keen raven
carmine halo
#

Error handling

bold zodiac
#

std::bad_alloc by itself is just a regular exception type, and not necessarily caused by critical allocation failures (custom allocators that operate with a set of contraints can choose to throw it to be consistent)

#

plus, if even the smallest of exception objects that std::bad_alloc is can't be allocated then something has gone really wrong

woven isle
#

@keen raven just use MSVC,
exceptions are not heap allocated there 😎
(oh no but what if we stack overflow when allocating the exception :O)

keen raven
keen raven
woven isle
keen raven
keen raven
woven isle
#

it puts the exception on the stack, that's it

keen raven
woven isle
#

just don't destroy it

#

like

#

ez

keen raven
woven isle
#

by being the compiler?

#

you're msvc, you know how your stack unwinding works

#

put the exception object somewhere where stack unwinding doesn't know about it and can't unwind it

#

ez

keen raven
woven isle
#

just put it after the end of the stack

keen raven
#

do you just not know the assembler details or are you just hiding the answer?

woven isle
#

I know nothing about the implementation details, but it seems easy to me

#

the stack grows

#

when unwinding, you're un-growing it

#

so just put it somewhere deep down beyond the last stackframe or something?

#

maybe it's not that easy but idk 🤷

keen raven
woven isle
#

I mean I think it should be easy, because the compiler is the one emitting the destructor invocations in the first place,
so just don't do it for the exception object,
then stack unwinding can't clean it up

keen raven
woven isle
#

🤷

keen raven
# woven isle 🤷

there's no way msvc++ are that dumb, there's something else hidden in here

woven isle
#

https://accu.org/journals/overload/12/63/orr_245/
this article seems to try to explain it

The upshot is that, when the catch body is executed, the complete stack down to the location of the throw is still available in memory. The raw stack pointer will only be reset when the body of the stack completes, and before this point the call stack will not be touched. So if we can obtain the address of the context record that was passed into each exception handler as the third argument, the pointer will still be valid inside the body of the catch .

carmine halo
keen raven
# woven isle https://accu.org/journals/overload/12/63/orr_245/ this article seems to try to e...
One key thing about the way MSVC exception handling works is that it involves making extra calls down the stack. At point (2) the C++ runtime calls RaiseException , which snapshots the exception and thread state and then it in turn calls the code to work along the exception chain calling exception handlers.

So, do you have the source code of RaiseException somewhere?
The article author from 2004 suggests readers to go and read the cited sources which include, a dead link
[Pietrek1] Matt Pietrek, A Crash Course on the Depths of Win32™ Structured Exception Handling , http://www.microsoft.com/msj/0197/Exception/Exception.aspx
and a large book about assembler
[Gordon] Jeremy Gordon, Win32 Exception handling for assembler programmers , http://www.jorgon.freeserve.co.uk/Except/Except.htm

#

With MinGW-g++.exe I see this:

Breakpoint 2, 0x0000000000419cc0 in malloc ()
(gdb) bt
#0  0x0000000000419cc0 in malloc ()
#1  0x000000000040f883 in __shmem_grab (name=<optimized out>, size=8, initfunc=0x4718b0 <__shmem_init_init>)
    at ../../../../../src/gcc-4.9.2/libgcc/../libgcc/config/i386/shmem-win32.c:79
#2  0x00000000004712b8 in __cxa_get_globals ()
#3  0x0000000000471675 in __cxa_throw ()
#4  0x00000000004015ba in f1 () at main.cpp:607
#5  0x000000000040164a in main () at main.cpp:615
(gdb)

which based on the __cxa prefix are definitely not running RaiseException, these are just GCC-s re-written algorithm for Windows

polar vineBOT
#

This question is being automatically marked as stale.
If your question has been answered, type !solved.
If your question is not answered feel free to bump the post or re-ask.
Take a look at !howto ask for tips on improving your question.

keen raven
#

The insanity of windows is that, when an exception is thrown the goddamn windows kernel gets involved in capturing that thing and selecting an appropriate exception handler, in some kind of horrific singly linked list embedded in the stack frame

#

I cannot evaluate if VirtualAlloc is used somewhere in there, a.k.a. if we again depend on the heap

#

so, I guess I have reached my skill limits

#

!solved

polar vineBOT
#

Thank you and let us know if you have any more questions!

This thread is now set to auto-hide after an hour of inactivity