| #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] = { 0 }; |
| void *obj; |
| |
| 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; |
| } |