Hacker News new | past | comments | ask | show | jobs | submit login

In this specific type of Win32 API case, I can think of a way to make this safe.

It would involve looking at the function pointer in QueueUserAPC and making sure the function being called doesn't mess with the stack frame being executed on.

This function will run in the context of the called thread, in that thread's stack. NOT in the calling thread.

It's a weird execution mode where you're allowed to hijack a blocked thread and run some code in its context.

Don't know enough about Rust or the like to say if that's something that could be done in the language with attributes/annotations for a function, but it seems plausible.




Perhaps simpler would be to just not unwind C++ exceptions through non-C++ stack frames and abort instead. (You'd run into these crashes at development time, debugging them would be pretty obvious, and it'd never release like this.) This might not be viable on Windows, though, where there is a lot of both C++ and legacy C code.


As I understand this was recent stabilized in rust and is now the default behaviour.

https://blog.rust-lang.org/2024/09/05/Rust-1.81.0.html#abort...

You have to explicitly opt into unwinding like this now otherwise the program will abort.


Another possibility is to avoid it in the first place by not allowing C++ function pointers that are not marked noexcept to be passed to C functions. I filed bugs against both GCC and LLVM requesting warnings:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118263

https://github.com/llvm/llvm-project/issues/121427

If/when they are implemented, they will become errors with -Werror.


Doesn't seem all that useful unless C++ compilers will start warning about noexcept functions calling exception-throwing functions -- they don't today: https://godbolt.org/z/4qbcbxaET .


That is supposed to be handled at runtime:

  > Whenever an exception is thrown and the search for a handler ([except.handle]) encounters the outermost block of a function with a non-throwing exception specification, the function std :: terminate is invoked ([except.terminate])
https://timsong-cpp.github.io/cppwp/n4950/except.spec#5

If it is not, then there is a bug in the C++ implementation.


Catching it at runtime somewhat defeats the benefit of your approach upthread:

> Another possibility is to avoid it in the first place by not allowing C++ function pointers that are not marked noexcept to be passed to C functions.


The two would combine to avoid situations where people spend 5 days debugging like unity did.

That said, my personal preference is to use C instead of C++, which avoids the issues of exceptions breaking kernel expectations entirely.


Nothing in C can prevent your function from being abnormally unwound through (whether it's via C++ exceptions or via C longjmp()). The only real fix is "don't use C++ exceptions unless you're 100% sure that the code in between is exception-safe (and don't use C longjmp() at all outside of controlled scenarios)".


A better fix is to avoid passing pointers to C++ functions that can throw exceptions to C functions. This theoretically can be enforced by the compiler by requiring the C++ function pointers be marked noexcept.

I filed bugs against both GCC and LLVM requesting warnings:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118263

https://github.com/llvm/llvm-project/issues/121427




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: