C#代码没有捕获SEHExceptions

时间:2015-04-26 01:37:46

标签: c# visual-c++ c++-cli

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

  

未处理的异常:System.AccessViolationException:尝试   读或写受保护的内存。这通常表明其他   记忆已腐败。

   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进程(这是一个与遗留应用程序的桥梁)来记录错误消息并优雅地消失,而不是弹出“程序停止工作”窗口。

提前致谢,

埃内斯托

1 个答案:

答案 0 :(得分:4)

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

这通常不是你真正想要的东西。原生C或C ++代码应该由编译器直接转换为机器代码。 _set_se_translator()的MSDN文章对此做了很好的警告:

  

在托管代码(使用/ clr编译的代码)或混合本机代码和托管代码中使用_set_se_translator时,请注意翻译器仅影响在本机代码中生成的异常。托管代码中生成的任何托管异常(例如在引发System :: Exception时)都不会通过转换器函数进行路由。

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

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

public ref class NativeKiller { ... }

您现在可以看到异常翻译工作正常。