Skip to content

Commit 4d501c4

Browse files
authored
Merge pull request contiki-ng#2830 from nvt/heapmem-calloc
heapmem: add a calloc function
2 parents ad65987 + de92e2e commit 4d501c4

File tree

5 files changed

+93
-19
lines changed

5 files changed

+93
-19
lines changed

os/lib/heapmem.c

+26-4
Original file line numberDiff line numberDiff line change
@@ -384,13 +384,12 @@ heapmem_zone_alloc_debug(heapmem_zone_t zone, size_t size,
384384
heapmem_zone_alloc(heapmem_zone_t zone, size_t size)
385385
#endif
386386
{
387-
/* Fail early on too large allocation requests to prevent wrapping values. */
388-
if(size > HEAPMEM_ARENA_SIZE) {
387+
if(zone >= HEAPMEM_MAX_ZONES || zones[zone].name == NULL) {
388+
LOG_WARN("Attempt to allocate from invalid zone: %u\n", zone);
389389
return NULL;
390390
}
391391

392-
if(zone >= HEAPMEM_MAX_ZONES || zones[zone].name == NULL) {
393-
LOG_WARN("Attempt to allocate from invalid zone: %u\n", zone);
392+
if(size > HEAPMEM_ARENA_SIZE || size == 0) {
394393
return NULL;
395394
}
396395

@@ -587,6 +586,29 @@ heapmem_realloc(void *ptr, size_t size)
587586
}
588587
#endif /* HEAPMEM_REALLOC */
589588

589+
/* heapmem_calloc: Allocates memory for a zero-initialized array. */
590+
void *
591+
#if HEAPMEM_DEBUG
592+
heapmem_calloc_debug(size_t nmemb, size_t size,
593+
const char *file, const unsigned line)
594+
#else
595+
heapmem_calloc(size_t nmemb, size_t size)
596+
#endif
597+
{
598+
size_t total_size = nmemb * size;
599+
600+
/* Overflow check. */
601+
if(size == 0 || total_size / size != nmemb) {
602+
return NULL;
603+
}
604+
605+
void *ptr = heapmem_alloc(total_size);
606+
if(ptr != NULL) {
607+
memset(ptr, 0, total_size);
608+
}
609+
return ptr;
610+
}
611+
590612
/* heapmem_stats: Provides statistics regarding heap memory usage. */
591613
void
592614
heapmem_stats(heapmem_stats_t *stats)

os/lib/heapmem.h

+29-13
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ typedef uint8_t heapmem_zone_t;
101101

102102
/**
103103
* \brief Register a zone with a reserved subdivision of the heap.
104-
* \param name A pointer to a chunk that has been allocated using
105-
* heapmem_alloc() or heapmem_realloc().
104+
* \param name A string containing the name of the zone.
106105
* \param zone_size The number of bytes to reserve for the zone.
107106
* \return A zone ID if the allocation succeeds, or
108107
* HEAPMEM_ZONE_INVALID if it fails.
@@ -112,17 +111,25 @@ heapmem_zone_t heapmem_zone_register(const char *name, size_t zone_size);
112111

113112
#if HEAPMEM_DEBUG
114113

115-
#define heapmem_alloc(size) heapmem_zone_alloc_debug(HEAPMEM_ZONE_GENERAL, (size), __FILE__, __LINE__)
116-
#define heapmem_zone_alloc(zone, size) heapmem_zone_alloc_debug((zone), (size), __FILE__, __LINE__)
117-
#define heapmem_realloc(ptr, size) heapmem_realloc_debug((ptr), (size), __FILE__, __LINE__)
118-
#define heapmem_free(ptr) heapmem_free_debug((ptr), __FILE__, __LINE__)
114+
#define heapmem_alloc(size) \
115+
heapmem_zone_alloc_debug(HEAPMEM_ZONE_GENERAL, (size), __FILE__, __LINE__)
116+
#define heapmem_zone_alloc(zone, size) \
117+
heapmem_zone_alloc_debug((zone), (size), __FILE__, __LINE__)
118+
#define heapmem_realloc(ptr, size) \
119+
heapmem_realloc_debug((ptr), (size), __FILE__, __LINE__)
120+
#define heapmem_calloc(nmemb, size) \
121+
heapmem_calloc_debug((nmemb), (size), __FILE__, __LINE__)
122+
#define heapmem_free(ptr) \
123+
heapmem_free_debug((ptr), __FILE__, __LINE__)
119124

120125
void *heapmem_alloc_debug(size_t size,
121126
const char *file, const unsigned line);
122127
void *heapmem_zone_alloc_debug(heapmem_zone_t zone, size_t size,
123128
const char *file, const unsigned line);
124129
void *heapmem_realloc_debug(void *ptr, size_t size,
125130
const char *file, const unsigned line);
131+
void *heapmem_calloc_debug(size_t nmemb, size_t size,
132+
const char *file, const unsigned line);
126133
bool heapmem_free_debug(void *ptr,
127134
const char *file, const unsigned line);
128135

@@ -137,7 +144,6 @@ bool heapmem_free_debug(void *ptr,
137144
* \sa heapmem_realloc
138145
* \sa heapmem_free
139146
*/
140-
141147
#define heapmem_alloc(size) heapmem_zone_alloc(HEAPMEM_ZONE_GENERAL, (size))
142148

143149
/**
@@ -155,7 +161,7 @@ void *heapmem_zone_alloc(heapmem_zone_t zone, size_t size);
155161
/**
156162
* \brief Reallocate a chunk of memory in the heap.
157163
* \param ptr A pointer to a chunk that has been allocated using
158-
* heapmem_alloc() or heapmem_realloc().
164+
* heapmem_alloc(), heapmem_calloc(), or heapmem_realloc().
159165
* \param size The number of bytes to allocate.
160166
* \return A pointer to the allocated memory chunk,
161167
* or NULL if the allocation failed.
@@ -165,24 +171,36 @@ void *heapmem_zone_alloc(heapmem_zone_t zone, size_t size);
165171
* the chunk and returns NULL.
166172
*
167173
* \sa heapmem_alloc
174+
* \sa heapmem_calloc
168175
* \sa heapmem_free
169176
*/
170-
171177
void *heapmem_realloc(void *ptr, size_t size);
172178

179+
/**
180+
* \brief Allocate memory for a zero-initialized array.
181+
* \param nmemb The number of elements to allocate.
182+
* \param size The size of each element.
183+
* \return A pointer to the allocated memory,
184+
* or NULL if the allocation failed.
185+
*
186+
* \sa heapmem_alloc
187+
* \sa heapmem_free
188+
*/
189+
void *heapmem_calloc(size_t nmemb, size_t size);
190+
173191
/**
174192
* \brief Deallocate a chunk of memory.
175193
* \param ptr A pointer to a chunk that has been allocated using
176-
* heapmem_alloc() or heapmem_realloc().
194+
* heapmem_alloc(), heapmem_calloc(), or heapmem_realloc().
177195
* \return A boolean indicating whether the memory could be deallocated.
178196
*
179197
* \note If ptr is NULL, this function will return immediately without
180198
* performing any action.
181199
*
182200
* \sa heapmem_alloc
201+
* \sa heapmem_calloc
183202
* \sa heapmem_realloc
184203
*/
185-
186204
bool heapmem_free(void *ptr);
187205

188206
#endif /* HEAPMEM_DEBUG */
@@ -199,14 +217,12 @@ bool heapmem_free(void *ptr);
199217
* and the number of chunks allocated. By using this information, developers
200218
* can tune their software to use the heapmem allocator more efficiently.
201219
*/
202-
203220
void heapmem_stats(heapmem_stats_t *stats);
204221

205222
/**
206223
* \brief Obtain the minimum alignment of allocated addresses.
207224
* \return The alignment value, which is a power of two.
208225
*/
209-
210226
size_t heapmem_alignment(void);
211227

212228
#endif /* !HEAPMEM_H */

tests/08-native-runs/12-heapmem/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
all: test-heapmem
1+
CONTIKI_PROJECT = test-heapmem
2+
all: $(CONTIKI_PROJECT)
23

34
TARGET ?= native
45

tests/08-native-runs/12-heapmem/test-heapmem.c

+34
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,37 @@ UNIT_TEST(reallocations)
237237

238238
UNIT_TEST_END();
239239
}
240+
/*****************************************************************************/UNIT_TEST_REGISTER(zero_init_alloc, "Heapmem calloc");
241+
UNIT_TEST(zero_init_alloc)
242+
{
243+
#define MAX_SIZE 500
244+
#define NUM_ALLOCS 10
245+
246+
UNIT_TEST_BEGIN();
247+
248+
void *ptr1 = heapmem_calloc(0, MAX_SIZE);
249+
UNIT_TEST_ASSERT(ptr1 == NULL);
250+
251+
void *ptr2 = heapmem_calloc(1, 0);
252+
UNIT_TEST_ASSERT(ptr2 == NULL);
253+
254+
uint8_t *ptr_array[NUM_ALLOCS];
255+
for(size_t i = 1; i <= NUM_ALLOCS; i++) {
256+
size_t nmemb = i * 10;
257+
size_t size = MAX_SIZE / i;
258+
ptr_array[i - 1] = heapmem_calloc(nmemb, size);
259+
UNIT_TEST_ASSERT(ptr_array[i - 1] != NULL);
260+
for(size_t j = 0; j < nmemb * size; j++) {
261+
UNIT_TEST_ASSERT(ptr_array[i - 1][j] == 0);
262+
}
263+
}
264+
265+
for(size_t i = 1; i <= NUM_ALLOCS; i++) {
266+
UNIT_TEST_ASSERT(heapmem_free(ptr_array[NUM_ALLOCS - i]));
267+
}
268+
269+
UNIT_TEST_END();
270+
}
240271
/*****************************************************************************/
241272
UNIT_TEST_REGISTER(stats_check, "Heapmem statistics validation");
242273
UNIT_TEST(stats_check)
@@ -301,12 +332,15 @@ PROCESS_THREAD(test_heapmem_process, ev, data)
301332
UNIT_TEST_RUN(max_alloc);
302333
UNIT_TEST_RUN(invalid_freeing);
303334
UNIT_TEST_RUN(reallocations);
335+
UNIT_TEST_RUN(zero_init_alloc);
304336
UNIT_TEST_RUN(stats_check);
305337
UNIT_TEST_RUN(zones);
306338

307339
if(!UNIT_TEST_PASSED(do_many_allocations) ||
308340
!UNIT_TEST_PASSED(max_alloc) ||
309341
!UNIT_TEST_PASSED(invalid_freeing) ||
342+
!UNIT_TEST_PASSED(reallocations) ||
343+
!UNIT_TEST_PASSED(zero_init_alloc) ||
310344
!UNIT_TEST_PASSED(stats_check) ||
311345
!UNIT_TEST_PASSED(zones)) {
312346
printf("=check-me= FAILED\n");

tests/08-native-runs/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ examples/hello-world/native:./08-native-ping.sh \
1515
examples/coap/coap-example-server/native:./09-native-coap.sh \
1616
examples/snmp-server/native:./10-snmp-server.sh \
1717
tests/08-native-runs/11-aes-ccm/native:./11-aes-ccm.sh \
18-
tests/08-native-runs/12-heapmem/native:./12-heapmem.sh \
18+
tests/08-native-runs/12-heapmem/native:./12-heapmem.sh:DEFINES=HEAPMEM_DEBUG=0 \
19+
tests/08-native-runs/12-heapmem/native:./12-heapmem.sh:DEFINES=HEAPMEM_DEBUG=1 \
1920
tests/08-native-runs/13-coffee/native:./13-coffee.sh
2021

2122

0 commit comments

Comments
 (0)