Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/src/catch2
diff options
context:
space:
mode:
authorDuncan Horn2025-09-25 04:31:49 -0700
committerGitHub2025-09-25 13:31:49 +0200
commitf7e7fa0983e83b922cb6336ff3a55d33b2873943 (patch)
tree0dc0715cf30890ad4b88c2b3cf369516ce59cb0e /src/catch2
parentb626e4c7aedb953e79784265e12283a62d5e94d3 (diff)
downloadcatch3-f7e7fa0983e83b922cb6336ff3a55d33b2873943.tar.gz
Fix ReusableStringStream to access the container under the lock (#3031)
Commit 582200a made `ReusableStringStream`'s index reservation thread safe, however it's still accessing the `m_streams` vector outside the lock. This makes it so that the `add` call returns the pointer in addition to the index so that the lock doesn't need to get acquired again until destruction. The issue with accessing `m_streams` outside the lock is that `add` can call `push_back` on the vector, which might re-allocate. If this re-allocation occurs concurrently with anther thread trying to index into this array, you get UB (typically a null pointer read).
Diffstat (limited to 'src/catch2')
-rw-r--r--src/catch2/internal/catch_reusable_string_stream.cpp15
1 files changed, 8 insertions, 7 deletions
diff --git a/src/catch2/internal/catch_reusable_string_stream.cpp b/src/catch2/internal/catch_reusable_string_stream.cpp
index a2dd5a63..875da4da 100644
--- a/src/catch2/internal/catch_reusable_string_stream.cpp
+++ b/src/catch2/internal/catch_reusable_string_stream.cpp
@@ -12,6 +12,7 @@
#include <cstdio>
#include <sstream>
+#include <tuple>
#include <vector>
namespace Catch {
@@ -23,16 +24,16 @@ namespace Catch {
std::ostringstream m_referenceStream; // Used for copy state/ flags from
Detail::Mutex m_mutex;
- auto add() -> std::size_t {
+ auto add() -> std::pair<std::size_t, std::ostringstream*> {
Detail::LockGuard _( m_mutex );
if( m_unused.empty() ) {
m_streams.push_back( Detail::make_unique<std::ostringstream>() );
- return m_streams.size()-1;
+ return { m_streams.size()-1, m_streams.back().get() };
}
else {
auto index = m_unused.back();
m_unused.pop_back();
- return index;
+ return { index, m_streams[index].get() };
}
}
@@ -46,10 +47,10 @@ namespace Catch {
}
};
- ReusableStringStream::ReusableStringStream()
- : m_index( Singleton<StringStreams>::getMutable().add() ),
- m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
- {}
+ ReusableStringStream::ReusableStringStream() {
+ std::tie( m_index, m_oss ) =
+ Singleton<StringStreams>::getMutable().add();
+ }
ReusableStringStream::~ReusableStringStream() {
static_cast<std::ostringstream*>( m_oss )->str("");