summaryrefslogtreecommitdiffstats
path: root/unit-tests
diff options
context:
space:
mode:
authorJoe Thornber <thornber@redhat.com>2010-08-09 10:56:01 +0000
committerJoe Thornber <thornber@redhat.com>2010-08-09 10:56:01 +0000
commit52e1564fddf769d481ef8bc89a01c680777bcbbc (patch)
tree9ebf3a6c825029c278ec2300ab2bec33f9b7fc36 /unit-tests
parentfae2c492595add56718d45efaee36438e4279600 (diff)
downloadlvm2-52e1564fddf769d481ef8bc89a01c680777bcbbc.tar.gz
lvm2-52e1564fddf769d481ef8bc89a01c680777bcbbc.tar.xz
lvm2-52e1564fddf769d481ef8bc89a01c680777bcbbc.zip
[MM] Make valgrind aware of the pool allocators
./configure with --enable-valgrind-pool to enable this.
Diffstat (limited to 'unit-tests')
-rw-r--r--unit-tests/mm/Makefile.in31
-rw-r--r--unit-tests/mm/TESTS1
-rwxr-xr-xunit-tests/mm/check_results31
-rw-r--r--unit-tests/mm/pool_valgrind_t.c183
4 files changed, 246 insertions, 0 deletions
diff --git a/unit-tests/mm/Makefile.in b/unit-tests/mm/Makefile.in
new file mode 100644
index 00000000..1b3499ed
--- /dev/null
+++ b/unit-tests/mm/Makefile.in
@@ -0,0 +1,31 @@
+#
+# Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+# Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions
+# of the GNU General Public License v.2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+top_builddir = @top_builddir@
+VPATH = @srcdir@
+
+SOURCES=\
+ pool_valgrind_t.c
+
+TARGETS=\
+ pool_valgrind_t
+
+include $(top_builddir)/make.tmpl
+DM_LIBS = -ldevmapper $(LIBS)
+
+pool_valgrind_t: pool_valgrind_t.o
+ $(CC) $(CFLAGS) -o $@ pool_valgrind_t.o $(LDFLAGS) $(DM_LIBS)
+
diff --git a/unit-tests/mm/TESTS b/unit-tests/mm/TESTS
new file mode 100644
index 00000000..3bf31544
--- /dev/null
+++ b/unit-tests/mm/TESTS
@@ -0,0 +1 @@
+valgrind pool awareness:valgrind ./pool_valgrind_t 2>&1 | ./check_results
diff --git a/unit-tests/mm/check_results b/unit-tests/mm/check_results
new file mode 100755
index 00000000..a7b0975a
--- /dev/null
+++ b/unit-tests/mm/check_results
@@ -0,0 +1,31 @@
+#!/usr/bin/env ruby1.9
+
+require 'pp'
+
+patterns = [
+ /Invalid read of size 1/,
+ /Invalid write of size 1/,
+ /Invalid read of size 1/,
+ /still reachable: [0-9,]+ bytes in 3 blocks/
+ ]
+
+lines = STDIN.readlines
+pp lines
+
+result = catch(:done) do
+ patterns.each do |pat|
+ loop do
+ throw(:done, false) if lines.size == 0
+
+ line = lines.shift
+ if line =~ pat
+ STDERR.puts "matched #{pat}"
+ break;
+ end
+ end
+ end
+
+ throw(:done, true)
+end
+
+exit(result ? 0 : 1)
diff --git a/unit-tests/mm/pool_valgrind_t.c b/unit-tests/mm/pool_valgrind_t.c
new file mode 100644
index 00000000..b430a9c1
--- /dev/null
+++ b/unit-tests/mm/pool_valgrind_t.c
@@ -0,0 +1,183 @@
+#include "libdevmapper.h"
+
+#include <assert.h>
+
+/*
+ * Checks that valgrind is picking up unallocated pool memory as
+ * uninitialised, even if the chunk has been recycled.
+ *
+ * $ valgrind --track-origins=yes ./pool_valgrind_t
+ *
+ * ==7023== Memcheck, a memory error detector
+ * ==7023== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
+ * ==7023== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
+ * ==7023== Command: ./pool_valgrind_t
+ * ==7023==
+ * first branch worked (as expected)
+ * ==7023== Conditional jump or move depends on uninitialised value(s)
+ * ==7023== at 0x4009AC: main (in /home/ejt/work/lvm2/unit-tests/mm/pool_valgrind_t)
+ * ==7023== Uninitialised value was created by a client request
+ * ==7023== at 0x4E40CB8: dm_pool_free (in /home/ejt/work/lvm2/libdm/ioctl/libdevmapper.so.1.02)
+ * ==7023== by 0x4009A8: main (in /home/ejt/work/lvm2/unit-tests/mm/pool_valgrind_t)
+ * ==7023==
+ * second branch worked (valgrind should have flagged this as an error)
+ * ==7023==
+ * ==7023== HEAP SUMMARY:
+ * ==7023== in use at exit: 0 bytes in 0 blocks
+ * ==7023== total heap usage: 2 allocs, 2 frees, 2,104 bytes allocated
+ * ==7023==
+ * ==7023== All heap blocks were freed -- no leaks are possible
+ * ==7023==
+ * ==7023== For counts of detected and suppressed errors, rerun with: -v
+ * ==7023== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
+ */
+
+#define COUNT 10
+
+static void check_free()
+{
+ int i;
+ char *blocks[COUNT];
+ struct dm_pool *p = dm_pool_create("blah", 1024);
+
+ for (i = 0; i < COUNT; i++)
+ blocks[i] = dm_pool_alloc(p, 37);
+
+ /* check we can access the last block */
+ blocks[COUNT - 1][0] = 'E';
+ if (blocks[COUNT - 1][0] == 'E')
+ printf("first branch worked (as expected)\n");
+
+ dm_pool_free(p, blocks[5]);
+
+ if (blocks[COUNT - 1][0] == 'E')
+ printf("second branch worked (valgrind should have flagged this as an error)\n");
+
+ dm_pool_destroy(p);
+}
+
+/* Checks that freed chunks are marked NOACCESS */
+static void check_free2()
+{
+ struct dm_pool *p = dm_pool_create("", 900); /* 900 will get
+ * rounded up to 1024,
+ * 1024 would have got
+ * rounded up to
+ * 2048 */
+ char *data1, *data2;
+
+ assert(p);
+ data1 = dm_pool_alloc(p, 123);
+ assert(data1);
+
+ data1 = dm_pool_alloc(p, 1024);
+ assert(data1);
+
+ data2 = dm_pool_alloc(p, 123);
+ assert(data2);
+
+ data2[0] = 'A'; /* should work fine */
+
+ dm_pool_free(p, data1);
+
+ /*
+ * so now the first chunk is active, the second chunk has become
+ * the free one.
+ */
+ data2[0] = 'B'; /* should prompt an invalid write error */
+
+ dm_pool_destroy(p);
+}
+
+static void check_alignment()
+{
+ /*
+ * Pool always tries to allocate blocks with particular alignment.
+ * So there are potentially small gaps between allocations. This
+ * test checks that valgrind is spotting illegal accesses to these
+ * gaps.
+ */
+
+ int i, sum;
+ struct dm_pool *p = dm_pool_create("blah", 1024);
+ char *data1, *data2;
+ char buffer[16];
+
+
+ data1 = dm_pool_alloc_aligned(p, 1, 4);
+ assert(data1);
+ data2 = dm_pool_alloc_aligned(p, 1, 4);
+ assert(data1);
+
+ snprintf(buffer, sizeof(buffer), "%c", *(data1 + 1)); /* invalid read size 1 */
+ dm_pool_destroy(p);
+}
+
+/*
+ * Looking at the code I'm not sure allocations that are near the chunk
+ * size are working. So this test is trying to exhibit a specific problem.
+ */
+static void check_allocation_near_chunk_size()
+{
+ int i;
+ char *data;
+ struct dm_pool *p = dm_pool_create("", 900);
+
+ /*
+ * allocate a lot and then free everything so we know there
+ * is a spare chunk.
+ */
+ for (i = 0; i < 1000; i++) {
+ data = dm_pool_alloc(p, 37);
+ memset(data, 0, 37);
+ assert(data);
+ }
+
+ dm_pool_empty(p);
+
+ /* now we allocate something close to the chunk size ... */
+ data = dm_pool_alloc(p, 1020);
+ assert(data);
+ memset(data, 0, 1020);
+
+ dm_pool_destroy(p);
+}
+
+/* FIXME: test the dbg_malloc at exit (this test should be in dbg_malloc) */
+static void check_leak_detection()
+{
+ int i;
+ struct dm_pool *p = dm_pool_create("", 1024);
+
+ for (i = 0; i < 10; i++)
+ dm_pool_alloc(p, (i + 1) * 37);
+}
+
+/* we shouldn't get any errors from this one */
+static void check_object_growth()
+{
+ int i;
+ struct dm_pool *p = dm_pool_create("", 32);
+ char data[100];
+ void *obj;
+
+ memset(data, 0, sizeof(data));
+
+ dm_pool_begin_object(p, 43);
+ for (i = 1; i < 100; i++)
+ dm_pool_grow_object(p, data, i);
+ obj = dm_pool_end_object(p);
+
+ dm_pool_destroy(p);
+}
+
+int main(int argc, char **argv)
+{
+ check_free();
+ check_free2();
+ check_alignment();
+ check_allocation_near_chunk_size();
+ check_leak_detection();
+ check_object_growth();
+ return 0;
+}