summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQuincey Koziol <koziol@hdfgroup.org>2016-01-03 22:06:52 (GMT)
committerQuincey Koziol <koziol@hdfgroup.org>2016-01-03 22:06:52 (GMT)
commitf017eb6fc09d74aa83eb5391028be5fd12380d34 (patch)
treed620ad36aebcac2abae7776518fa72db3c1d141a
parentf8465bd1243d16783b4df44b40193d8f5137a781 (diff)
downloadhdf5-f017eb6fc09d74aa83eb5391028be5fd12380d34.zip
hdf5-f017eb6fc09d74aa83eb5391028be5fd12380d34.tar.gz
hdf5-f017eb6fc09d74aa83eb5391028be5fd12380d34.tar.bz2
[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)
-rw-r--r--CMakeLists.txt8
-rw-r--r--config/cmake/cacheinit.cmake2
-rw-r--r--config/cmake/libhdf5.settings.cmake.in1
-rw-r--r--config/cmake/mccacheinit.cmake2
-rw-r--r--configure.ac31
-rw-r--r--release_docs/INSTALL_CMake.txt2
-rw-r--r--src/H5.c5
-rw-r--r--src/H5Dchunk.c32
-rw-r--r--src/H5Dpkg.h25
-rw-r--r--src/H5MM.c323
-rw-r--r--src/H5MMprivate.h13
-rw-r--r--src/libhdf5.settings.in1
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@