[svn-r26392] Reinstates r26327-8, which had been reverted due to failures on

Solaris and OS X.

Added public API functions that expose the C library's memory allocator
for use in filter functions that need to allocate or resize buffers.

Intended for use with filter plugins, particularly on Windows, where C
runtime (CRT) issues can cause problems.

Fixes: HDFFV-9100

Tested on: h5committest + OS X (quail) + Solaris (emu)
This commit is contained in:
Dana Robinson 2015-03-08 19:41:54 -05:00
parent 63bd09ec8b
commit 2a4ea9b24e
6 changed files with 239 additions and 63 deletions

View File

@ -858,29 +858,111 @@ H5close(void)
FUNC_LEAVE_API_NOFS(SUCCEED)
} /* end H5close() */
/*-------------------------------------------------------------------------
* Function: H5allocate_memory
*
* Purpose: Allocate a memory buffer with the semantics of malloc().
*
* NOTE: This function is intended for use with filter
* plugins so that all allocation and free operations
* use the same memory allocator. It is not intended for
* use as a general memory allocator in applications.
*
* Parameters:
*
* size: The size of the buffer.
*
* clear: Whether or not to memset the buffer to 0.
*
* Return:
*
* Success: A pointer to the allocated buffer.
*
* Failure: NULL
*
*-------------------------------------------------------------------------
*/
void *
H5allocate_memory(size_t size, hbool_t clear)
{
void *ret_value = NULL;
FUNC_ENTER_API_NOINIT;
H5TRACE2("*x", "zb", size, clear);
if(clear)
ret_value = H5MM_calloc(size);
else
ret_value = H5MM_malloc(size);
FUNC_LEAVE_API(ret_value)
} /* end H5allocate_memory() */
/*-------------------------------------------------------------------------
* Function: H5resize_memory
*
* Purpose: Resize a memory buffer with the semantics of realloc().
*
* NOTE: This function is intended for use with filter
* plugins so that all allocation and free operations
* use the same memory allocator. It is not intended for
* use as a general memory allocator in applications.
*
* Parameters:
*
* mem: The buffer to be resized.
*
* size: The size of the buffer.
*
* Return:
*
* Success: A pointer to the resized buffer.
*
* Failure: NULL (the input buffer will be unchanged)
*
*-------------------------------------------------------------------------
*/
void *
H5resize_memory(void *mem, size_t size)
{
void *ret_value = NULL;
FUNC_ENTER_API_NOINIT;
H5TRACE2("*x", "*xz", mem, size);
ret_value = H5MM_realloc(mem, size);
FUNC_LEAVE_API(ret_value)
} /* end H5resize_memory() */
/*-------------------------------------------------------------------------
* Function: H5free_memory
*
* Purpose: Frees memory allocated by the library that it is the user's
* Purpose: Frees memory allocated by the library that it is the user's
* responsibility to free. Ensures that the same library
* that was used to allocate the memory frees it. Passing
* NULL pointers is allowed.
*
* Return: SUCCEED/FAIL
* Return: SUCCEED/FAIL
*
*-------------------------------------------------------------------------
*/
herr_t
H5free_memory(void *mem)
{
FUNC_ENTER_API_NOINIT
FUNC_ENTER_API_NOINIT;
H5TRACE1("e", "*x", mem);
/* At this time, it is impossible for this to fail. */
HDfree(mem);
FUNC_LEAVE_API(SUCCEED)
} /* end H5free_memory() */
@ -944,3 +1026,4 @@ DllMain(_In_ HINSTANCE hinstDLL, _In_ DWORD fdwReason, _In_ LPVOID lpvReserved)
return fOkay;
}
#endif /* H5_HAVE_WIN32_API && H5_BUILT_AS_DYNAMIC_LIB && H5_HAVE_WIN_THREADS && H5_HAVE_THREADSAFE*/

View File

@ -31,93 +31,107 @@
#include "H5Eprivate.h"
#include "H5MMprivate.h"
#ifndef NDEBUG
/*-------------------------------------------------------------------------
* Function: H5MM_malloc
* Function: H5MM_malloc
*
* Purpose: Just like the POSIX version of malloc(3). This routine
* specifically checks for allocations of 0 bytes and fails
* in that case. This routine is not called when NDEBUG is
* defined.
* Purpose: Similar to the C89 version of malloc().
*
* Return: Success: Ptr to new memory
* On size of 0, we return a NULL pointer instead of the
* standard-allowed 'special' pointer since that's more
* difficult to check as a return value. This is still
* considered an error condition since allocations of zero
* bytes usually indicate problems.
*
* Return: Success: Pointer new memory
*
* Failure: NULL
* Failure: NULL
*
* Programmer: Quincey Koziol
* koziol@ncsa.uiuc.edu
* Nov 8 2003
*
* Modifications:
* Programmer: Quincey Koziol
* Nov 8 2003
*
*-------------------------------------------------------------------------
*/
void *
H5MM_malloc(size_t size)
{
/* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
FUNC_ENTER_NOAPI_NOINIT_NOERR
void *ret_value;
HDassert(size);
FUNC_LEAVE_NOAPI(HDmalloc(size));
/* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
FUNC_ENTER_NOAPI_NOINIT_NOERR
if(size)
ret_value = HDmalloc(size);
else
ret_value = NULL;
FUNC_LEAVE_NOAPI(ret_value);
} /* end H5MM_malloc() */
/*-------------------------------------------------------------------------
* Function: H5MM_calloc
* Function: H5MM_calloc
*
* Purpose: Similar to the POSIX version of calloc(3), except this routine
* just takes a 'size' parameter. This routine
* specifically checks for allocations of 0 bytes and fails
* in that case. This routine is not called when NDEBUG is
* defined.
* Purpose: Similar to the C89 version of calloc(), except this
* routine just takes a 'size' parameter.
*
* Return: Success: Ptr to new memory
* On size of 0, we return a NULL pointer instead of the
* standard-allowed 'special' pointer since that's more
* difficult to check as a return value. This is still
* considered an error condition since allocations of zero
* bytes usually indicate problems.
*
* Failure: NULL
*
* Return: Success: Pointer new memory
*
* Failure: NULL
*
* Programmer: Quincey Koziol
* koziol@ncsa.uiuc.edu
* Nov 8 2003
*
* Modifications:
* Nov 8 2003
*
*-------------------------------------------------------------------------
*/
void *
H5MM_calloc(size_t size)
{
/* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
FUNC_ENTER_NOAPI_NOINIT_NOERR
void *ret_value;
HDassert(size);
FUNC_LEAVE_NOAPI(HDcalloc(1,size));
/* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
FUNC_ENTER_NOAPI_NOINIT_NOERR
if(size)
ret_value = HDcalloc((size_t)1, size);
else
ret_value = NULL;
FUNC_LEAVE_NOAPI(ret_value);
} /* end H5MM_calloc() */
#endif /* NDEBUG */
/*-------------------------------------------------------------------------
* Function: H5MM_realloc
* Function: H5MM_realloc
*
* Purpose: Just like the POSIX version of realloc(3). Specifically, the
* following calls are equivalent
* Purpose: Similar semantics as C89's realloc(). Specifically, the
* following calls are equivalent:
*
* H5MM_realloc (NULL, size) <==> H5MM_malloc (size)
* H5MM_realloc (ptr, 0) <==> H5MM_xfree (ptr)
* H5MM_realloc (NULL, 0) <==> NULL
* H5MM_realloc(NULL, size) <==> H5MM_malloc(size)
* H5MM_realloc(ptr, 0) <==> H5MM_xfree(ptr)
* H5MM_realloc(NULL, 0) <==> NULL
*
* Return: Success: Ptr to new memory or NULL if the memory
* was freed or HDrealloc couldn't allocate
* memory.
* Note that the (NULL, 0) combination is undefined behavior
* in the C standard.
*
* Failure: NULL
* Return: Success: Ptr to new memory if size > 0
* NULL if size is zero
*
* Programmer: Robb Matzke
* matzke@llnl.gov
* Jul 10 1997
* Failure: NULL (input buffer is unchanged on failure)
*
* Programmer: Robb Matzke
* Jul 10 1997
*
*-------------------------------------------------------------------------
*/
@ -129,16 +143,19 @@ H5MM_realloc(void *mem, size_t size)
/* Use FUNC_ENTER_NOAPI_NOINIT_NOERR here to avoid performance issues */
FUNC_ENTER_NOAPI_NOINIT_NOERR
if(NULL == mem) {
if(0 == size)
HDassert(mem || size);
if(NULL == mem && 0 == size) {
/* Not defined in the standard, return NULL */
ret_value = NULL;
}
else {
ret_value = HDrealloc(mem, size);
/* Some platforms do not return NULL if size is zero. */
if(0 == size)
ret_value = NULL;
else
ret_value = H5MM_malloc(size);
} /* end if */
else if(0 == size)
ret_value = H5MM_xfree(mem);
else
ret_value = HDrealloc(mem, size);
}
FUNC_LEAVE_NOAPI(ret_value)
} /* end H5MM_realloc() */

View File

@ -33,19 +33,13 @@
/* Private headers needed by this file */
#include "H5private.h"
#ifdef NDEBUG
#define H5MM_malloc(Z) HDmalloc(Z)
#define H5MM_calloc(Z) HDcalloc((size_t)1,Z)
#endif /* NDEBUG */
#define H5MM_free(Z) HDfree(Z)
/*
* Library prototypes...
*/
#ifndef NDEBUG
H5_DLL void *H5MM_malloc(size_t size);
H5_DLL void *H5MM_calloc(size_t size);
#endif /* NDEBUG */
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);

View File

@ -332,6 +332,8 @@ H5_DLL herr_t H5get_libversion(unsigned *majnum, unsigned *minnum,
H5_DLL herr_t H5check_version(unsigned majnum, unsigned minnum,
unsigned relnum);
H5_DLL herr_t H5free_memory(void *mem);
H5_DLL void *H5allocate_memory(size_t size, hbool_t clear);
H5_DLL void *H5resize_memory(void *mem, size_t size);
#ifdef __cplusplus
}

View File

@ -68,6 +68,18 @@
} \
}
#define CHECK_PTR_NULL(ret,where) { \
if (VERBOSE_HI) { \
print_func(" Call to routine: %15s at line %4d in %s returned %p\n", \
(where), (int)__LINE__, __FILE__, (ret)); \
} \
if (ret) { \
TestErrPrintf ("*** UNEXPECTED RETURN from %s is not NULL line %4d in %s\n", \
(where), (int)__LINE__, __FILE__); \
H5Eprint2(H5E_DEFAULT, stdout); \
} \
}
/* Used to make certain a return value _is_ a value */
#define VERIFY(_x, _val, where) do { \
long __x = (long)_x, __val = (long)_val; \

View File

@ -5302,6 +5302,73 @@ test_misc31(void)
#endif /* H5_NO_DEPRECATED_SYMBOLS */
} /* end test_misc31() */
/****************************************************************
*
* test_misc32(): Simple test of filter memory allocation
* functions.
*
***************************************************************/
static void
test_misc32(void)
{
void *buffer;
void *resized;
size_t size;
/* Output message about test being performed */
MESSAGE(5, ("Edge case test of filter memory allocation functions\n"));
/* Test that the filter memory allocation functions behave correctly
* at edge cases.
*/
/* FREE */
/* Test freeing a NULL pointer.
* No real confirmation check here, but Valgrind will confirm no
* shenanigans.
*/
buffer = NULL;
H5free_memory(buffer);
/* ALLOCATE */
/* Size zero returns NULL.
* Also checks that a size of zero and setting the buffer clear flag
* to TRUE can be used together.
*
* Note that we have asserts in the code, so only check when NDEBUG
* is defined.
*/
#ifdef NDEBUG
buffer = H5allocate_memory(0, FALSE);
CHECK_PTR_NULL(buffer, "H5allocate_memory"); /*BAD*/
buffer = H5allocate_memory(0, TRUE);
CHECK_PTR_NULL(buffer, "H5allocate_memory"); /*BAD*/
#endif /* NDEBUG */
/* RESIZE */
/* Size zero returns NULL. Valgrind will confirm buffer is freed. */
size = 1024;
buffer = H5allocate_memory(size, TRUE);
resized = H5resize_memory(buffer, 0);
CHECK_PTR_NULL(resized, "H5resize_memory");
/* NULL input pointer returns new buffer */
resized = H5resize_memory(NULL, 1024);
CHECK_PTR(resized, "H5resize_memory");
H5free_memory(resized);
/* NULL input pointer and size zero returns NULL */
#ifdef NDEBUG
resized = H5resize_memory(NULL, 0);
CHECK_PTR_NULL(resized, "H5resize_memory"); /*BAD*/
#endif /* NDEBUG */
} /* end test_misc32() */
/****************************************************************
**
@ -5349,6 +5416,7 @@ test_misc(void)
test_misc29(); /* Test that speculative metadata reads are handled correctly */
test_misc30(); /* Exercise local heap loading bug where free lists were getting dropped */
test_misc31(); /* Test Reentering library through deprecated routines after H5close() */
test_misc32(); /* Test filter memory allocation functions */
} /* test_misc() */