如何在外部线程中解决 "error C2712: Cannot use __try in functions that require object unwinding"?
How to workaround "error C2712: Cannot use __try in functions that require object unwinding" in a foreign thread?
我正在使用一个库(oatpp
网络服务框架)来启动调用我的处理程序的线程。所以我无法控制要在其中插入 __try
...__except
的线程的最外层代码(我需要它来进行核心转储)。
处理程序实现如下所示:
shared_ptr<oatpp::web::server::HttpRequestHandler::OutgoingResponse> DownloadRequestHandler::handle(
const std::shared_ptr<IncomingRequest>& request)
{
__try {
return handleGuarded(request);
}
__except (Debugging::GenerateDump(GetExceptionInformation(), GetExceptionCode())) {
quick_exit(4);
}
}
所以关键是这个方法需要转发从守护方法返回的响应对象,这个对象(shared_ptr
)是不可展开的。因此,我得到 error C2712: Cannot use __try in functions that require object unwinding
.
能否就如何解决此问题提出建议?
到目前为止,我提出了以下涉及 3 个中间函数的解决方案。欢迎更简洁的解决方案!
shared_ptr<oatpp::web::server::HttpRequestHandler::OutgoingResponse> DownloadRequestHandler::handle(
const std::shared_ptr<IncomingRequest>& request)
{
shared_ptr<oatpp::web::server::HttpRequestHandler::OutgoingResponse> response;
handleGuarded1(request, response);
return response;
}
void DownloadRequestHandler::handleGuarded1(const std::shared_ptr<IncomingRequest>& request,
std::shared_ptr<OutgoingResponse>& response)
{
__try {
handleGuarded2(request, response);
}
__except (Debugging::GenerateDump(GetExceptionInformation(), GetExceptionCode())) {
quick_exit(4);
}
}
void DownloadRequestHandler::handleGuarded2(const std::shared_ptr<IncomingRequest>& request,
std::shared_ptr<OutgoingResponse>& response)
{
response = handleGuarded(request);
}
shared_ptr<oatpp::web::server::HttpRequestHandler::OutgoingResponse> DownloadRequestHandler::handleGuarded(
const std::shared_ptr<IncomingRequest>& request)
{
// Do the actual work...
}
我会提出两个选项:
1) 扩展或实现您自己的 HttpConnectionHandler and spawn threads the way you want. For this, you need to override the handleConnection 方法。
像这样:
void handleConnection(const std::shared_ptr<oatpp::data::stream::IOStream>& connection,
const std::shared_ptr<const ParameterMap>& params) override {
...
std::thread t([m_components, connection]{
HttpProcessor::Task task(m_components, connection)
__try {
task.run(); // run guarded
__except (Debugging::GenerateDump(GetExceptionInformation(), GetExceptionCode())) {
quick_exit(4);
}
})
...
}
其余代码只需复制粘贴即可。目前,m_components
var 是 HttpConnectionHandler
的私有成员,这会阻止您直接从 HttpConnectionHandler
继承,但您可以创建 PR 以使其受到保护 - 因此您需要仅覆盖一种方法。
这种方法的优点是,在此级别处理异常使您能够使用 oatpp ApiController
及其所有请求映射。
缺点 - 如果发生核心转储,您将无法 return 响应客户端。
2) 第二个选项是为 oatpp 创建一个 PR,以添加一个编译器选项,用于在 HttpProcessor
中添加一个额外的 __try __except
块
因此可以通知客户端有关核心转储的信息。
与其在现场观察 SEH 异常,不如设置一个未处理的异常过滤器更为传统。系统提供 SetUnhandledExceptionFilter API 来为线程注册回调,以防 SEH 异常未处理(C++ 异常也是建立在 SEH 异常之上的,因此未处理的 C++ 也会调用此回调例外)。
要使用异常过滤器正确检测目标进程中的每个线程,需要在创建任何线程时得到通知。每当使用 fdwReason
代码 DLL_THREAD_ATTACH
创建线程时,都会调用 DLL 的入口点。从那里调用 SetUnhandledExceptionFilter
是安全的。
UnhandledExceptionFilter 回调获取指向 EXCEPTION_POINTERS
结构的指针,这是有意义的小型转储所必需的(包括代码中引发异常的位置)。确保执行 绝对最小值 你可能会逃避以响应未处理的异常,即将 EXCEPTION_POINTERS
传输到外部进程,让它写出转储,并在写入转储时终止您的进程。
我正在使用一个库(oatpp
网络服务框架)来启动调用我的处理程序的线程。所以我无法控制要在其中插入 __try
...__except
的线程的最外层代码(我需要它来进行核心转储)。
处理程序实现如下所示:
shared_ptr<oatpp::web::server::HttpRequestHandler::OutgoingResponse> DownloadRequestHandler::handle(
const std::shared_ptr<IncomingRequest>& request)
{
__try {
return handleGuarded(request);
}
__except (Debugging::GenerateDump(GetExceptionInformation(), GetExceptionCode())) {
quick_exit(4);
}
}
所以关键是这个方法需要转发从守护方法返回的响应对象,这个对象(shared_ptr
)是不可展开的。因此,我得到 error C2712: Cannot use __try in functions that require object unwinding
.
能否就如何解决此问题提出建议?
到目前为止,我提出了以下涉及 3 个中间函数的解决方案。欢迎更简洁的解决方案!
shared_ptr<oatpp::web::server::HttpRequestHandler::OutgoingResponse> DownloadRequestHandler::handle(
const std::shared_ptr<IncomingRequest>& request)
{
shared_ptr<oatpp::web::server::HttpRequestHandler::OutgoingResponse> response;
handleGuarded1(request, response);
return response;
}
void DownloadRequestHandler::handleGuarded1(const std::shared_ptr<IncomingRequest>& request,
std::shared_ptr<OutgoingResponse>& response)
{
__try {
handleGuarded2(request, response);
}
__except (Debugging::GenerateDump(GetExceptionInformation(), GetExceptionCode())) {
quick_exit(4);
}
}
void DownloadRequestHandler::handleGuarded2(const std::shared_ptr<IncomingRequest>& request,
std::shared_ptr<OutgoingResponse>& response)
{
response = handleGuarded(request);
}
shared_ptr<oatpp::web::server::HttpRequestHandler::OutgoingResponse> DownloadRequestHandler::handleGuarded(
const std::shared_ptr<IncomingRequest>& request)
{
// Do the actual work...
}
我会提出两个选项:
1) 扩展或实现您自己的 HttpConnectionHandler and spawn threads the way you want. For this, you need to override the handleConnection 方法。
像这样:
void handleConnection(const std::shared_ptr<oatpp::data::stream::IOStream>& connection,
const std::shared_ptr<const ParameterMap>& params) override {
...
std::thread t([m_components, connection]{
HttpProcessor::Task task(m_components, connection)
__try {
task.run(); // run guarded
__except (Debugging::GenerateDump(GetExceptionInformation(), GetExceptionCode())) {
quick_exit(4);
}
})
...
}
其余代码只需复制粘贴即可。目前,m_components
var 是 HttpConnectionHandler
的私有成员,这会阻止您直接从 HttpConnectionHandler
继承,但您可以创建 PR 以使其受到保护 - 因此您需要仅覆盖一种方法。
这种方法的优点是,在此级别处理异常使您能够使用 oatpp
ApiController
及其所有请求映射。缺点 - 如果发生核心转储,您将无法 return 响应客户端。
2) 第二个选项是为 oatpp 创建一个 PR,以添加一个编译器选项,用于在 HttpProcessor
中添加一个额外的__try __except
块
因此可以通知客户端有关核心转储的信息。
与其在现场观察 SEH 异常,不如设置一个未处理的异常过滤器更为传统。系统提供 SetUnhandledExceptionFilter API 来为线程注册回调,以防 SEH 异常未处理(C++ 异常也是建立在 SEH 异常之上的,因此未处理的 C++ 也会调用此回调例外)。
要使用异常过滤器正确检测目标进程中的每个线程,需要在创建任何线程时得到通知。每当使用 fdwReason
代码 DLL_THREAD_ATTACH
创建线程时,都会调用 DLL 的入口点。从那里调用 SetUnhandledExceptionFilter
是安全的。
UnhandledExceptionFilter 回调获取指向 EXCEPTION_POINTERS
结构的指针,这是有意义的小型转储所必需的(包括代码中引发异常的位置)。确保执行 绝对最小值 你可能会逃避以响应未处理的异常,即将 EXCEPTION_POINTERS
传输到外部进程,让它写出转储,并在写入转储时终止您的进程。