util/Exception: sanitize message strings
This should prevent leaking unsanitized strings from libraries.
This commit is contained in:
parent
abb23ba894
commit
7b938b4d14
|
@ -2,9 +2,40 @@
|
|||
// author: Max Kellermann <max.kellermann@gmail.com>
|
||||
|
||||
#include "Exception.hxx"
|
||||
#include "CharUtil.hxx"
|
||||
#include "StringStrip.hxx"
|
||||
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
* Append the given C string to a std::string, with some
|
||||
* sanitizations: strip whitespace at the beginning and the end and
|
||||
* combine multiple whitespace to a single space.
|
||||
*
|
||||
* This shall compress strangely formatted multi-line messages (which
|
||||
* may come from third-party libraries) to a single line.
|
||||
*/
|
||||
static void
|
||||
AppendSanitize(std::string &dest, const char *src) noexcept
|
||||
{
|
||||
src = StripLeft(src);
|
||||
|
||||
bool space = false;
|
||||
while (char ch = *src++) {
|
||||
if (IsWhitespaceFast(ch)) {
|
||||
space = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (space) {
|
||||
space = false;
|
||||
dest.push_back(' ');
|
||||
}
|
||||
|
||||
dest.push_back(ch);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void
|
||||
AppendNestedMessage(std::string &result, T &&e,
|
||||
|
@ -14,13 +45,13 @@ AppendNestedMessage(std::string &result, T &&e,
|
|||
std::rethrow_if_nested(std::forward<T>(e));
|
||||
} catch (const std::exception &nested) {
|
||||
result += separator;
|
||||
result += nested.what();
|
||||
AppendSanitize(result, nested.what());
|
||||
AppendNestedMessage(result, nested, fallback, separator);
|
||||
} catch (const std::nested_exception &ne) {
|
||||
AppendNestedMessage(result, ne, fallback, separator);
|
||||
} catch (const char *s) {
|
||||
result += separator;
|
||||
result += s;
|
||||
AppendSanitize(result, s);
|
||||
} catch (...) {
|
||||
result += separator;
|
||||
result += fallback;
|
||||
|
@ -31,7 +62,8 @@ std::string
|
|||
GetFullMessage(const std::exception &e,
|
||||
const char *fallback, const char *separator) noexcept
|
||||
{
|
||||
std::string result = e.what();
|
||||
std::string result;
|
||||
AppendSanitize(result, e.what());
|
||||
AppendNestedMessage(result, e, fallback, separator);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using std::string_view_literals::operator""sv;
|
||||
|
||||
TEST(ExceptionTest, RuntimeError)
|
||||
{
|
||||
ASSERT_EQ(GetFullMessage(std::make_exception_ptr(std::runtime_error("Foo"))), "Foo");
|
||||
|
@ -22,6 +24,22 @@ TEST(ExceptionTest, DerivedError)
|
|||
ASSERT_EQ(GetFullMessage(std::make_exception_ptr(DerivedError("Foo"))), "Foo");
|
||||
}
|
||||
|
||||
TEST(ExceptionTest, GetFullMessageSanitize)
|
||||
{
|
||||
try {
|
||||
try {
|
||||
throw " ABC \n DEF ";
|
||||
} catch (...) {
|
||||
std::throw_with_nested(std::runtime_error{"foo\r\n\tbar"});
|
||||
}
|
||||
|
||||
FAIL();
|
||||
} catch (...) {
|
||||
ASSERT_EQ(GetFullMessage(std::current_exception()),
|
||||
"foo bar; ABC DEF"sv);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ExceptionTest, FindNestedDirect)
|
||||
{
|
||||
struct Foo {};
|
||||
|
|
Loading…
Reference in New Issue