mirror of
https://github.com/scylladb/scylladb.git
synced 2026-05-12 19:02:12 +00:00
aws_error: fix nested exception handling
The loop that unwraps nested exception, rethrows nested exception and saves pointer to the temporary std::exception& inner on stack, then continues. This pointer is, thus, pointing to a released temporary Closes scylladb/scylladb#28143
This commit is contained in:
committed by
Pavel Emelyanov
parent
b7bc48e7b7
commit
829bd9b598
@@ -108,3 +108,57 @@ BOOST_AUTO_TEST_CASE(TestErrorsWithoutPrefixParse) {
|
||||
BOOST_REQUIRE_EQUAL("JunkMessage", error.get_error_message());
|
||||
BOOST_REQUIRE_EQUAL(error.is_retryable(), aws::retryable::no);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(TestNestedException) {
|
||||
// Test nested exceptions where the innermost is a system_error
|
||||
try {
|
||||
try {
|
||||
try {
|
||||
throw std::system_error(std::error_code(ECONNABORTED, std::system_category()));
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::runtime_error("Higher level runtime_error"));
|
||||
}
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::logic_error("Higher level logic_error"));
|
||||
}
|
||||
} catch (...) {
|
||||
auto error = aws::aws_error::from_maybe_nested_exception(std::current_exception());
|
||||
BOOST_REQUIRE_EQUAL(aws::aws_error_type::NETWORK_CONNECTION, error.get_error_type());
|
||||
BOOST_REQUIRE_EQUAL("Software caused connection abort", error.get_error_message());
|
||||
BOOST_REQUIRE_EQUAL(error.is_retryable(), aws::retryable::yes);
|
||||
}
|
||||
|
||||
// Test nested exceptions where the innermost is NOT a system_error
|
||||
try {
|
||||
try {
|
||||
throw std::logic_error("Something bad happened");
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::runtime_error("Higher level runtime_error"));
|
||||
}
|
||||
} catch (...) {
|
||||
auto error = aws::aws_error::from_maybe_nested_exception(std::current_exception());
|
||||
BOOST_REQUIRE_EQUAL(aws::aws_error_type::UNKNOWN, error.get_error_type());
|
||||
BOOST_REQUIRE_EQUAL("Higher level runtime_error", error.get_error_message());
|
||||
BOOST_REQUIRE_EQUAL(error.is_retryable(), aws::retryable::no);
|
||||
}
|
||||
|
||||
// Test single exception which is NOT a nested exception
|
||||
try {
|
||||
throw std::runtime_error("Something bad happened");
|
||||
} catch (...) {
|
||||
auto error = aws::aws_error::from_maybe_nested_exception(std::current_exception());
|
||||
BOOST_REQUIRE_EQUAL(aws::aws_error_type::UNKNOWN, error.get_error_type());
|
||||
BOOST_REQUIRE_EQUAL("Something bad happened", error.get_error_message());
|
||||
BOOST_REQUIRE_EQUAL(error.is_retryable(), aws::retryable::no);
|
||||
}
|
||||
|
||||
// Test with non-std::exception
|
||||
try {
|
||||
throw "foo";
|
||||
} catch (...) {
|
||||
auto error = aws::aws_error::from_maybe_nested_exception(std::current_exception());
|
||||
BOOST_REQUIRE_EQUAL(aws::aws_error_type::UNKNOWN, error.get_error_type());
|
||||
BOOST_REQUIRE_EQUAL("No error message was provided, exception content: char const*", error.get_error_message());
|
||||
BOOST_REQUIRE_EQUAL(error.is_retryable(), aws::retryable::no);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,24 +160,41 @@ aws_error aws_error::from_system_error(const std::system_error& system_error) {
|
||||
}
|
||||
}
|
||||
|
||||
aws_error aws_error::from_maybe_nested_exception(const std::exception& maybe_nested_error) {
|
||||
const std::exception* current_exception = &maybe_nested_error;
|
||||
while (current_exception) {
|
||||
if (auto sys_error = dynamic_cast<const std::system_error*>(current_exception)) {
|
||||
return from_system_error(*sys_error);
|
||||
}
|
||||
aws_error aws_error::from_maybe_nested_exception(std::exception_ptr eptr) {
|
||||
std::string original_message;
|
||||
while (eptr) {
|
||||
try {
|
||||
std::rethrow_if_nested(*current_exception);
|
||||
} catch (const std::exception& inner) {
|
||||
current_exception = &inner;
|
||||
continue;
|
||||
std::rethrow_exception(eptr);
|
||||
} catch (const std::exception& e) {
|
||||
if (original_message.empty()) {
|
||||
original_message = e.what();
|
||||
}
|
||||
|
||||
if (auto* sys = dynamic_cast<const std::system_error*>(&e)) {
|
||||
return from_system_error(*sys);
|
||||
}
|
||||
|
||||
try {
|
||||
std::rethrow_if_nested(e);
|
||||
} catch (...) {
|
||||
eptr = std::current_exception();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} catch (...) {
|
||||
// Non-std::exception, should not happen in general
|
||||
break;
|
||||
}
|
||||
current_exception = nullptr;
|
||||
}
|
||||
return {aws_error_type::UNKNOWN, maybe_nested_error.what(), retryable::no};
|
||||
|
||||
if (original_message.empty()) {
|
||||
original_message = fmt::format("No error message was provided, exception content: {}", eptr);
|
||||
}
|
||||
|
||||
return {aws_error_type::UNKNOWN, std::move(original_message), retryable::no};
|
||||
}
|
||||
|
||||
|
||||
aws_error aws_error::from_exception_ptr(std::exception_ptr exception) {
|
||||
if (exception) {
|
||||
try {
|
||||
@@ -188,8 +205,8 @@ aws_error aws_error::from_exception_ptr(std::exception_ptr exception) {
|
||||
return from_http_code(ex.status());
|
||||
} catch (const std::system_error& ex) {
|
||||
return from_system_error(ex);
|
||||
} catch (const std::exception& ex) {
|
||||
return from_maybe_nested_exception(ex);
|
||||
} catch (const std::exception&) {
|
||||
return from_maybe_nested_exception(std::current_exception());
|
||||
} catch (...) {
|
||||
return aws_error{aws_error_type::UNKNOWN, seastar::format("{}", std::current_exception()), retryable::no};
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
static std::optional<aws_error> parse(seastar::sstring&& body);
|
||||
static aws_error from_http_code(seastar::http::reply::status_type http_code);
|
||||
static aws_error from_system_error(const std::system_error& system_error);
|
||||
static aws_error from_maybe_nested_exception(const std::exception& maybe_nested_error);
|
||||
static aws_error from_maybe_nested_exception(std::exception_ptr maybe_nested_error);
|
||||
static aws_error from_exception_ptr(std::exception_ptr exception);
|
||||
static const aws_errors& get_errors();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user