C# 代码未捕获 SEHExceptions

C# code not catching SEHExceptions

我有一个 C# 应用程序调用一个托管的 C++ DLL,该 DLL 故意访问无效地址;我在我的 C++ 项目中启用了 SEH Exceptions,我在我的 C++ 代码中添加了一个 _se_translator_function,我还在 SIGSEGV 发生时添加了一个信号处理程序。使用来自纯本机测试的 C++ 代码,一切正常,但是当我从 .net 应用程序调用我的 C++ 代码时,应用程序崩溃并显示:

Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

   at K.killnative() in c:\users\ebascon\documents\visual studio 2013\projects\consoleapplication3\consoleapplication4\source.cpp:line 32

这是我的 C# 控制台应用程序:

namespace ConsoleApplication3 {
    class Program {
        static void Main(string[] args) {
            try {
                var k = new NativeKiller();
                k.kill();
            }
            catch (Exception ex) {
                Console.WriteLine("Catching " + ex);
            }
        }
    }
}

这是调用的 C++/CLI 代码:

void MXXExceptionTranslator(unsigned int, struct _EXCEPTION_POINTERS*)
{
    throw std::exception("Crash happens");
}

void killnative() {
    try {
        _set_se_translator(MXXExceptionTranslator);

        signal(SIGSEGV, [](int) {
            puts("Exception");
            exit(-1);
        });

        int* p = reinterpret_cast<int*>(0xDEADBEEF);
        printf("%d\n", *p);
    }
    catch (...) { //Removing this catch does not change anything
        puts("Doing nothing");
    }
}

public ref class NativeKiller {
public:
    void kill() {
        killnative();
    }
};

你认为我做错了什么?在我现实世界的问题中,我需要这个 C++/CLI 进程(这是一个与遗留应用程序的桥梁)来记录错误消息并优雅地死去,而不是弹出 "The program stopped working" window.

提前致谢,

埃内斯托

这是一个很好的问题,它可以帮助您发现您没有正确构建代码。 C++/CLI 编译器非常强大,几乎 强大,几乎可以将任何本机代码翻译成 IL。与 C# 编译器生成的 IL 完全相同。并且它在运行时被视为相同,抖动在运行时将其转换为机器代码。

这通常不是您真正想要的。本机 C 或 C++ 代码应该由编译器直接翻译成机器代码。 _set_se_translator() 的 MSDN 文章对此做了很好的警告:

When using _set_se_translator from managed code (code compiled with /clr) or mixed native and managed code, be aware that the translator affects exceptions generated in native code only. Any managed exceptions generated in managed code (such as when raising System::Exception) are not routed through the translator function.

通常的落坑方式是在自己的源文件或库项目中单独编译native代码。但更容易的是利用 C++/CLI 编译器的能力在单个源文件中在 IL 和机器代码生成之间来回动态切换。修复:

#pragma managed(push, off)
void MXXExceptionTranslator(unsigned int, struct _EXCEPTION_POINTERS*) { ... }
void killnative() { ... }
#pragma managed(pop)

public ref class NativeKiller { ... }

现在您会看到异常转换器工作正常。