What changed, and why it matters
This commit adds a small helper class that wraps a temporary data buffer used internally by Bitcoin Core's database code. It makes sure the buffer is empty when use starts and clears it when use ends, and in debug builds it will crash the program if a buffer is accidentally reused while still in use. It is a defensive hardening change, not a fix for a known exploitable bug.
No immediate action required. Treat as routine defensive hardening. If auditing, verify that all DB paths that reuse caller-owned DataStream scratch buffers adopt ScopedDataStreamUsage consistently.
Security signals we found
Defensive RAII guard for shared scratch buffers
Debug-only assertion on entry state (fail-fast for contract violations)
No change to network, consensus, wallet, or RPC behavior
No bug class or vulnerability described in commit message
Evidence from the diff
The patch introduces ScopedDataStreamUsage, an RAII guard around a DataStream reference. Its constructor asserts the stream is empty, and its destructor clears the stream. The intent is to preserve the existing ‘temporary scratch buffer’ contract in DB paths and to turn accidental nested reuse into a debug assertion failure. A unit test verifies the guard clears the stream on scope exit and allows reuse after that.
Changed components
src/streams.hsrc/test/streams_tests.cppInspect captured patch +32 / −0
diff --git a/src/streams.h b/src/streams.h
index 96cea55e..e939dd18 100644
--- a/src/streams.h
+++ b/src/streams.h
@@ -265,6 +265,20 @@ public:
size_t GetMemoryUsage() const noexcept;
};
+// Require empty scratch streams on entry and reset them on exit.
+class ScopedDataStreamUsage
+{
+ DataStream& m_stream;
+
+public:
+ explicit ScopedDataStreamUsage(DataStream& stream) : m_stream{stream} { assert(m_stream.empty()); }
+
+ ScopedDataStreamUsage(const ScopedDataStreamUsage&) = delete;
+ ScopedDataStreamUsage& operator=(const ScopedDataStreamUsage&) = delete;
+
+ ~ScopedDataStreamUsage() { m_stream.clear(); }
+};
+
template <typename IStream>
class BitStreamReader
{
diff --git a/src/test/streams_tests.cpp b/src/test/streams_tests.cpp
index 6a6026bf..6a3be3cc 100644
--- a/src/test/streams_tests.cpp
+++ b/src/test/streams_tests.cpp
@@ -88,6 +88,24 @@ BOOST_AUTO_TEST_CASE(obfuscation_empty)
BOOST_CHECK(non_null_obf);
}
+BOOST_AUTO_TEST_CASE(streams_scoped_data_stream_usage)
+{
+ DataStream stream{};
+ {
+ ScopedDataStreamUsage usage{stream};
+ stream << uint8_t{42};
+ BOOST_CHECK_GT(stream.size(), 0U);
+ }
+ BOOST_CHECK(stream.empty());
+
+ {
+ ScopedDataStreamUsage usage{stream};
+ stream << uint16_t{42};
+ BOOST_CHECK_GT(stream.size(), 0U);
+ }
+ BOOST_CHECK(stream.empty());
+}
+
BOOST_AUTO_TEST_CASE(xor_file)
{
fs::path xor_path{m_args.GetDataDirBase() / "test_xor.bin"};
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.