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