xref: /freebsd/contrib/libcbor/test/callbacks_test.c (revision 02e9120893770924227138ba49df1edb3896112a)
1 /*
2  * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
3  *
4  * libcbor is free software; you can redistribute it and/or modify
5  * it under the terms of the MIT license. See LICENSE for details.
6  */
7 #include "assertions.h"
8 #include "cbor.h"
9 #include "cbor/internal/builder_callbacks.h"
10 #include "cbor/internal/stack.h"
11 #include "test_allocator.h"
12 
13 unsigned char data[] = {
14     0x93, 0x01, 0x19, 0x01, 0x01, 0x1A, 0x00, 0x01, 0x05, 0xB8, 0x1B, 0x00,
15     0x00, 0x00, 0x01, 0x8F, 0x5A, 0xE8, 0xB8, 0x20, 0x39, 0x01, 0x00, 0x3A,
16     0x00, 0x01, 0x05, 0xB7, 0x3B, 0x00, 0x00, 0x00, 0x01, 0x8F, 0x5A, 0xE8,
17     0xB7, 0x5F, 0x41, 0x01, 0x41, 0x02, 0xFF, 0x7F, 0x61, 0x61, 0x61, 0x62,
18     0xFF, 0x9F, 0xFF, 0xA1, 0x61, 0x61, 0x61, 0x62, 0xC0, 0xBF, 0xFF, 0xF9,
19     0x3C, 0x00, 0xFA, 0x47, 0xC3, 0x50, 0x00, 0xFB, 0x7E, 0x37, 0xE4, 0x3C,
20     0x88, 0x00, 0x75, 0x9C, 0xF6, 0xF7, 0xF5};
21 
22 /* Exercise the default callbacks */
23 static void test_default_callbacks(void** _CBOR_UNUSED(_state)) {
24   size_t read = 0;
25   while (read < 79) {
26     struct cbor_decoder_result result =
27         cbor_stream_decode(data + read, 79 - read, &cbor_empty_callbacks, NULL);
28     read += result.read;
29   }
30 }
31 
32 unsigned char bytestring_data[] = {0x01, 0x02, 0x03};
33 static void test_builder_byte_string_callback_append(
34     void** _CBOR_UNUSED(_state)) {
35   struct _cbor_stack stack = _cbor_stack_init();
36   assert_non_null(
37       _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
38   struct _cbor_decoder_context context = {
39       .creation_failed = false,
40       .syntax_error = false,
41       .root = NULL,
42       .stack = &stack,
43   };
44 
45   cbor_builder_byte_string_callback(&context, bytestring_data, 3);
46 
47   assert_false(context.creation_failed);
48   assert_false(context.syntax_error);
49   assert_size_equal(context.stack->size, 1);
50 
51   cbor_item_t* bytestring = stack.top->item;
52   assert_size_equal(cbor_refcount(bytestring), 1);
53   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
54   assert_true(cbor_isa_bytestring(bytestring));
55   assert_size_equal(cbor_bytestring_length(bytestring), 0);
56   assert_true(cbor_bytestring_is_indefinite(bytestring));
57   assert_size_equal(cbor_bytestring_chunk_count(bytestring), 1);
58 
59   cbor_item_t* chunk = cbor_bytestring_chunks_handle(bytestring)[0];
60   assert_size_equal(cbor_refcount(chunk), 1);
61   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
62   assert_true(cbor_isa_bytestring(chunk));
63   assert_true(cbor_bytestring_is_definite(chunk));
64   assert_size_equal(cbor_bytestring_length(chunk), 3);
65   assert_memory_equal(cbor_bytestring_handle(chunk), bytestring_data, 3);
66   // Data is copied
67   assert_ptr_not_equal(cbor_bytestring_handle(chunk), bytestring_data);
68 
69   cbor_decref(&bytestring);
70   _cbor_stack_pop(&stack);
71 }
72 
73 static void test_builder_byte_string_callback_append_alloc_failure(
74     void** _CBOR_UNUSED(_state)) {
75   struct _cbor_stack stack = _cbor_stack_init();
76   assert_non_null(
77       _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
78   struct _cbor_decoder_context context = {
79       .creation_failed = false,
80       .syntax_error = false,
81       .root = NULL,
82       .stack = &stack,
83   };
84 
85   WITH_FAILING_MALLOC(
86       { cbor_builder_byte_string_callback(&context, bytestring_data, 3); });
87 
88   assert_true(context.creation_failed);
89   assert_false(context.syntax_error);
90   assert_size_equal(context.stack->size, 1);
91 
92   // The stack remains unchanged
93   cbor_item_t* bytestring = stack.top->item;
94   assert_size_equal(cbor_refcount(bytestring), 1);
95   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
96   assert_true(cbor_isa_bytestring(bytestring));
97   assert_size_equal(cbor_bytestring_length(bytestring), 0);
98   assert_true(cbor_bytestring_is_indefinite(bytestring));
99   assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
100 
101   cbor_decref(&bytestring);
102   _cbor_stack_pop(&stack);
103 }
104 
105 static void test_builder_byte_string_callback_append_item_alloc_failure(
106     void** _CBOR_UNUSED(_state)) {
107   struct _cbor_stack stack = _cbor_stack_init();
108   assert_non_null(
109       _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
110   struct _cbor_decoder_context context = {
111       .creation_failed = false,
112       .syntax_error = false,
113       .root = NULL,
114       .stack = &stack,
115   };
116 
117   // Allocate new data block, but fail to allocate a new item with it
118   WITH_MOCK_MALLOC(
119       { cbor_builder_byte_string_callback(&context, bytestring_data, 3); }, 2,
120       MALLOC, MALLOC_FAIL);
121 
122   assert_true(context.creation_failed);
123   assert_false(context.syntax_error);
124   assert_size_equal(context.stack->size, 1);
125 
126   // The stack remains unchanged
127   cbor_item_t* bytestring = stack.top->item;
128   assert_size_equal(cbor_refcount(bytestring), 1);
129   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
130   assert_true(cbor_isa_bytestring(bytestring));
131   assert_size_equal(cbor_bytestring_length(bytestring), 0);
132   assert_true(cbor_bytestring_is_indefinite(bytestring));
133   assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
134 
135   cbor_decref(&bytestring);
136   _cbor_stack_pop(&stack);
137 }
138 
139 static void test_builder_byte_string_callback_append_parent_alloc_failure(
140     void** _CBOR_UNUSED(_state)) {
141   struct _cbor_stack stack = _cbor_stack_init();
142   assert_non_null(
143       _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
144   struct _cbor_decoder_context context = {
145       .creation_failed = false,
146       .syntax_error = false,
147       .root = NULL,
148       .stack = &stack,
149   };
150 
151   // Allocate new item, but fail to push it into the parent on the stack
152   WITH_MOCK_MALLOC(
153       { cbor_builder_byte_string_callback(&context, bytestring_data, 3); }, 3,
154       MALLOC, MALLOC, REALLOC_FAIL);
155 
156   assert_true(context.creation_failed);
157   assert_false(context.syntax_error);
158   assert_size_equal(context.stack->size, 1);
159 
160   // The stack remains unchanged
161   cbor_item_t* bytestring = stack.top->item;
162   assert_size_equal(cbor_refcount(bytestring), 1);
163   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
164   assert_true(cbor_isa_bytestring(bytestring));
165   assert_size_equal(cbor_bytestring_length(bytestring), 0);
166   assert_true(cbor_bytestring_is_indefinite(bytestring));
167   assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
168 
169   cbor_decref(&bytestring);
170   _cbor_stack_pop(&stack);
171 }
172 
173 unsigned char string_data[] = {0x61, 0x62, 0x63};
174 static void test_builder_string_callback_append(void** _CBOR_UNUSED(_state)) {
175   struct _cbor_stack stack = _cbor_stack_init();
176   assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
177   struct _cbor_decoder_context context = {
178       .creation_failed = false,
179       .syntax_error = false,
180       .root = NULL,
181       .stack = &stack,
182   };
183 
184   cbor_builder_string_callback(&context, string_data, 3);
185 
186   assert_false(context.creation_failed);
187   assert_false(context.syntax_error);
188   assert_size_equal(context.stack->size, 1);
189 
190   cbor_item_t* string = stack.top->item;
191   assert_size_equal(cbor_refcount(string), 1);
192   assert_true(cbor_isa_string(string));
193   assert_size_equal(cbor_string_length(string), 0);
194   assert_true(cbor_string_is_indefinite(string));
195   assert_size_equal(cbor_string_chunk_count(string), 1);
196 
197   cbor_item_t* chunk = cbor_string_chunks_handle(string)[0];
198   assert_size_equal(cbor_refcount(chunk), 1);
199   assert_true(cbor_isa_string(chunk));
200   assert_true(cbor_string_is_definite(chunk));
201   assert_size_equal(cbor_string_length(chunk), 3);
202   assert_memory_equal(cbor_string_handle(chunk), "abc", 3);
203   // Data is copied
204   assert_ptr_not_equal(cbor_string_handle(chunk), string_data);
205 
206   cbor_decref(&string);
207   _cbor_stack_pop(&stack);
208 }
209 
210 static void test_builder_string_callback_append_alloc_failure(
211     void** _CBOR_UNUSED(_state)) {
212   struct _cbor_stack stack = _cbor_stack_init();
213   assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
214   struct _cbor_decoder_context context = {
215       .creation_failed = false,
216       .syntax_error = false,
217       .root = NULL,
218       .stack = &stack,
219   };
220 
221   WITH_FAILING_MALLOC(
222       { cbor_builder_string_callback(&context, string_data, 3); });
223 
224   assert_true(context.creation_failed);
225   assert_false(context.syntax_error);
226   assert_size_equal(context.stack->size, 1);
227 
228   // The stack remains unchanged
229   cbor_item_t* string = stack.top->item;
230   assert_size_equal(cbor_refcount(string), 1);
231   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
232   assert_true(cbor_isa_string(string));
233   assert_size_equal(cbor_string_length(string), 0);
234   assert_true(cbor_string_is_indefinite(string));
235   assert_size_equal(cbor_string_chunk_count(string), 0);
236 
237   cbor_decref(&string);
238   _cbor_stack_pop(&stack);
239 }
240 
241 static void test_builder_string_callback_append_item_alloc_failure(
242     void** _CBOR_UNUSED(_state)) {
243   struct _cbor_stack stack = _cbor_stack_init();
244   assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
245   struct _cbor_decoder_context context = {
246       .creation_failed = false,
247       .syntax_error = false,
248       .root = NULL,
249       .stack = &stack,
250   };
251 
252   // Allocate new data block, but fail to allocate a new item with it
253   WITH_MOCK_MALLOC({ cbor_builder_string_callback(&context, string_data, 3); },
254                    2, MALLOC, MALLOC_FAIL);
255 
256   assert_true(context.creation_failed);
257   assert_false(context.syntax_error);
258   assert_size_equal(context.stack->size, 1);
259 
260   // The stack remains unchanged
261   cbor_item_t* string = stack.top->item;
262   assert_size_equal(cbor_refcount(string), 1);
263   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
264   assert_true(cbor_isa_string(string));
265   assert_size_equal(cbor_string_length(string), 0);
266   assert_true(cbor_string_is_indefinite(string));
267   assert_size_equal(cbor_string_chunk_count(string), 0);
268 
269   cbor_decref(&string);
270   _cbor_stack_pop(&stack);
271 }
272 
273 static void test_builder_string_callback_append_parent_alloc_failure(
274     void** _CBOR_UNUSED(_state)) {
275   struct _cbor_stack stack = _cbor_stack_init();
276   assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
277   struct _cbor_decoder_context context = {
278       .creation_failed = false,
279       .syntax_error = false,
280       .root = NULL,
281       .stack = &stack,
282   };
283 
284   // Allocate new item, but fail to push it into the parent on the stack
285   WITH_MOCK_MALLOC({ cbor_builder_string_callback(&context, string_data, 3); },
286                    3, MALLOC, MALLOC, REALLOC_FAIL);
287 
288   assert_true(context.creation_failed);
289   assert_false(context.syntax_error);
290   assert_size_equal(context.stack->size, 1);
291 
292   // The stack remains unchanged
293   cbor_item_t* string = stack.top->item;
294   assert_size_equal(cbor_refcount(string), 1);
295   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
296   assert_true(cbor_isa_string(string));
297   assert_size_equal(cbor_string_length(string), 0);
298   assert_true(cbor_string_is_indefinite(string));
299   assert_size_equal(cbor_string_chunk_count(string), 0);
300 
301   cbor_decref(&string);
302   _cbor_stack_pop(&stack);
303 }
304 
305 static void test_append_array_failure(void** _CBOR_UNUSED(_state)) {
306   struct _cbor_stack stack = _cbor_stack_init();
307   assert_non_null(_cbor_stack_push(&stack, cbor_new_definite_array(0), 0));
308   stack.top->subitems = 1;
309   struct _cbor_decoder_context context = {
310       .creation_failed = false,
311       .syntax_error = false,
312       .root = NULL,
313       .stack = &stack,
314   };
315   cbor_item_t* item = cbor_build_uint8(42);
316 
317   _cbor_builder_append(item, &context);
318 
319   assert_true(context.creation_failed);
320   assert_false(context.syntax_error);
321   assert_size_equal(context.stack->size, 1);
322 
323   // The stack remains unchanged
324   cbor_item_t* array = stack.top->item;
325   assert_size_equal(cbor_refcount(array), 1);
326   assert_true(cbor_isa_array(array));
327   assert_size_equal(cbor_array_size(array), 0);
328 
329   // item free'd by _cbor_builder_append
330   cbor_decref(&array);
331   _cbor_stack_pop(&stack);
332 }
333 
334 static void test_append_map_failure(void** _CBOR_UNUSED(_state)) {
335   struct _cbor_stack stack = _cbor_stack_init();
336   assert_non_null(
337       _cbor_stack_push(&stack, cbor_new_indefinite_map(), /*subitems=*/0));
338   struct _cbor_decoder_context context = {
339       .creation_failed = false,
340       .syntax_error = false,
341       .root = NULL,
342       .stack = &stack,
343   };
344   cbor_item_t* item = cbor_build_uint8(42);
345 
346   WITH_MOCK_MALLOC({ _cbor_builder_append(item, &context); }, 1, REALLOC_FAIL);
347 
348   assert_true(context.creation_failed);
349   assert_false(context.syntax_error);
350   assert_size_equal(context.stack->size, 1);
351 
352   // The stack remains unchanged
353   cbor_item_t* map = stack.top->item;
354   assert_size_equal(cbor_refcount(map), 1);
355   assert_true(cbor_isa_map(map));
356   assert_size_equal(cbor_map_size(map), 0);
357 
358   // item free'd by _cbor_builder_append
359   cbor_decref(&map);
360   _cbor_stack_pop(&stack);
361 }
362 
363 // Size 1 array start, but we get an indef break
364 unsigned char invalid_indef_break_data[] = {0x81, 0xFF};
365 static void test_invalid_indef_break(void** _CBOR_UNUSED(_state)) {
366   struct cbor_load_result res;
367   cbor_item_t* item = cbor_load(invalid_indef_break_data, 2, &res);
368 
369   assert_null(item);
370   assert_size_equal(res.read, 2);
371   assert_true(res.error.code == CBOR_ERR_SYNTAXERROR);
372 }
373 
374 int main(void) {
375   const struct CMUnitTest tests[] = {
376       cmocka_unit_test(test_default_callbacks),
377       cmocka_unit_test(test_builder_byte_string_callback_append),
378       cmocka_unit_test(test_builder_byte_string_callback_append_alloc_failure),
379       cmocka_unit_test(
380           test_builder_byte_string_callback_append_item_alloc_failure),
381       cmocka_unit_test(
382           test_builder_byte_string_callback_append_parent_alloc_failure),
383       cmocka_unit_test(test_builder_string_callback_append),
384       cmocka_unit_test(test_builder_string_callback_append_alloc_failure),
385       cmocka_unit_test(test_builder_string_callback_append_item_alloc_failure),
386       cmocka_unit_test(
387           test_builder_string_callback_append_parent_alloc_failure),
388       cmocka_unit_test(test_append_array_failure),
389       cmocka_unit_test(test_append_map_failure),
390       cmocka_unit_test(test_invalid_indef_break),
391   };
392 
393   cmocka_run_group_tests(tests, NULL, NULL);
394 }
395