xref: /netbsd-src/external/mit/libcbor/dist/test/memory_allocation_test.c (revision 5dd36a3bc8bf2a9dec29ceb6349550414570c447)
1*5dd36a3bSchristos /*
2*5dd36a3bSchristos  * Copyright (c) 2014-2019 Pavel Kalvoda <me@pavelkalvoda.com>
3*5dd36a3bSchristos  *
4*5dd36a3bSchristos  * libcbor is free software; you can redistribute it and/or modify
5*5dd36a3bSchristos  * it under the terms of the MIT license. See LICENSE for details.
6*5dd36a3bSchristos  */
7*5dd36a3bSchristos 
8*5dd36a3bSchristos #include <setjmp.h>
9*5dd36a3bSchristos #include <stdarg.h>
10*5dd36a3bSchristos #include <stddef.h>
11*5dd36a3bSchristos 
12*5dd36a3bSchristos #include <cmocka.h>
13*5dd36a3bSchristos 
14*5dd36a3bSchristos #include "cbor.h"
15*5dd36a3bSchristos 
16*5dd36a3bSchristos // This test simulates cases when malloc unexpectedly fails and leaves a
17*5dd36a3bSchristos // possibly partially constructed object behind. It this is especially useful
18*5dd36a3bSchristos // in conjunction with the memory correctness check.
19*5dd36a3bSchristos //
20*5dd36a3bSchristos // WARNING: The test only works with CBOR_CUSTOM_ALLOC
21*5dd36a3bSchristos 
22*5dd36a3bSchristos typedef enum call_expectation {
23*5dd36a3bSchristos   MALLOC,
24*5dd36a3bSchristos   MALLOC_FAIL,
25*5dd36a3bSchristos   REALLOC,
26*5dd36a3bSchristos   REALLOC_FAIL
27*5dd36a3bSchristos } call_expectation;
28*5dd36a3bSchristos 
29*5dd36a3bSchristos // How many alloc calls we expect
30*5dd36a3bSchristos int alloc_calls_expected;
31*5dd36a3bSchristos // How many alloc calls we got
32*5dd36a3bSchristos int alloc_calls;
33*5dd36a3bSchristos // Array of booleans indicating whether to return a block or fail with NULL
34*5dd36a3bSchristos call_expectation *expectations;
35*5dd36a3bSchristos 
set_mock_malloc(int calls,...)36*5dd36a3bSchristos void set_mock_malloc(int calls, ...) {
37*5dd36a3bSchristos   va_list args;
38*5dd36a3bSchristos   va_start(args, calls);
39*5dd36a3bSchristos   alloc_calls_expected = calls;
40*5dd36a3bSchristos   alloc_calls = 0;
41*5dd36a3bSchristos   expectations = calloc(calls, sizeof(expectations));
42*5dd36a3bSchristos   for (int i = 0; i < calls; i++) {
43*5dd36a3bSchristos     // Promotable types, baby
44*5dd36a3bSchristos     expectations[i] = va_arg(args, call_expectation);
45*5dd36a3bSchristos   }
46*5dd36a3bSchristos   va_end(args);
47*5dd36a3bSchristos }
48*5dd36a3bSchristos 
finalize_mock_malloc()49*5dd36a3bSchristos void finalize_mock_malloc() {
50*5dd36a3bSchristos   assert_int_equal(alloc_calls, alloc_calls_expected);
51*5dd36a3bSchristos   free(expectations);
52*5dd36a3bSchristos }
53*5dd36a3bSchristos 
instrumented_malloc(size_t size)54*5dd36a3bSchristos void *instrumented_malloc(size_t size) {
55*5dd36a3bSchristos   if (alloc_calls >= alloc_calls_expected) {
56*5dd36a3bSchristos     goto error;
57*5dd36a3bSchristos   }
58*5dd36a3bSchristos 
59*5dd36a3bSchristos   if (expectations[alloc_calls] == MALLOC) {
60*5dd36a3bSchristos     alloc_calls++;
61*5dd36a3bSchristos     return malloc(size);
62*5dd36a3bSchristos   } else if (expectations[alloc_calls] == MALLOC_FAIL) {
63*5dd36a3bSchristos     alloc_calls++;
64*5dd36a3bSchristos     return NULL;
65*5dd36a3bSchristos   }
66*5dd36a3bSchristos 
67*5dd36a3bSchristos error:
68*5dd36a3bSchristos   print_error("Unexpected call to malloc");
69*5dd36a3bSchristos   fail();
70*5dd36a3bSchristos   return NULL;
71*5dd36a3bSchristos }
72*5dd36a3bSchristos 
instrumented_realloc(void * ptr,size_t size)73*5dd36a3bSchristos void *instrumented_realloc(void *ptr, size_t size) {
74*5dd36a3bSchristos   if (alloc_calls >= alloc_calls_expected) {
75*5dd36a3bSchristos     goto error;
76*5dd36a3bSchristos   }
77*5dd36a3bSchristos 
78*5dd36a3bSchristos   if (expectations[alloc_calls] == REALLOC) {
79*5dd36a3bSchristos     alloc_calls++;
80*5dd36a3bSchristos     return realloc(ptr, size);
81*5dd36a3bSchristos   } else if (expectations[alloc_calls] == REALLOC_FAIL) {
82*5dd36a3bSchristos     alloc_calls++;
83*5dd36a3bSchristos     return NULL;
84*5dd36a3bSchristos   }
85*5dd36a3bSchristos 
86*5dd36a3bSchristos error:
87*5dd36a3bSchristos   print_error("Unexpected call to realloc");
88*5dd36a3bSchristos   fail();
89*5dd36a3bSchristos   return NULL;
90*5dd36a3bSchristos }
91*5dd36a3bSchristos 
92*5dd36a3bSchristos #define WITH_MOCK_MALLOC(block, malloc_calls, ...) \
93*5dd36a3bSchristos   do {                                             \
94*5dd36a3bSchristos     set_mock_malloc(malloc_calls, __VA_ARGS__);    \
95*5dd36a3bSchristos     block;                                         \
96*5dd36a3bSchristos     finalize_mock_malloc();                        \
97*5dd36a3bSchristos   } while (0)
98*5dd36a3bSchristos 
99*5dd36a3bSchristos #define WITH_FAILING_MALLOC(block) WITH_MOCK_MALLOC(block, 1, MALLOC_FAIL)
100*5dd36a3bSchristos 
test_int_creation(void ** state)101*5dd36a3bSchristos static void test_int_creation(void **state) {
102*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_int8()); });
103*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_int16()); });
104*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_int32()); });
105*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_int64()); });
106*5dd36a3bSchristos 
107*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_uint8(0xFF)); });
108*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_uint16(0xFF)); });
109*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_uint32(0xFF)); });
110*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_uint64(0xFF)); });
111*5dd36a3bSchristos 
112*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_negint8(0xFF)); });
113*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_negint16(0xFF)); });
114*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_negint32(0xFF)); });
115*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_negint64(0xFF)); });
116*5dd36a3bSchristos }
117*5dd36a3bSchristos 
test_bytestring_creation(void ** state)118*5dd36a3bSchristos static void test_bytestring_creation(void **state) {
119*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_bytestring()); });
120*5dd36a3bSchristos 
121*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_bytestring()); });
122*5dd36a3bSchristos   WITH_MOCK_MALLOC({ assert_null(cbor_new_indefinite_bytestring()); }, 2,
123*5dd36a3bSchristos                    MALLOC, MALLOC_FAIL);
124*5dd36a3bSchristos 
125*5dd36a3bSchristos   unsigned char bytes[] = {0, 0, 0xFF, 0xAB};
126*5dd36a3bSchristos 
127*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_bytestring(bytes, 4)); });
128*5dd36a3bSchristos   WITH_MOCK_MALLOC({ assert_null(cbor_build_bytestring(bytes, 4)); }, 2, MALLOC,
129*5dd36a3bSchristos                    MALLOC_FAIL);
130*5dd36a3bSchristos }
131*5dd36a3bSchristos 
test_string_creation(void ** state)132*5dd36a3bSchristos static void test_string_creation(void **state) {
133*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_string()); });
134*5dd36a3bSchristos 
135*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_string()); });
136*5dd36a3bSchristos   WITH_MOCK_MALLOC({ assert_null(cbor_new_indefinite_string()); }, 2, MALLOC,
137*5dd36a3bSchristos                    MALLOC_FAIL);
138*5dd36a3bSchristos 
139*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_string("Test")); });
140*5dd36a3bSchristos   WITH_MOCK_MALLOC({ assert_null(cbor_build_string("Test")); }, 2, MALLOC,
141*5dd36a3bSchristos                    MALLOC_FAIL);
142*5dd36a3bSchristos 
143*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_stringn("Test", 4)); });
144*5dd36a3bSchristos   WITH_MOCK_MALLOC({ assert_null(cbor_build_stringn("Test", 4)); }, 2, MALLOC,
145*5dd36a3bSchristos                    MALLOC_FAIL);
146*5dd36a3bSchristos }
147*5dd36a3bSchristos 
test_array_creation(void ** state)148*5dd36a3bSchristos static void test_array_creation(void **state) {
149*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_array(42)); });
150*5dd36a3bSchristos   WITH_MOCK_MALLOC({ assert_null(cbor_new_definite_array(42)); }, 2, MALLOC,
151*5dd36a3bSchristos                    MALLOC_FAIL);
152*5dd36a3bSchristos 
153*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_array()); });
154*5dd36a3bSchristos }
155*5dd36a3bSchristos 
test_map_creation(void ** state)156*5dd36a3bSchristos static void test_map_creation(void **state) {
157*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_definite_map(42)); });
158*5dd36a3bSchristos   WITH_MOCK_MALLOC({ assert_null(cbor_new_definite_map(42)); }, 2, MALLOC,
159*5dd36a3bSchristos                    MALLOC_FAIL);
160*5dd36a3bSchristos 
161*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_indefinite_map()); });
162*5dd36a3bSchristos }
163*5dd36a3bSchristos 
test_tag_creation(void ** state)164*5dd36a3bSchristos static void test_tag_creation(void **state) {
165*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_tag(42)); });
166*5dd36a3bSchristos }
167*5dd36a3bSchristos 
test_float_ctrl_creation(void ** state)168*5dd36a3bSchristos static void test_float_ctrl_creation(void **state) {
169*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_ctrl()); });
170*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_float2()); });
171*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_float4()); });
172*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_float8()); });
173*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_null()); });
174*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_new_undef()); });
175*5dd36a3bSchristos 
176*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_bool(false)); });
177*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_float2(3.14)); });
178*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_float4(3.14)); });
179*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_float8(3.14)); });
180*5dd36a3bSchristos   WITH_FAILING_MALLOC({ assert_null(cbor_build_ctrl(0xAF)); });
181*5dd36a3bSchristos }
182*5dd36a3bSchristos 
test_bytestring_add_chunk(void ** state)183*5dd36a3bSchristos static void test_bytestring_add_chunk(void **state) {
184*5dd36a3bSchristos   unsigned char bytes[] = {0, 0, 0xFF, 0xAB};
185*5dd36a3bSchristos   WITH_MOCK_MALLOC(
186*5dd36a3bSchristos       {
187*5dd36a3bSchristos         cbor_item_t *bytestring = cbor_new_indefinite_bytestring();
188*5dd36a3bSchristos         cbor_item_t *chunk = cbor_build_bytestring(bytes, 4);
189*5dd36a3bSchristos 
190*5dd36a3bSchristos         assert_false(cbor_bytestring_add_chunk(bytestring, chunk));
191*5dd36a3bSchristos         assert_int_equal(cbor_bytestring_chunk_count(bytestring), 0);
192*5dd36a3bSchristos         assert_int_equal(
193*5dd36a3bSchristos             ((struct cbor_indefinite_string_data *)bytestring->data)
194*5dd36a3bSchristos                 ->chunk_capacity,
195*5dd36a3bSchristos             0);
196*5dd36a3bSchristos 
197*5dd36a3bSchristos         cbor_decref(&chunk);
198*5dd36a3bSchristos         cbor_decref(&bytestring);
199*5dd36a3bSchristos       },
200*5dd36a3bSchristos       5, MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
201*5dd36a3bSchristos }
202*5dd36a3bSchristos 
test_string_add_chunk(void ** state)203*5dd36a3bSchristos static void test_string_add_chunk(void **state) {
204*5dd36a3bSchristos   WITH_MOCK_MALLOC(
205*5dd36a3bSchristos       {
206*5dd36a3bSchristos         cbor_item_t *string = cbor_new_indefinite_string();
207*5dd36a3bSchristos         cbor_item_t *chunk = cbor_build_string("Hello!");
208*5dd36a3bSchristos 
209*5dd36a3bSchristos         assert_false(cbor_string_add_chunk(string, chunk));
210*5dd36a3bSchristos         assert_int_equal(cbor_string_chunk_count(string), 0);
211*5dd36a3bSchristos         assert_int_equal(((struct cbor_indefinite_string_data *)string->data)
212*5dd36a3bSchristos                              ->chunk_capacity,
213*5dd36a3bSchristos                          0);
214*5dd36a3bSchristos 
215*5dd36a3bSchristos         cbor_decref(&chunk);
216*5dd36a3bSchristos         cbor_decref(&string);
217*5dd36a3bSchristos       },
218*5dd36a3bSchristos       5, MALLOC, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
219*5dd36a3bSchristos }
220*5dd36a3bSchristos 
test_array_push(void ** state)221*5dd36a3bSchristos static void test_array_push(void **state) {
222*5dd36a3bSchristos   WITH_MOCK_MALLOC(
223*5dd36a3bSchristos       {
224*5dd36a3bSchristos         cbor_item_t *array = cbor_new_indefinite_array();
225*5dd36a3bSchristos         cbor_item_t *string = cbor_build_string("Hello!");
226*5dd36a3bSchristos 
227*5dd36a3bSchristos         assert_false(cbor_array_push(array, string));
228*5dd36a3bSchristos         assert_int_equal(cbor_array_allocated(array), 0);
229*5dd36a3bSchristos         assert_null(array->data);
230*5dd36a3bSchristos         assert_int_equal(array->metadata.array_metadata.end_ptr, 0);
231*5dd36a3bSchristos 
232*5dd36a3bSchristos         cbor_decref(&string);
233*5dd36a3bSchristos         cbor_decref(&array);
234*5dd36a3bSchristos       },
235*5dd36a3bSchristos       4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
236*5dd36a3bSchristos }
237*5dd36a3bSchristos 
test_map_add(void ** state)238*5dd36a3bSchristos static void test_map_add(void **state) {
239*5dd36a3bSchristos   WITH_MOCK_MALLOC(
240*5dd36a3bSchristos       {
241*5dd36a3bSchristos         cbor_item_t *map = cbor_new_indefinite_map();
242*5dd36a3bSchristos         cbor_item_t *key = cbor_build_uint8(0);
243*5dd36a3bSchristos         cbor_item_t *value = cbor_build_bool(true);
244*5dd36a3bSchristos 
245*5dd36a3bSchristos         assert_false(
246*5dd36a3bSchristos             cbor_map_add(map, (struct cbor_pair){.key = key, .value = value}));
247*5dd36a3bSchristos         assert_int_equal(cbor_map_allocated(map), 0);
248*5dd36a3bSchristos         assert_null(map->data);
249*5dd36a3bSchristos 
250*5dd36a3bSchristos         cbor_decref(&map);
251*5dd36a3bSchristos         cbor_decref(&key);
252*5dd36a3bSchristos         cbor_decref(&value);
253*5dd36a3bSchristos       },
254*5dd36a3bSchristos       4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
255*5dd36a3bSchristos }
256*5dd36a3bSchristos 
main(void)257*5dd36a3bSchristos int main(void) {
258*5dd36a3bSchristos #if CBOR_CUSTOM_ALLOC
259*5dd36a3bSchristos   cbor_set_allocs(instrumented_malloc, instrumented_realloc, free);
260*5dd36a3bSchristos 
261*5dd36a3bSchristos   // TODO: string chunks realloc test
262*5dd36a3bSchristos   const struct CMUnitTest tests[] = {
263*5dd36a3bSchristos       cmocka_unit_test(test_int_creation),
264*5dd36a3bSchristos       cmocka_unit_test(test_bytestring_creation),
265*5dd36a3bSchristos       cmocka_unit_test(test_string_creation),
266*5dd36a3bSchristos       cmocka_unit_test(test_array_creation),
267*5dd36a3bSchristos       cmocka_unit_test(test_map_creation),
268*5dd36a3bSchristos       cmocka_unit_test(test_tag_creation),
269*5dd36a3bSchristos       cmocka_unit_test(test_float_ctrl_creation),
270*5dd36a3bSchristos 
271*5dd36a3bSchristos       cmocka_unit_test(test_bytestring_add_chunk),
272*5dd36a3bSchristos       cmocka_unit_test(test_string_add_chunk),
273*5dd36a3bSchristos       cmocka_unit_test(test_array_push),
274*5dd36a3bSchristos       cmocka_unit_test(test_map_add),
275*5dd36a3bSchristos   };
276*5dd36a3bSchristos #else
277*5dd36a3bSchristos   // Can't do anything without a custom allocator
278*5dd36a3bSchristos   const struct CMUnitTest tests[] = {};
279*5dd36a3bSchristos #endif
280*5dd36a3bSchristos 
281*5dd36a3bSchristos   return cmocka_run_group_tests(tests, NULL, NULL);
282*5dd36a3bSchristos }
283