encoding: don't call flush() in OBufferStream if already closed
Refs: #5240
Change-Id: I48e2694657971960079c5b07b35102d32c316bc1
diff --git a/ndn-cxx/encoding/buffer-stream.cpp b/ndn-cxx/encoding/buffer-stream.cpp
index bf363c5..6ee415d 100644
--- a/ndn-cxx/encoding/buffer-stream.cpp
+++ b/ndn-cxx/encoding/buffer-stream.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2022 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -24,13 +24,13 @@
namespace ndn {
namespace detail {
-BufferAppendDevice::BufferAppendDevice(Buffer& container)
+BufferSink::BufferSink(Buffer& container)
: m_container(container)
{
}
std::streamsize
-BufferAppendDevice::write(const char_type* s, std::streamsize n)
+BufferSink::write(const char_type* s, std::streamsize n)
{
m_container.insert(m_container.end(), s, s + n);
return n;
@@ -39,21 +39,27 @@
} // namespace detail
OBufferStream::OBufferStream()
- : m_buffer(make_shared<Buffer>())
- , m_device(*m_buffer)
+ : m_buffer(std::make_shared<Buffer>())
{
- open(m_device);
+ open(detail::BufferSink{*m_buffer});
}
-OBufferStream::~OBufferStream()
+OBufferStream::~OBufferStream() noexcept
{
- close();
+ try {
+ close();
+ }
+ catch (...) {
+ // ignore
+ }
}
shared_ptr<Buffer>
OBufferStream::buf()
{
- flush();
+ if (is_open()) {
+ flush();
+ }
return m_buffer;
}
diff --git a/ndn-cxx/encoding/buffer-stream.hpp b/ndn-cxx/encoding/buffer-stream.hpp
index 6716221..16e4806 100644
--- a/ndn-cxx/encoding/buffer-stream.hpp
+++ b/ndn-cxx/encoding/buffer-stream.hpp
@@ -26,63 +26,61 @@
#include "ndn-cxx/encoding/buffer.hpp"
-#include <boost/iostreams/categories.hpp>
+#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
namespace ndn {
-
namespace detail {
-/** @brief (implementation detail) a Boost.Iostreams.Sink which appends to an \p ndn::Buffer
+/**
+ * @brief (implementation detail) A Boost.Iostreams.Sink that appends to a Buffer.
*/
-class BufferAppendDevice
+class BufferSink : public boost::iostreams::sink
{
public:
- typedef char char_type;
- typedef boost::iostreams::sink_tag category;
-
explicit
- BufferAppendDevice(Buffer& container);
+ BufferSink(Buffer& container);
std::streamsize
write(const char_type* s, std::streamsize n);
-protected:
+private:
Buffer& m_container;
};
} // namespace detail
-/** @brief implements an output stream that constructs \p ndn::Buffer
+/**
+ * @brief An output stream that writes to a Buffer.
*
- * The benefit of using stream interface is that it provides automatic buffering of
- * written data and eliminates (or reduces) overhead of resizing the underlying buffer
- * when writing small pieces of data.
+ * The benefit of using stream interface is that it provides automatic buffering of
+ * written data and eliminates (or reduces) overhead of resizing the underlying buffer
+ * when writing small pieces of data.
*
- * Usage example:
- * @code
- * OBufferStream obuf;
- * obuf.put(0);
- * obuf.write(anotherBuffer, anotherBufferSize);
- * shared_ptr<Buffer> buf = obuf.buf();
- * @endcode
+ * Usage example:
+ * @code
+ * OBufferStream obuf;
+ * obuf << "foo";
+ * obuf.put(0);
+ * obuf.write(anotherBuffer, anotherBufferSize);
+ * std::shared_ptr<Buffer> buf = obuf.buf();
+ * @endcode
*/
-class OBufferStream : public boost::iostreams::stream<detail::BufferAppendDevice>
+class OBufferStream : public boost::iostreams::stream<detail::BufferSink>
{
public:
OBufferStream();
- ~OBufferStream() override;
+ ~OBufferStream() noexcept override;
/**
- * Flush written data to the stream and return shared pointer to the underlying buffer
+ * @brief Return a shared pointer to the underlying buffer.
*/
shared_ptr<Buffer>
buf();
private:
- BufferPtr m_buffer;
- detail::BufferAppendDevice m_device;
+ shared_ptr<Buffer> m_buffer;
};
} // namespace ndn
diff --git a/tests/unit/encoding/buffer-stream.t.cpp b/tests/unit/encoding/buffer-stream.t.cpp
index 9418f8c..3f67d50 100644
--- a/tests/unit/encoding/buffer-stream.t.cpp
+++ b/tests/unit/encoding/buffer-stream.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2018 Regents of the University of California.
+ * Copyright (c) 2013-2022 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -63,11 +63,22 @@
BOOST_AUTO_TEST_CASE(Destructor) // Bug 3727
{
auto os = make_unique<OBufferStream>();
+ auto buf = os->buf();
*os << 'x';
- os.reset(); // should not cause use-after-free
+ // do NOT flush or call buf() here
- // avoid "test case [...] did not check any assertions" message from Boost.Test
- BOOST_CHECK(true);
+ os.reset(); // should not cause use-after-free
+ BOOST_CHECK_EQUAL(buf->size(), 1);
+}
+
+BOOST_AUTO_TEST_CASE(Close) // Bug 5240
+{
+ OBufferStream os;
+ os << "foo";
+ os.close();
+
+ auto buf = os.buf(); // should not cause assertion failure
+ BOOST_CHECK_EQUAL(buf->size(), 3);
}
BOOST_AUTO_TEST_SUITE_END() // TestBufferStream