From f017eb6fc09d74aa83eb5391028be5fd12380d34 Mon Sep 17 00:00:00 2001 From: Quincey Koziol Date: Sun, 3 Jan 2016 17:06:52 -0500 Subject: [svn-r28777] Description: Add --enable-memory-alloc-sanity-check option to configure, to track and sanity check memory allocations within the library. This is orthogonal to the --enable-using-memchecker option and can be used with/without it. Tested on: MacOSX/64 10.11.2 (amazon) w/serial & parallel (h5committest forthcoming) --- CMakeLists.txt | 8 + config/cmake/cacheinit.cmake | 2 + config/cmake/libhdf5.settings.cmake.in | 1 + config/cmake/mccacheinit.cmake | 2 + configure.ac | 31 ++++ release_docs/INSTALL_CMake.txt | 2 + src/H5.c | 5 + src/H5Dchunk.c | 32 +++- src/H5Dpkg.h | 25 +-- src/H5MM.c | 323 +++++++++++++++++++++++++++++++-- src/H5MMprivate.h | 13 +- src/libhdf5.settings.in | 1 + 12 files changed, 397 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 65124ab..23b55c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -376,6 +376,14 @@ if (HDF5_ENABLE_USING_MEMCHECKER) endif (HDF5_ENABLE_USING_MEMCHECKER) #----------------------------------------------------------------------------- +# Option to indicate internal memory allocation sanity checks are enabled +#----------------------------------------------------------------------------- +option (HDF5_MEMORY_ALLOC_SANITY_CHECK "Indicate that internal memory allocation sanity checks are enabled" OFF) +if (HDF5_MEMORY_ALLOC_SANITY_CHECK) + set (H5_MEMORY_ALLOC_SANITY_CHECK 1) +endif (HDF5_MEMORY_ALLOC_SANITY_CHECK) + +#----------------------------------------------------------------------------- # Option to use deprecated public API symbols #----------------------------------------------------------------------------- option (HDF5_ENABLE_DEPRECATED_SYMBOLS "Enable deprecated public API symbols" ON) diff --git a/config/cmake/cacheinit.cmake b/config/cmake/cacheinit.cmake index 4bef99f..5cae21b 100644 --- a/config/cmake/cacheinit.cmake +++ b/config/cmake/cacheinit.cmake @@ -36,6 +36,8 @@ set (HDF5_ENABLE_COVERAGE OFF CACHE BOOL "Enable code coverage for Libraries and set (HDF5_ENABLE_USING_MEMCHECKER OFF CACHE BOOL "Indicate that a memory checker is used" FORCE) +set (HDF5_MEMORY_ALLOC_SANITY_CHECK OFF CACHE BOOL "Indicate that internal memory allocation sanity checks are enabled" FORCE) + set (HDF5_DISABLE_COMPILER_WARNINGS OFF CACHE BOOL "Disable compiler warnings" FORCE) set (HDF5_USE_FOLDERS ON CACHE BOOL "Enable folder grouping of projects in IDEs." FORCE) diff --git a/config/cmake/libhdf5.settings.cmake.in b/config/cmake/libhdf5.settings.cmake.in index ba764a4..cc6ae3e 100644 --- a/config/cmake/libhdf5.settings.cmake.in +++ b/config/cmake/libhdf5.settings.cmake.in @@ -65,6 +65,7 @@ Features: dmalloc: @H5_HAVE_LIBDMALLOC@ Clear file buffers before write: @HDF5_Enable_Clear_File_Buffers@ Using memory checker: @HDF5_ENABLE_USING_MEMCHECKER@ +Memory allocation sanity checks: @HDF5_MEMORY_ALLOC_SANITY_CHECK@ Function Stack Tracing: @HDF5_ENABLE_CODESTACK@ Strict File Format Checks: @HDF5_STRICT_FORMAT_CHECKS@ Optimization Instrumentation: @HDF5_Enable_Instrument@ diff --git a/config/cmake/mccacheinit.cmake b/config/cmake/mccacheinit.cmake index 19ecc15..e54db1f 100644 --- a/config/cmake/mccacheinit.cmake +++ b/config/cmake/mccacheinit.cmake @@ -48,6 +48,8 @@ set (HDF5_ENABLE_COVERAGE OFF CACHE BOOL "Enable code coverage for Libraries and set (HDF5_ENABLE_USING_MEMCHECKER ON CACHE BOOL "Indicate that a memory checker is used" FORCE) +set (HDF5_MEMORY_ALLOC_SANITY_CHECK OFF CACHE BOOL "Indicate that internal memory allocation sanity checks are enabled" FORCE) + set (HDF5_DISABLE_COMPILER_WARNINGS OFF CACHE BOOL "Disable compiler warnings" FORCE) set (HDF5_USE_FOLDERS ON CACHE BOOL "Enable folder grouping of projects in IDEs." FORCE) diff --git a/configure.ac b/configure.ac index 0e853a8..9c1d5b0 100644 --- a/configure.ac +++ b/configure.ac @@ -2044,6 +2044,8 @@ AC_ARG_ENABLE([using-memchecker], library. Enabling this causes the library to be more picky about it's memory operations and also disables the library's free space manager code. + This option is orthogonal to the + --enable-memory-alloc-sanity-check option. Default=no.])], [USINGMEMCHECKER=$enableval]) @@ -2062,6 +2064,35 @@ case "X-$USINGMEMCHECKER" in ;; esac +## ---------------------------------------------------------------------- +## Check if they would like to enable the internal memory allocation sanity +## checking code. +## +AC_SUBST([MEMORYALLOCSANITYCHECK]) +AC_MSG_CHECKING([whether internal memory allocation sanity checking is used]) +AC_ARG_ENABLE([memory-alloc-sanity-check], + [AS_HELP_STRING([--enable-memory-alloc-sanity-check], + [Enable this option to turn on internal memory + allocation sanity checking. This could cause + more memory use and somewhat slower allocation. + This option is orthogonal to the + --enable-using-memchecker option. + Default=no.])], + [MEMORYALLOCSANITYCHECK=$enableval]) + +case "X-$MEMORYALLOCSANITYCHECK" in + X-yes) + MEMORYALLOCSANITYCHECK=yes + AC_MSG_RESULT([yes]) + AC_DEFINE([MEMORY_ALLOC_SANITY_CHECK], [1], + [Define to enable internal memory allocation sanity checking.]) + ;; + *) + MEMORYALLOCSANITYCHECK=no + AC_MSG_RESULT([no]) + ;; +esac + ## Checkpoint the cache AC_CACHE_SAVE diff --git a/release_docs/INSTALL_CMake.txt b/release_docs/INSTALL_CMake.txt index e745084..37326ed 100644 --- a/release_docs/INSTALL_CMake.txt +++ b/release_docs/INSTALL_CMake.txt @@ -411,6 +411,7 @@ These five steps are described in detail below. set (HDF5_BUILD_PARALLEL_ALL OFF CACHE BOOL "Build Parallel Programs" FORCE) set (HDF5_ENABLE_COVERAGE OFF CACHE BOOL "Enable code coverage for Libraries and Programs" FORCE) set (HDF5_ENABLE_USING_MEMCHECKER OFF CACHE BOOL "Indicate that a memory checker is used" FORCE) + set (HDF5_MEMORY_ALLOC_SANITY_CHECK OFF CACHE BOOL "Indicate that internal memory allocation sanity checks are enabled" FORCE) set (HDF5_DISABLE_COMPILER_WARNINGS OFF CACHE BOOL "Disable compiler warnings" FORCE) set (HDF5_USE_FOLDERS ON CACHE BOOL "Enable folder grouping of projects in IDEs." FORCE) set (HDF5_USE_16_API_DEFAULT OFF CACHE BOOL "Use the HDF5 1.6.x API by default" FORCE) @@ -587,6 +588,7 @@ HDF5_ENABLE_LARGE_FILE "Enable support for large (64-bit) files on Linux HDF5_ENABLE_PARALLEL "Enable parallel build (requires MPI)" OFF HDF5_ENABLE_TRACE "Enable API tracing capability" OFF HDF5_ENABLE_USING_MEMCHECKER "Indicate that a memory checker is used" OFF +HDF5_MEMORY_ALLOC_SANITY_CHECK "Indicate that internal memory allocation sanity checks are enabled" OFF HDF5_METADATA_TRACE_FILE "Enable metadata trace file collection" OFF HDF5_NO_PACKAGES "Do not include CPack Packaging" OFF HDF5_PACKAGE_EXTLIBS "CPACK - include external libraries" OFF diff --git a/src/H5.c b/src/H5.c index 2086ce8..a522398 100644 --- a/src/H5.c +++ b/src/H5.c @@ -396,6 +396,11 @@ H5_term_library(void) (void)H5MM_free(tmp_open_stream); } /* end while */ +#if defined H5_MEMORY_ALLOC_SANITY_CHECK + /* Sanity check memory allocations */ + H5MM_final_sanity_check(); +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + /* Reset flag indicating that the library is being shut down */ H5_TERM_GLOBAL = FALSE; diff --git a/src/H5Dchunk.c b/src/H5Dchunk.c index 6b99a43..0c4cba1 100644 --- a/src/H5Dchunk.c +++ b/src/H5Dchunk.c @@ -107,6 +107,25 @@ /* Local Typedefs */ /******************/ +/* Raw data chunks are cached. Each entry in the cache is: */ +typedef struct H5D_rdcc_ent_t { + hbool_t locked; /*entry is locked in cache */ + hbool_t dirty; /*needs to be written to disk? */ + hbool_t deleted; /*chunk about to be deleted */ + hsize_t scaled[H5O_LAYOUT_NDIMS]; /*scaled chunk 'name' (coordinates) */ + uint32_t rd_count; /*bytes remaining to be read */ + uint32_t wr_count; /*bytes remaining to be written */ + H5F_block_t chunk_block; /*offset/length of chunk in file */ + hsize_t chunk_idx; /*index of chunk in dataset */ + uint8_t *chunk; /*the unfiltered chunk data */ + unsigned idx; /*index in hash table */ + struct H5D_rdcc_ent_t *next;/*next item in doubly-linked list */ + struct H5D_rdcc_ent_t *prev;/*previous item in doubly-linked list */ + struct H5D_rdcc_ent_t *tmp_next;/*next item in temporary doubly-linked list */ + struct H5D_rdcc_ent_t *tmp_prev;/*previous item in temporary doubly-linked list */ +} H5D_rdcc_ent_t; +typedef H5D_rdcc_ent_t *H5D_rdcc_ent_ptr_t; /* For free lists */ + /* Callback info for iteration to prune chunks */ typedef struct H5D_chunk_it_ud1_t { H5D_chunk_common_ud_t common; /* Common info for B-tree user data (must be first) */ @@ -244,6 +263,11 @@ static herr_t H5D__chunk_flush_entry(const H5D_t *dset, hid_t dxpl_id, const H5D_dxpl_cache_t *dxpl_cache, H5D_rdcc_ent_t *ent, hbool_t reset); static herr_t H5D__chunk_cache_evict(const H5D_t *dset, hid_t dxpl_id, const H5D_dxpl_cache_t *dxpl_cache, H5D_rdcc_ent_t *ent, hbool_t flush); +static void *H5D__chunk_lock(const H5D_io_info_t *io_info, + H5D_chunk_ud_t *udata, hbool_t relax); +static herr_t H5D__chunk_unlock(const H5D_io_info_t *io_info, + const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk, + uint32_t naccessed); static herr_t H5D__chunk_cache_prune(const H5D_t *dset, hid_t dxpl_id, const H5D_dxpl_cache_t *dxpl_cache, size_t size); static herr_t H5D__chunk_prune_fill(H5D_chunk_it_ud1_t *udata); @@ -3008,7 +3032,7 @@ done: * *------------------------------------------------------------------------- */ -void * +static void * H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, hbool_t relax) { @@ -3024,7 +3048,7 @@ H5D__chunk_lock(const H5D_io_info_t *io_info, H5D_chunk_ud_t *udata, void *chunk = NULL; /*the file chunk */ void *ret_value = NULL; /* Return value */ - FUNC_ENTER_PACKAGE + FUNC_ENTER_STATIC HDassert(io_info); HDassert(io_info->dxpl_cache); @@ -3286,7 +3310,7 @@ done: * *------------------------------------------------------------------------- */ -herr_t +static herr_t H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk, uint32_t naccessed) { @@ -3294,7 +3318,7 @@ H5D__chunk_unlock(const H5D_io_info_t *io_info, const H5D_chunk_ud_t *udata, const H5D_rdcc_t *rdcc = &(io_info->dset->shared->cache.chunk); herr_t ret_value = SUCCEED; /* Return value */ - FUNC_ENTER_PACKAGE + FUNC_ENTER_STATIC /* Sanity check */ HDassert(io_info); diff --git a/src/H5Dpkg.h b/src/H5Dpkg.h index 4e6376b..97fc442 100644 --- a/src/H5Dpkg.h +++ b/src/H5Dpkg.h @@ -369,6 +369,7 @@ typedef struct H5D_chunk_cached_t { } H5D_chunk_cached_t; /* The raw data chunk cache */ +struct H5D_rdcc_ent_t; /* Forward declaration of struct used below */ typedef struct H5D_rdcc_t { struct { unsigned ninits; /* Number of chunk creations */ @@ -497,25 +498,6 @@ typedef struct { hsize_t size; /* Accumulated number of bytes for the selection */ } H5D_vlen_bufsize_t; -/* Raw data chunks are cached. Each entry in the cache is: */ -typedef struct H5D_rdcc_ent_t { - hbool_t locked; /*entry is locked in cache */ - hbool_t dirty; /*needs to be written to disk? */ - hbool_t deleted; /*chunk about to be deleted */ - hsize_t scaled[H5O_LAYOUT_NDIMS]; /*scaled chunk 'name' (coordinates) */ - uint32_t rd_count; /*bytes remaining to be read */ - uint32_t wr_count; /*bytes remaining to be written */ - H5F_block_t chunk_block; /*offset/length of chunk in file */ - hsize_t chunk_idx; /*index of chunk in dataset */ - uint8_t *chunk; /*the unfiltered chunk data */ - unsigned idx; /*index in hash table */ - struct H5D_rdcc_ent_t *next;/*next item in doubly-linked list */ - struct H5D_rdcc_ent_t *prev;/*previous item in doubly-linked list */ - struct H5D_rdcc_ent_t *tmp_next;/*next item in temporary doubly-linked list */ - struct H5D_rdcc_ent_t *tmp_prev;/*previous item in temporary doubly-linked list */ -} H5D_rdcc_ent_t; -typedef H5D_rdcc_ent_t *H5D_rdcc_ent_ptr_t; /* For free lists */ - /*****************************/ /* Package Private Variables */ @@ -623,11 +605,6 @@ H5_DLL herr_t H5D__chunk_set_info(const H5D_t *dset); H5_DLL hbool_t H5D__chunk_is_space_alloc(const H5O_storage_t *storage); H5_DLL herr_t H5D__chunk_lookup(const H5D_t *dset, hid_t dxpl_id, const hsize_t *scaled, H5D_chunk_ud_t *udata); -H5_DLL void *H5D__chunk_lock(const H5D_io_info_t *io_info, - H5D_chunk_ud_t *udata, hbool_t relax); -H5_DLL herr_t H5D__chunk_unlock(const H5D_io_info_t *io_info, - const H5D_chunk_ud_t *udata, hbool_t dirty, void *chunk, - uint32_t naccessed); H5_DLL herr_t H5D__chunk_allocated(H5D_t *dset, hid_t dxpl_id, hsize_t *nbytes); H5_DLL herr_t H5D__chunk_allocate(const H5D_t *dset, hid_t dxpl_id, hbool_t full_overwrite, hsize_t old_dim[]); diff --git a/src/H5MM.c b/src/H5MM.c index a37bbff..05bfb9e 100644 --- a/src/H5MM.c +++ b/src/H5MM.c @@ -25,9 +25,195 @@ */ -#include "H5private.h" -#include "H5Eprivate.h" -#include "H5MMprivate.h" +/****************/ +/* Module Setup */ +/****************/ + + +/***********/ +/* Headers */ +/***********/ +#include "H5private.h" /* Generic Functions */ +#include "H5Eprivate.h" /* Error handling */ +#include "H5MMprivate.h" /* Memory management */ + + +/****************/ +/* Local Macros */ +/****************/ +#if defined H5_MEMORY_ALLOC_SANITY_CHECK +#define H5MM_SIG_SIZE 4 +#define H5MM_HEAD_GUARD_SIZE 8 +#define H5MM_TAIL_GUARD_SIZE 8 +#define H5MM_BLOCK_FROM_BUF(mem) ((H5MM_block_t *)((unsigned char *)mem - (offsetof(H5MM_block_t, b) + H5MM_HEAD_GUARD_SIZE))) +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + + +/******************/ +/* Local Typedefs */ +/******************/ + +#if defined H5_MEMORY_ALLOC_SANITY_CHECK +/* Memory allocation "block", wrapped around each allocation */ +struct H5MM_block_t; /* Forward declaration for typedef */ +typedef struct H5MM_block_t { + unsigned char sig[H5MM_SIG_SIZE]; /* Signature for the block, to indicate it was allocated with H5MM* interface */ + struct H5MM_block_t *next; /* Pointer to next block in the list of allocated blocks */ + struct H5MM_block_t *prev; /* Pointer to previous block in the list of allocated blocks */ + size_t size; + hbool_t in_use; + unsigned char b[]; +} H5MM_block_t; +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + + +/********************/ +/* Local Prototypes */ +/********************/ +#if defined H5_MEMORY_ALLOC_SANITY_CHECK +static hbool_t H5MM__is_our_block(void *mem); +static void H5MM__sanity_check_block(const H5MM_block_t *block); +static void H5MM__sanity_check(void *mem); +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + + +/*********************/ +/* Package Variables */ +/*********************/ + + +/*****************************/ +/* Library Private Variables */ +/*****************************/ + + +/*******************/ +/* Local Variables */ +/*******************/ + +#if defined H5_MEMORY_ALLOC_SANITY_CHECK +/* Constant strings for block signature, head & tail guards */ +static const char H5MM_block_signature_s[H5MM_SIG_SIZE] = {'H', '5', 'M', 'M'}; +static const char H5MM_block_head_guard_s[H5MM_HEAD_GUARD_SIZE] = {'D', 'E', 'A', 'D', 'B', 'E', 'E', 'F'}; +static const char H5MM_block_tail_guard_s[H5MM_TAIL_GUARD_SIZE] = {'B', 'E', 'E', 'F', 'D', 'E', 'A', 'D'}; + +/* Flag to indicate the the interface has been initialized */ +static hbool_t H5MM_init_s = FALSE; + +/* Head of the list of allocated blocks */ +static H5MM_block_t H5MM_block_head_s; + +/* Statistics about block allocations */ +static unsigned long long H5MM_total_alloc_bytes_s = 0; +static unsigned long long H5MM_curr_alloc_bytes_s = 0; +static unsigned long long H5MM_peak_alloc_bytes_s = 0; +static size_t H5MM_max_block_size_s = 0; +static size_t H5MM_total_alloc_blocks_count_s = 0; +static size_t H5MM_curr_alloc_blocks_count_s = 0; +static size_t H5MM_peak_alloc_blocks_count_s = 0; +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + + +#if defined H5_MEMORY_ALLOC_SANITY_CHECK + +/*------------------------------------------------------------------------- + * Function: H5MM__is_our_block + * + * Purpose: Try to determine if a memory buffer has been allocated through + * the H5MM* interface, instead of the system's malloc() routines. + * + * Return: Success: TRUE/FALSE + * Failure: (Can't fail) + * + * Programmer: Quincey Koziol + * Dec 30 2015 + * + *------------------------------------------------------------------------- + */ +static hbool_t +H5MM__is_our_block(void *mem) +{ + H5MM_block_t *block = H5MM_BLOCK_FROM_BUF(mem); + + return(0 == HDmemcmp(block->sig, H5MM_block_signature_s, H5MM_SIG_SIZE)); +} + + +/*------------------------------------------------------------------------- + * Function: H5MM__sanity_check_block + * + * Purpose: Check a block wrapper around a buffer to validate it. + * + * Return: N/A (void) + * + * Programmer: Quincey Koziol + * Dec 30 2015 + * + *------------------------------------------------------------------------- + */ +static void +H5MM__sanity_check_block(const H5MM_block_t *block) +{ + HDassert(block->size > 0); + HDassert(block->in_use); + /* Check for head & tail guards, if not head of linked list */ + if(block->size != SIZE_T_MAX) { + HDassert(0 == HDmemcmp(block->b, H5MM_block_head_guard_s, H5MM_HEAD_GUARD_SIZE)); + HDassert(0 == HDmemcmp(block->b + H5MM_HEAD_GUARD_SIZE + block->size, H5MM_block_tail_guard_s, H5MM_TAIL_GUARD_SIZE)); + } +} + + +/*------------------------------------------------------------------------- + * Function: H5MM__sanity_check + * + * Purpose: Check a buffer to validate it (just calls + * H5MM__sanity_check_block after finding block for buffer) + * + * Return: N/A (void) + * + * Programmer: Quincey Koziol + * Dec 30 2015 + * + *------------------------------------------------------------------------- + */ +static void +H5MM__sanity_check(void *mem) +{ + H5MM_block_t *block = H5MM_BLOCK_FROM_BUF(mem); + + H5MM__sanity_check_block(block); +} + + +/*------------------------------------------------------------------------- + * Function: H5MM_final_sanity_check + * + * Purpose: Final sanity checks on memory allocation. + * + * Return: N/A (void) + * + * Programmer: Quincey Koziol + * Jan 1 2016 + * + *------------------------------------------------------------------------- + */ +void +H5MM_final_sanity_check(void) +{ + HDassert(0 == H5MM_curr_alloc_bytes_s); + HDassert(0 == H5MM_curr_alloc_blocks_count_s); + HDassert(H5MM_block_head_s.next == &H5MM_block_head_s); + HDassert(H5MM_block_head_s.prev == &H5MM_block_head_s); +#ifdef H5MM_PRINT_MEMORY_STATS + HDfprintf(stderr, "%s: H5MM_total_alloc_bytes_s = %llu\n", __func__, H5MM_total_alloc_bytes_s); + HDfprintf(stderr, "%s: H5MM_peak_alloc_bytes_s = %llu\n", __func__, H5MM_peak_alloc_bytes_s); + HDfprintf(stderr, "%s: H5MM_max_block_size_s = %zu\n", __func__, H5MM_max_block_size_s); + HDfprintf(stderr, "%s: H5MM_total_alloc_blocks_count_s = %zu\n", __func__, H5MM_total_alloc_blocks_count_s); + HDfprintf(stderr, "%s: H5MM_peak_alloc_blocks_count_s = %zu\n", __func__, H5MM_peak_alloc_blocks_count_s); +#endif /* H5MM_PRINT_MEMORY_STATS */ +} +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ /*------------------------------------------------------------------------- @@ -42,7 +228,6 @@ * bytes usually indicate problems. * * Return: Success: Pointer new memory - * * Failure: NULL * * Programmer: Quincey Koziol @@ -60,12 +245,61 @@ H5MM_malloc(size_t size) /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ FUNC_ENTER_NOAPI_NOINIT_NOERR - if(size) +#if defined H5_MEMORY_ALLOC_SANITY_CHECK + /* Initialize block list head singleton */ + if(!H5MM_init_s) { + HDmemcpy(H5MM_block_head_s.sig, H5MM_block_signature_s, H5MM_SIG_SIZE); + H5MM_block_head_s.next = &H5MM_block_head_s; + H5MM_block_head_s.prev = &H5MM_block_head_s; + H5MM_block_head_s.size = SIZE_T_MAX; + H5MM_block_head_s.in_use = TRUE; + + H5MM_init_s = TRUE; + } /* end if */ +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + + if(size) { +#if defined H5_MEMORY_ALLOC_SANITY_CHECK + H5MM_block_t *block; + size_t alloc_size = sizeof(H5MM_block_t) + size + H5MM_HEAD_GUARD_SIZE + H5MM_TAIL_GUARD_SIZE; + + if(NULL != (block = (H5MM_block_t *)HDmalloc(alloc_size))) { + /* Set up block */ + HDmemcpy(block->sig, H5MM_block_signature_s, H5MM_SIG_SIZE); + block->next = H5MM_block_head_s.next; + H5MM_block_head_s.next = block; + block->next->prev = block; + block->prev = &H5MM_block_head_s; + block->size = size; + block->in_use = TRUE; + HDmemcpy(block->b, H5MM_block_head_guard_s, H5MM_HEAD_GUARD_SIZE); + HDmemcpy(block->b + H5MM_HEAD_GUARD_SIZE + size, H5MM_block_tail_guard_s, H5MM_TAIL_GUARD_SIZE); + + /* Update statistics */ + H5MM_total_alloc_bytes_s += size; + H5MM_curr_alloc_bytes_s += size; + if(H5MM_curr_alloc_bytes_s > H5MM_peak_alloc_bytes_s) + H5MM_peak_alloc_bytes_s = H5MM_curr_alloc_bytes_s; + if(size > H5MM_max_block_size_s) + H5MM_max_block_size_s = size; + H5MM_total_alloc_blocks_count_s++; + H5MM_curr_alloc_blocks_count_s++; + if(H5MM_curr_alloc_blocks_count_s > H5MM_peak_alloc_blocks_count_s) + H5MM_peak_alloc_blocks_count_s = H5MM_curr_alloc_blocks_count_s; + + /* Set buffer to return */ + ret_value = block->b + H5MM_HEAD_GUARD_SIZE; + } /* end if */ + else + ret_value = NULL; +#else /* H5_MEMORY_ALLOC_SANITY_CHECK */ ret_value = HDmalloc(size); +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + } /* end if */ else ret_value = NULL; - FUNC_LEAVE_NOAPI(ret_value); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5MM_malloc() */ @@ -83,7 +317,6 @@ H5MM_malloc(size_t size) * * * Return: Success: Pointer new memory - * * Failure: NULL * * Programmer: Quincey Koziol @@ -101,12 +334,18 @@ H5MM_calloc(size_t size) /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ FUNC_ENTER_NOAPI_NOINIT_NOERR - if(size) + if(size) { +#if defined H5_MEMORY_ALLOC_SANITY_CHECK + if(NULL != (ret_value = H5MM_malloc(size))) + HDmemset(ret_value, 0, size); +#else /* H5_MEMORY_ALLOC_SANITY_CHECK */ ret_value = HDcalloc((size_t)1, size); +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + } /* end if */ else ret_value = NULL; - FUNC_LEAVE_NOAPI(ret_value); + FUNC_LEAVE_NOAPI(ret_value) } /* end H5MM_calloc() */ @@ -123,9 +362,7 @@ H5MM_calloc(size_t size) * Note that the (NULL, 0) combination is undefined behavior * in the C standard. * - * Return: Success: Ptr to new memory if size > 0 - * NULL if size is zero - * + * Return: Success: Ptr to new memory if size > 0, NULL if size is zero * Failure: NULL (input buffer is unchanged on failure) * * Programmer: Robb Matzke @@ -143,17 +380,39 @@ H5MM_realloc(void *mem, size_t size) HDassert(mem || size); - if(NULL == mem && 0 == size) { + if(NULL == mem && 0 == size) /* Not defined in the standard, return NULL */ ret_value = NULL; - } else { +#if defined H5_MEMORY_ALLOC_SANITY_CHECK + if(size > 0) { + if(mem) { + if(H5MM__is_our_block(mem)) { + H5MM_block_t *block = H5MM_BLOCK_FROM_BUF(mem); + size_t old_size = block->size; + + H5MM__sanity_check(mem); + + ret_value = H5MM_malloc(size); + HDmemcpy(ret_value, mem, MIN(size, old_size)); + H5MM_xfree(mem); + } /* end if */ + else + ret_value = HDrealloc(mem, size); + } + else + ret_value = H5MM_malloc(size); + } + else + ret_value = H5MM_xfree(mem); +#else /* H5_MEMORY_ALLOC_SANITY_CHECK */ ret_value = HDrealloc(mem, size); /* Some platforms do not return NULL if size is zero. */ if(0 == size) ret_value = NULL; - } +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + } /* end else */ FUNC_LEAVE_NOAPI(ret_value) } /* end H5MM_realloc() */ @@ -250,8 +509,38 @@ H5MM_xfree(void *mem) /* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */ FUNC_ENTER_NOAPI_NOINIT_NOERR - if(mem) + if(mem) { +#if defined H5_MEMORY_ALLOC_SANITY_CHECK + if(H5MM__is_our_block(mem)) { + H5MM_block_t *block = H5MM_BLOCK_FROM_BUF(mem); + + /* Run sanity checks on this block and its neighbors */ + H5MM__sanity_check(mem); + H5MM__sanity_check_block(block->next); + H5MM__sanity_check_block(block->prev); + + /* Update statistics */ + H5MM_curr_alloc_bytes_s -= block->size; + H5MM_curr_alloc_blocks_count_s--; + + /* Reset block info */ + HDmemset(block->sig, 0, H5MM_SIG_SIZE); + block->next->prev = block->prev; + block->prev->next = block->next; + block->next = NULL; + block->prev = NULL; + block->in_use = FALSE; + + /* Free the block (finally!) */ + HDfree(block); + } + else + HDfree(mem); +#else /* H5_MEMORY_ALLOC_SANITY_CHECK */ HDfree(mem); +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + } /* end if */ - FUNC_LEAVE_NOAPI(NULL); + FUNC_LEAVE_NOAPI(NULL) } /* end H5MM_xfree() */ + diff --git a/src/H5MMprivate.h b/src/H5MMprivate.h index 0d608b2..c494a60 100644 --- a/src/H5MMprivate.h +++ b/src/H5MMprivate.h @@ -21,8 +21,6 @@ * * Purpose: Private header for memory management. * - * Modifications: - * *------------------------------------------------------------------------- */ #ifndef _H5MMprivate_H @@ -33,7 +31,12 @@ /* Private headers needed by this file */ #include "H5private.h" +#if defined H5_MEMORY_ALLOC_SANITY_CHECK +/*#define H5MM_PRINT_MEMORY_STATS */ +#define H5MM_free(Z) H5MM_xfree(Z) +#else /* H5_MEMORY_ALLOC_SANITY_CHECK */ #define H5MM_free(Z) HDfree(Z) +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ /* * Library prototypes... @@ -44,5 +47,9 @@ H5_DLL void *H5MM_realloc(void *mem, size_t size); H5_DLL char *H5MM_xstrdup(const char *s); H5_DLL char *H5MM_strdup(const char *s); H5_DLL void *H5MM_xfree(void *mem); +#if defined H5_MEMORY_ALLOC_SANITY_CHECK +H5_DLL void H5MM_final_sanity_check(void); +#endif /* H5_MEMORY_ALLOC_SANITY_CHECK */ + +#endif /* _H5MMprivate_H */ -#endif diff --git a/src/libhdf5.settings.in b/src/libhdf5.settings.in index 2355543..90224c1 100644 --- a/src/libhdf5.settings.in +++ b/src/libhdf5.settings.in @@ -66,6 +66,7 @@ Features: dmalloc: @HAVE_DMALLOC@ Clear file buffers before write: @CLEARFILEBUF@ Using memory checker: @USINGMEMCHECKER@ +Memory allocation sanity checks: @MEMORYALLOCSANITYCHECK@ Function Stack Tracing: @CODESTACK@ Strict File Format Checks: @STRICT_FORMAT_CHECKS@ Optimization Instrumentation: @INSTRUMENT@ -- cgit v0.12