abyss_mallocvar.h

00001 /* These are some dynamic memory allocation facilities.  They are essentially
00002    an extension to C, as they do allocations with a cognizance of C 
00003    variables.  You can use them to make C read more like a high level
00004    language.
00005 
00006    Before including this, you must define an __inline__ macro if your
00007    compiler doesn't recognize it as a keyword.
00008 */
00009 
00010 #ifndef MALLOCVAR_INCLUDED
00011 #define MALLOCVAR_INCLUDED
00012 
00013 #include <xmlrpc-c/config.h>
00014 
00015 #include <limits.h>
00016 #include <stdlib.h>
00017 
00018 static __inline__ void
00019 mallocProduct(void **      const resultP, 
00020               unsigned int const factor1,
00021               unsigned int const factor2) {
00022 /*----------------------------------------------------------------------------
00023    malloc a space whose size in bytes is the product of 'factor1' and
00024    'factor2'.  But if that size cannot be represented as an unsigned int,
00025    return NULL without allocating anything.  Also return NULL if the malloc
00026    fails.
00027 
00028    If either factor is zero, malloc a single byte.
00029 
00030    Note that malloc() actually takes a size_t size argument, so the
00031    proper test would be whether the size can be represented by size_t,
00032    not unsigned int.  But there is no reliable indication available to
00033    us, like UINT_MAX, of what the limitations of size_t are.  We
00034    assume size_t is at least as expressive as unsigned int and that
00035    nobody really needs to allocate more than 4GB of memory.
00036 -----------------------------------------------------------------------------*/
00037     if (factor1 == 0 || factor2 == 0)
00038         *resultP = malloc(1);
00039     else {
00040         if (UINT_MAX / factor2 < factor1) 
00041             *resultP = NULL;
00042         else 
00043             *resultP = malloc(factor1 * factor2); 
00044     }
00045 }
00046 
00047 
00048 
00049 static __inline__ void
00050 reallocProduct(void **      const blockP,
00051                unsigned int const factor1,
00052                unsigned int const factor2) {
00053     
00054     if (UINT_MAX / factor2 < factor1) 
00055         *blockP = NULL;
00056     else 
00057         *blockP = realloc(*blockP, factor1 * factor2); 
00058 }
00059 
00060 
00061 /* IMPLEMENTATION NOTE:  There are huge strict aliasing pitfalls here
00062    if you cast pointers, e.g. (void **)
00063 */
00064 
00065 #define MALLOCARRAY(arrayName, nElements) do { \
00066     void * array; \
00067     mallocProduct(&array, nElements, sizeof(arrayName[0])); \
00068     arrayName = array; \
00069 } while (0)
00070 
00071 #define REALLOCARRAY(arrayName, nElements) { \
00072     void * array = arrayName; \
00073     reallocProduct(&array, nElements, sizeof(arrayName[0])); \
00074     arrayName = array; \
00075 } while (0)
00076 
00077 
00078 #define MALLOCARRAY_NOFAIL(arrayName, nElements) \
00079 do { \
00080     MALLOCARRAY(arrayName, nElements); \
00081     if ((arrayName) == NULL) \
00082         abort(); \
00083 } while(0)
00084 
00085 #define REALLOCARRAY_NOFAIL(arrayName, nElements) \
00086 do { \
00087     REALLOCARRAY(arrayName, nElements); \
00088     if ((arrayName) == NULL) \
00089         abort(); \
00090 } while(0)
00091 
00092 
00093 #define MALLOCVAR(varName) \
00094     varName = malloc(sizeof(*varName))
00095 
00096 #define MALLOCVAR_NOFAIL(varName) \
00097     do {if ((varName = malloc(sizeof(*varName))) == NULL) abort();} while(0)
00098 
00099 #endif
00100