I have swagger codegen generated c++ code with cpprest that makes some server calls.
Issue that I am facing: If cpprest http request returns any error code (4xx or 5xx), I get the following crash when I run my program in CentOS Linux. If cpprest http request returns a success, my program does not crash.
Callstack of the crash:
0x00007fe97b987207 libc.so.6!gsignal(+0x37) 0x00007fe97b9888f8 libc.so.6!abort(+0x147) 0x0000000007f2478b MyServer!abort_message() 0x0000000007f24ae1 MyServer!demangling_terminate_handler()() 0x0000000007f24983 MyServer!std::__terminate(void (*)())() 0x0000000007f24a05 MyServer!std::terminate()(+0x44) 0x00007fe97a417734 libstdc++.so.6!_ZSt17rethrow_exceptionNSt15__exception_ptr13exception_ptrE(+0x73) 0x00007fe97c9fdc05 libMyLibrary.so!_ZN4pplx7details16_ExceptionHolder21_RethrowUserExceptionEv(+0x24) 0x00007fe97c9fea05 libMyLibrary.so!_ZN4pplx7details15_Task_impl_base5_WaitEv(+0x2e4) 0x00007fe97c9faab6 libMyLibrary.so!_ZN5Test18MyManager16CallServerApi1EPKwS2_ibS2_Pwm(+0x615)
Explanation: Basically, MyLibrary shared object has a function CallServerApi1() that calls a function in the swagger code gen called CallServerApi1() again, which makes a cpprest request.
The following code is inside CallServerApi1() function of MyApi class in swagger generated code:
return m_ApiClient->callApi(path, utility::conversions::to_string_t("POST"), queryParams, httpBody, headerParams, formParams, fileParams, requestHttpContentType)
.then([=](web::http::http_response response)
{
// 1xx - informational : OK
// 2xx - successful : OK
// 3xx - redirection : OK
// 4xx - client error : not OK
// 5xx - client error : not OK
if (response.status_code() >= 400)
{
//throw my exception with details in case http returned a error response code.
throw MyException(response.status_code()
, utility::conversions::to_string_t("error calling CallServerApi1: ") + response.reason_phrase()
, std::make_shared<std::stringstream>(response.extract_utf8string(true).get()));
}
return response.extract_string(); // If successfull return the response data
});
My code in MyLibrary has a try catch to catch the MyException thrown by the swagger generate code.
try
{
auto task = api.CallServerApi1();
task.wait();
if (task.is_done())
{
}
}
catch (const MyException& e)
{
string error = e.what();
int error = e.error_code().value();
}
I read here: https://learn.microsoft.com/en-us/cpp/parallel/concrt/exception-handling-in-the-concurrency-runtime?view=vs-2019 that states that
When you throw an exception in the body of a work function that you pass to a task object, the runtime stores that exception and marshals it to the context that calls concurrency::task::get or concurrency::task::wait.
and
When a task throws an exception, its task-based continuations are scheduled to run.
My understanding is that, since the swagger generated code has task based continuation, and the crash callstack has a line that states that the pplx is throwing a user exception
libMyLibrary.so!_ZN4pplx7details16_ExceptionHolder21_RethrowUserExceptionEv(+0x24)
It seems like cpprest is re-throwing an exception and it not being handled by the swagger generated code due to value-based continuation, and hence it crashes because libstdc++ standard is instructed to do so for rethrown exceptions. Can anyone shed light on this, whether this might be the case and if so, is there a way to inform swagger code gen to use task based continuations instead of value based, to allow the exception from cpprest to pass through and be handled inside the then() block ?