about summary refs log tree commit diff
path: root/lib/util/mallocvar.h
blob: b750e1776cf3c1d8be3c6573ac8f9c36398bbea6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/* These are some dynamic memory allocation facilities.  They are essentially
   an extension to C, as they do allocations with a cognizance of C 
   variables.  You can use them to make C read more like a high level
   language.

   Before including this, you must define an __inline__ macro if your
   compiler doesn't recognize it as a keyword.
*/

#ifndef MALLOCVAR_INCLUDED
#define MALLOCVAR_INCLUDED

#include "pm_config.h"

#include <limits.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* to fake out automatic code indenters */
#endif

static __inline__ void
mallocProduct(void **      const resultP, 
              unsigned int const factor1,
              unsigned int const factor2) {
/*----------------------------------------------------------------------------
   malloc a space whose size in bytes is the product of 'factor1' and
   'factor2'.  But if that size cannot be represented as an unsigned int,
   return NULL without allocating anything.  Also return NULL if the malloc
   fails.

   If either factor is zero, malloc a single byte.

   Note that malloc() actually takes a size_t size argument, so the
   proper test would be whether the size can be represented by size_t,
   not unsigned int.  But there is no reliable indication available to
   us, like UINT_MAX, of what the limitations of size_t are.  We
   assume size_t is at least as expressive as unsigned int and that
   nobody really needs to allocate more than 4GB of memory.
-----------------------------------------------------------------------------*/
    if (factor1 == 0 || factor2 == 0)
        *resultP = malloc(1);
    else {
        if (UINT_MAX / factor2 < factor1) 
            *resultP = NULL;
        else 
            *resultP = malloc(factor1 * factor2); 
    }
}



static __inline__ void
reallocProduct(void **      const blockP,
               unsigned int const factor1,
               unsigned int const factor2) {

    void * const oldBlockP = *blockP;

    void * newBlockP;
    
    if (UINT_MAX / factor2 < factor1) 
        newBlockP = NULL;
    else 
        newBlockP = realloc(oldBlockP, factor1 * factor2); 

    if (newBlockP)
        *blockP = newBlockP;
    else {
        free(oldBlockP);
        *blockP = NULL;
    }
}



#define MALLOCARRAY(arrayName, nElements) do { \
    void * array; \
    mallocProduct(&array, nElements, sizeof(arrayName[0])); \
    arrayName = array; \
} while (0)

#define REALLOCARRAY(arrayName, nElements) do { \
    void * array; \
    array = arrayName; \
    reallocProduct(&array, nElements, sizeof(arrayName[0])); \
    arrayName = array; \
} while (0)


#define MALLOCARRAY_NOFAIL(arrayName, nElements) \
do { \
    MALLOCARRAY(arrayName, nElements); \
    if ((arrayName) == NULL) \
        abort(); \
} while(0)

#define REALLOCARRAY_NOFAIL(arrayName, nElements) \
do { \
    REALLOCARRAY(arrayName, nElements); \
    if ((arrayName) == NULL) \
        abort(); \
} while(0)


#define MALLOCVAR(varName) \
    varName = malloc(sizeof(*varName))

#define MALLOCVAR_NOFAIL(varName) \
    do {if ((varName = malloc(sizeof(*varName))) == NULL) abort();} while(0)

#ifdef __cplusplus
}
#endif
#endif