summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoic Dachary <loic@dachary.org>2013-02-10 14:23:36 +0100
committerLoic Dachary <loic@dachary.org>2013-02-10 15:32:35 +0100
commit749218f155969fd87a6194b26acd00a9332d522d (patch)
tree0c3e6f2106b00c6fa3eb7d24d118b8c6fc250f47
parentabc80ffc5b1aab3915c049701ab85c57fe93d550 (diff)
downloadceph-749218f155969fd87a6194b26acd00a9332d522d.tar.gz
buffer::ptr self assignment bug + patch
After buffer::ptr a(1); a = a; a call to a.get_raw() will return a null pointer and there will be no pointer referencing the original buffer::raw object although its reference count is 1. buffer::ptr& buffer::ptr::operator= (const ptr& p) is modified to use a local buffer::raw pointer to fix the memory leak. a = a is a noop instead of loosing the original raw buffer. A set of unit tests is added src/test/bufferlist.cc to demonstrate that the proposed change works as expected. It is checked with valgrind that reports no memory leak. The same test can be run against the original code to show that it leaks. http://tracker.ceph.com/issues/4070 refs #4070 Signed-off-by: Loic Dachary <loic@dachary.org>
-rw-r--r--src/common/buffer.cc10
-rw-r--r--src/test/bufferlist.cc48
2 files changed, 53 insertions, 5 deletions
diff --git a/src/common/buffer.cc b/src/common/buffer.cc
index b2d3ec6ed8c..58346df2383 100644
--- a/src/common/buffer.cc
+++ b/src/common/buffer.cc
@@ -285,14 +285,14 @@ bool buffer_track_alloc = get_env_bool("CEPH_BUFFER_TRACK");
}
buffer::ptr& buffer::ptr::operator= (const ptr& p)
{
- // be careful -- we need to properly handle self-assignment.
if (p._raw) {
- p._raw->nref.inc(); // inc new
+ p._raw->nref.inc();
bdout << "ptr " << this << " get " << _raw << bendl;
}
- release(); // dec (+ dealloc) old (if any)
- if (p._raw) {
- _raw = p._raw;
+ buffer::raw *raw = p._raw;
+ release();
+ if (raw) {
+ _raw = raw;
_off = p._off;
_len = p._len;
} else {
diff --git a/src/test/bufferlist.cc b/src/test/bufferlist.cc
index 4dafee8cd34..c7668a26541 100644
--- a/src/test/bufferlist.cc
+++ b/src/test/bufferlist.cc
@@ -40,6 +40,54 @@ TEST(BufferList, TestPtrAppend) {
ASSERT_EQ(memcmp(bl.c_str(), correct, curpos), 0);
}
+TEST(BufferList, ptr_assignment) {
+ unsigned len = 17;
+ //
+ // override a bufferptr set with the same raw
+ //
+ {
+ bufferptr original(len);
+ bufferptr same_raw(original.get_raw());
+ unsigned offset = 5;
+ unsigned length = len - offset;
+ original.set_offset(offset);
+ original.set_length(length);
+ same_raw = original;
+ ASSERT_EQ(2, original.raw_nref());
+ ASSERT_EQ(same_raw.get_raw(), original.get_raw());
+ ASSERT_EQ(same_raw.offset(), original.offset());
+ ASSERT_EQ(same_raw.length(), original.length());
+ }
+
+ //
+ // self assignment is a noop
+ //
+ {
+ bufferptr original(len);
+ original = original;
+ ASSERT_EQ(1, original.raw_nref());
+ ASSERT_EQ((unsigned)0, original.offset());
+ ASSERT_EQ(len, original.length());
+ }
+
+ //
+ // a copy points to the same raw
+ //
+ {
+ bufferptr original(len);
+ unsigned offset = 5;
+ unsigned length = len - offset;
+ original.set_offset(offset);
+ original.set_length(length);
+ bufferptr ptr;
+ ptr = original;
+ ASSERT_EQ(2, original.raw_nref());
+ ASSERT_EQ(ptr.get_raw(), original.get_raw());
+ ASSERT_EQ(original.offset(), ptr.offset());
+ ASSERT_EQ(original.length(), ptr.length());
+ }
+}
+
TEST(BufferList, TestDirectAppend) {
bufferlist bl;
char correct[MAX_TEST];