From c000e9c1f409c926b766333c615c321eab82e366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Schre=CC=81ter?= Date: Fri, 24 Feb 2023 21:51:46 +0100 Subject: [PATCH 1/2] Add NUL character at the end of copied error message C++ error message returned by `what` must be NUL-terminated. However, the current copy function only copied the characters, but didn't add the NUL. Allocate one more byte and set it to NUL. --- src/cxx.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/cxx.cc b/src/cxx.cc index 4958eb08b..d449429da 100644 --- a/src/cxx.cc +++ b/src/cxx.cc @@ -449,8 +449,9 @@ static_assert(!std::is_same::const_iterator, "Vec::const_iterator != Vec::iterator"); static const char *errorCopy(const char *ptr, std::size_t len) { - char *copy = new char[len]; + char *copy = new char[len + 1]; std::memcpy(copy, ptr, len); + copy[len] = 0; return copy; } From eec29dc3a0f567fe40438c4f56f4f0a56349db88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Schre=CC=81ter?= Date: Sun, 26 Feb 2023 17:21:49 +0100 Subject: [PATCH 2/2] Fix: Prevent crash on OOM in error copy When the error message is copied, the allocation may fail. This would terminate the process, since it's called from a `noexcept` function. Make the allocation `nothrow` and handle `nullptr` in `what()` method appropriately, returning a generic message saying that the message cannot be allocated. This also prevents a crash if `what()` is called on a moved object (which is technically UB, but still better not to crash). --- src/cxx.cc | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/cxx.cc b/src/cxx.cc index d449429da..c630647b7 100644 --- a/src/cxx.cc +++ b/src/cxx.cc @@ -448,10 +448,14 @@ static_assert(!std::is_same::const_iterator, Vec::iterator>::value, "Vec::const_iterator != Vec::iterator"); -static const char *errorCopy(const char *ptr, std::size_t len) { - char *copy = new char[len + 1]; - std::memcpy(copy, ptr, len); - copy[len] = 0; +// Copy the error message into a private buffer and return it. +// If the allocation fails, nullptr is returned. +static const char *errorCopy(const char *ptr, std::size_t len) noexcept { + char *copy = new (std::nothrow) char[len + 1]; + if (copy) { + std::memcpy(copy, ptr, len); + copy[len] = 0; + } return copy; } @@ -497,7 +501,12 @@ Error &Error::operator=(Error &&other) &noexcept { return *this; } -const char *Error::what() const noexcept { return this->msg; } +const char *Error::what() const noexcept { + if (this->msg) + return this->msg; + else + return ""; +} namespace { template