xref: /src/contrib/libcbor/test/callbacks_test.c (revision b5b9517bfe394e55088f5a05882eabae7e9b7b29)
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 */
test_default_callbacks(void ** _state _CBOR_UNUSED)23 static void test_default_callbacks(void** _state _CBOR_UNUSED) {
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};
test_builder_byte_string_callback_append(void ** _state _CBOR_UNUSED)33 static void test_builder_byte_string_callback_append(
34     void** _state _CBOR_UNUSED) {
35   struct _cbor_stack stack = _cbor_stack_init();
36   struct _cbor_stack_record* stack_top =
37       _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0);
38   assert_non_null(stack_top);
39   struct _cbor_decoder_context context = {
40       .creation_failed = false,
41       .syntax_error = false,
42       .root = NULL,
43       .stack = &stack,
44   };
45 
46   cbor_builder_byte_string_callback(&context, bytestring_data, 3);
47 
48   assert_false(context.creation_failed);
49   assert_false(context.syntax_error);
50   assert_size_equal(context.stack->size, 1);
51 
52   cbor_item_t* bytestring = stack.top->item;
53   assert_size_equal(cbor_refcount(bytestring), 1);
54   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
55   assert_true(cbor_isa_bytestring(bytestring));
56   assert_size_equal(cbor_bytestring_length(bytestring), 0);
57   assert_true(cbor_bytestring_is_indefinite(bytestring));
58   assert_size_equal(cbor_bytestring_chunk_count(bytestring), 1);
59 
60   cbor_item_t* chunk = cbor_bytestring_chunks_handle(bytestring)[0];
61   assert_size_equal(cbor_refcount(chunk), 1);
62   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
63   assert_true(cbor_isa_bytestring(chunk));
64   assert_true(cbor_bytestring_is_definite(chunk));
65   assert_size_equal(cbor_bytestring_length(chunk), 3);
66   assert_memory_equal(cbor_bytestring_handle(chunk), bytestring_data, 3);
67   // Data is copied
68   assert_ptr_not_equal(cbor_bytestring_handle(chunk), bytestring_data);
69 
70   cbor_decref(&bytestring);
71   _cbor_stack_pop(&stack);
72 }
73 
test_builder_byte_string_callback_append_alloc_failure(void ** _state _CBOR_UNUSED)74 static void test_builder_byte_string_callback_append_alloc_failure(
75     void** _state _CBOR_UNUSED) {
76   struct _cbor_stack stack = _cbor_stack_init();
77   struct _cbor_stack_record* stack_top =
78       _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0);
79   assert_non_null(stack_top);
80   struct _cbor_decoder_context context = {
81       .creation_failed = false,
82       .syntax_error = false,
83       .root = NULL,
84       .stack = &stack,
85   };
86 
87   WITH_FAILING_MALLOC(
88       { cbor_builder_byte_string_callback(&context, bytestring_data, 3); });
89 
90   assert_true(context.creation_failed);
91   assert_false(context.syntax_error);
92   assert_size_equal(context.stack->size, 1);
93 
94   // The stack remains unchanged
95   cbor_item_t* bytestring = stack.top->item;
96   assert_size_equal(cbor_refcount(bytestring), 1);
97   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
98   assert_true(cbor_isa_bytestring(bytestring));
99   assert_size_equal(cbor_bytestring_length(bytestring), 0);
100   assert_true(cbor_bytestring_is_indefinite(bytestring));
101   assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
102 
103   cbor_decref(&bytestring);
104   _cbor_stack_pop(&stack);
105 }
106 
test_builder_byte_string_callback_append_item_alloc_failure(void ** _state _CBOR_UNUSED)107 static void test_builder_byte_string_callback_append_item_alloc_failure(
108     void** _state _CBOR_UNUSED) {
109   struct _cbor_stack stack = _cbor_stack_init();
110   struct _cbor_stack_record* stack_top =
111       _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0);
112   assert_non_null(stack_top);
113   struct _cbor_decoder_context context = {
114       .creation_failed = false,
115       .syntax_error = false,
116       .root = NULL,
117       .stack = &stack,
118   };
119 
120   // Allocate new data block, but fail to allocate a new item with it
121   WITH_MOCK_MALLOC(
122       { cbor_builder_byte_string_callback(&context, bytestring_data, 3); }, 2,
123       MALLOC, MALLOC_FAIL);
124 
125   assert_true(context.creation_failed);
126   assert_false(context.syntax_error);
127   assert_size_equal(context.stack->size, 1);
128 
129   // The stack remains unchanged
130   cbor_item_t* bytestring = stack.top->item;
131   assert_size_equal(cbor_refcount(bytestring), 1);
132   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
133   assert_true(cbor_isa_bytestring(bytestring));
134   assert_size_equal(cbor_bytestring_length(bytestring), 0);
135   assert_true(cbor_bytestring_is_indefinite(bytestring));
136   assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
137 
138   cbor_decref(&bytestring);
139   _cbor_stack_pop(&stack);
140 }
141 
test_builder_byte_string_callback_append_parent_alloc_failure(void ** _state _CBOR_UNUSED)142 static void test_builder_byte_string_callback_append_parent_alloc_failure(
143     void** _state _CBOR_UNUSED) {
144   struct _cbor_stack stack = _cbor_stack_init();
145   struct _cbor_stack_record* stack_top =
146       _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0);
147   assert_non_null(stack_top);
148   struct _cbor_decoder_context context = {
149       .creation_failed = false,
150       .syntax_error = false,
151       .root = NULL,
152       .stack = &stack,
153   };
154 
155   // Allocate new item, but fail to push it into the parent on the stack
156   WITH_MOCK_MALLOC(
157       { cbor_builder_byte_string_callback(&context, bytestring_data, 3); }, 3,
158       MALLOC, MALLOC, REALLOC_FAIL);
159 
160   assert_true(context.creation_failed);
161   assert_false(context.syntax_error);
162   assert_size_equal(context.stack->size, 1);
163 
164   // The stack remains unchanged
165   cbor_item_t* bytestring = stack.top->item;
166   assert_size_equal(cbor_refcount(bytestring), 1);
167   assert_true(cbor_typeof(bytestring) == CBOR_TYPE_BYTESTRING);
168   assert_true(cbor_isa_bytestring(bytestring));
169   assert_size_equal(cbor_bytestring_length(bytestring), 0);
170   assert_true(cbor_bytestring_is_indefinite(bytestring));
171   assert_size_equal(cbor_bytestring_chunk_count(bytestring), 0);
172 
173   cbor_decref(&bytestring);
174   _cbor_stack_pop(&stack);
175 }
176 
177 unsigned char string_data[] = {0x61, 0x62, 0x63};
test_builder_string_callback_append(void ** _state _CBOR_UNUSED)178 static void test_builder_string_callback_append(void** _state _CBOR_UNUSED) {
179   struct _cbor_stack stack = _cbor_stack_init();
180   struct _cbor_stack_record* stack_top =
181       _cbor_stack_push(&stack, cbor_new_indefinite_string(), 0);
182   assert_non_null(stack_top);
183   struct _cbor_decoder_context context = {
184       .creation_failed = false,
185       .syntax_error = false,
186       .root = NULL,
187       .stack = &stack,
188   };
189 
190   cbor_builder_string_callback(&context, string_data, 3);
191 
192   assert_false(context.creation_failed);
193   assert_false(context.syntax_error);
194   assert_size_equal(context.stack->size, 1);
195 
196   cbor_item_t* string = stack.top->item;
197   assert_size_equal(cbor_refcount(string), 1);
198   assert_true(cbor_isa_string(string));
199   assert_size_equal(cbor_string_length(string), 0);
200   assert_true(cbor_string_is_indefinite(string));
201   assert_size_equal(cbor_string_chunk_count(string), 1);
202 
203   cbor_item_t* chunk = cbor_string_chunks_handle(string)[0];
204   assert_size_equal(cbor_refcount(chunk), 1);
205   assert_true(cbor_isa_string(chunk));
206   assert_true(cbor_string_is_definite(chunk));
207   assert_size_equal(cbor_string_length(chunk), 3);
208   assert_memory_equal(cbor_string_handle(chunk), "abc", 3);
209   // Data is copied
210   assert_ptr_not_equal(cbor_string_handle(chunk), string_data);
211 
212   cbor_decref(&string);
213   _cbor_stack_pop(&stack);
214 }
215 
test_builder_string_callback_append_alloc_failure(void ** _state _CBOR_UNUSED)216 static void test_builder_string_callback_append_alloc_failure(
217     void** _state _CBOR_UNUSED) {
218   struct _cbor_stack stack = _cbor_stack_init();
219   struct _cbor_stack_record* stack_top =
220       _cbor_stack_push(&stack, cbor_new_indefinite_string(), 0);
221   assert_non_null(stack_top);
222   struct _cbor_decoder_context context = {
223       .creation_failed = false,
224       .syntax_error = false,
225       .root = NULL,
226       .stack = &stack,
227   };
228 
229   WITH_FAILING_MALLOC(
230       { cbor_builder_string_callback(&context, string_data, 3); });
231 
232   assert_true(context.creation_failed);
233   assert_false(context.syntax_error);
234   assert_size_equal(context.stack->size, 1);
235 
236   // The stack remains unchanged
237   cbor_item_t* string = stack.top->item;
238   assert_size_equal(cbor_refcount(string), 1);
239   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
240   assert_true(cbor_isa_string(string));
241   assert_size_equal(cbor_string_length(string), 0);
242   assert_true(cbor_string_is_indefinite(string));
243   assert_size_equal(cbor_string_chunk_count(string), 0);
244 
245   cbor_decref(&string);
246   _cbor_stack_pop(&stack);
247 }
248 
test_builder_string_callback_append_item_alloc_failure(void ** _state _CBOR_UNUSED)249 static void test_builder_string_callback_append_item_alloc_failure(
250     void** _state _CBOR_UNUSED) {
251   struct _cbor_stack stack = _cbor_stack_init();
252   struct _cbor_stack_record* stack_top =
253       _cbor_stack_push(&stack, cbor_new_indefinite_string(), 0);
254   assert_non_null(stack_top);
255   struct _cbor_decoder_context context = {
256       .creation_failed = false,
257       .syntax_error = false,
258       .root = NULL,
259       .stack = &stack,
260   };
261 
262   // Allocate new data block, but fail to allocate a new item with it
263   WITH_MOCK_MALLOC({ cbor_builder_string_callback(&context, string_data, 3); },
264                    2, MALLOC, MALLOC_FAIL);
265 
266   assert_true(context.creation_failed);
267   assert_false(context.syntax_error);
268   assert_size_equal(context.stack->size, 1);
269 
270   // The stack remains unchanged
271   cbor_item_t* string = stack.top->item;
272   assert_size_equal(cbor_refcount(string), 1);
273   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
274   assert_true(cbor_isa_string(string));
275   assert_size_equal(cbor_string_length(string), 0);
276   assert_true(cbor_string_is_indefinite(string));
277   assert_size_equal(cbor_string_chunk_count(string), 0);
278 
279   cbor_decref(&string);
280   _cbor_stack_pop(&stack);
281 }
282 
test_builder_string_callback_append_parent_alloc_failure(void ** _state _CBOR_UNUSED)283 static void test_builder_string_callback_append_parent_alloc_failure(
284     void** _state _CBOR_UNUSED) {
285   struct _cbor_stack stack = _cbor_stack_init();
286   struct _cbor_stack_record* stack_top =
287       _cbor_stack_push(&stack, cbor_new_indefinite_string(), 0);
288   assert_non_null(stack_top);
289   struct _cbor_decoder_context context = {
290       .creation_failed = false,
291       .syntax_error = false,
292       .root = NULL,
293       .stack = &stack,
294   };
295 
296   // Allocate new item, but fail to push it into the parent on the stack
297   WITH_MOCK_MALLOC({ cbor_builder_string_callback(&context, string_data, 3); },
298                    3, MALLOC, MALLOC, REALLOC_FAIL);
299 
300   assert_true(context.creation_failed);
301   assert_false(context.syntax_error);
302   assert_size_equal(context.stack->size, 1);
303 
304   // The stack remains unchanged
305   cbor_item_t* string = stack.top->item;
306   assert_size_equal(cbor_refcount(string), 1);
307   assert_true(cbor_typeof(string) == CBOR_TYPE_STRING);
308   assert_true(cbor_isa_string(string));
309   assert_size_equal(cbor_string_length(string), 0);
310   assert_true(cbor_string_is_indefinite(string));
311   assert_size_equal(cbor_string_chunk_count(string), 0);
312 
313   cbor_decref(&string);
314   _cbor_stack_pop(&stack);
315 }
316 
test_append_array_failure(void ** _state _CBOR_UNUSED)317 static void test_append_array_failure(void** _state _CBOR_UNUSED) {
318   struct _cbor_stack stack = _cbor_stack_init();
319   struct _cbor_stack_record* stack_top =
320       _cbor_stack_push(&stack, cbor_new_definite_array(0), 0);
321   assert_non_null(stack_top);
322   stack.top->subitems = 1;
323   struct _cbor_decoder_context context = {
324       .creation_failed = false,
325       .syntax_error = false,
326       .root = NULL,
327       .stack = &stack,
328   };
329   cbor_item_t* item = cbor_build_uint8(42);
330 
331   _cbor_builder_append(item, &context);
332 
333   assert_true(context.creation_failed);
334   assert_false(context.syntax_error);
335   assert_size_equal(context.stack->size, 1);
336 
337   // The stack remains unchanged
338   cbor_item_t* array = stack.top->item;
339   assert_size_equal(cbor_refcount(array), 1);
340   assert_true(cbor_isa_array(array));
341   assert_size_equal(cbor_array_size(array), 0);
342 
343   // item free'd by _cbor_builder_append
344   cbor_decref(&array);
345   _cbor_stack_pop(&stack);
346 }
347 
test_append_map_failure(void ** _state _CBOR_UNUSED)348 static void test_append_map_failure(void** _state _CBOR_UNUSED) {
349   struct _cbor_stack stack = _cbor_stack_init();
350   struct _cbor_stack_record* stack_top =
351       _cbor_stack_push(&stack, cbor_new_indefinite_map(), /*subitems=*/0);
352   assert_non_null(stack_top);
353   struct _cbor_decoder_context context = {
354       .creation_failed = false,
355       .syntax_error = false,
356       .root = NULL,
357       .stack = &stack,
358   };
359   cbor_item_t* item = cbor_build_uint8(42);
360 
361   WITH_MOCK_MALLOC({ _cbor_builder_append(item, &context); }, 1, REALLOC_FAIL);
362 
363   assert_true(context.creation_failed);
364   assert_false(context.syntax_error);
365   assert_size_equal(context.stack->size, 1);
366 
367   // The stack remains unchanged
368   cbor_item_t* map = stack.top->item;
369   assert_size_equal(cbor_refcount(map), 1);
370   assert_true(cbor_isa_map(map));
371   assert_size_equal(cbor_map_size(map), 0);
372 
373   // item free'd by _cbor_builder_append
374   cbor_decref(&map);
375   _cbor_stack_pop(&stack);
376 }
377 
378 // Size 1 array start, but we get an indef break
379 unsigned char invalid_indef_break_data[] = {0x81, 0xFF};
test_invalid_indef_break(void ** _state _CBOR_UNUSED)380 static void test_invalid_indef_break(void** _state _CBOR_UNUSED) {
381   struct cbor_load_result res;
382   cbor_item_t* item = cbor_load(invalid_indef_break_data, 2, &res);
383 
384   assert_null(item);
385   assert_size_equal(res.read, 2);
386   assert_true(res.error.code == CBOR_ERR_SYNTAXERROR);
387 }
388 
test_invalid_state_indef_break(void ** _state _CBOR_UNUSED)389 static void test_invalid_state_indef_break(void** _state _CBOR_UNUSED) {
390   struct _cbor_stack stack = _cbor_stack_init();
391   struct _cbor_stack_record* stack_top =
392       _cbor_stack_push(&stack, cbor_new_int8(), /*subitems=*/0);
393   assert_non_null(stack_top);
394   struct _cbor_decoder_context context = {
395       .creation_failed = false,
396       .syntax_error = false,
397       .root = NULL,
398       .stack = &stack,
399   };
400 
401   cbor_builder_indef_break_callback(&context);
402 
403   assert_false(context.creation_failed);
404   assert_true(context.syntax_error);
405   assert_size_equal(context.stack->size, 1);
406   // The stack remains unchanged
407   cbor_item_t* small_int = stack.top->item;
408   assert_size_equal(cbor_refcount(small_int), 1);
409   assert_true(cbor_isa_uint(small_int));
410 
411   cbor_decref(&small_int);
412   _cbor_stack_pop(&stack);
413 }
414 
main(void)415 int main(void) {
416   const struct CMUnitTest tests[] = {
417       cmocka_unit_test(test_default_callbacks),
418       cmocka_unit_test(test_builder_byte_string_callback_append),
419       cmocka_unit_test(test_builder_byte_string_callback_append_alloc_failure),
420       cmocka_unit_test(
421           test_builder_byte_string_callback_append_item_alloc_failure),
422       cmocka_unit_test(
423           test_builder_byte_string_callback_append_parent_alloc_failure),
424       cmocka_unit_test(test_builder_string_callback_append),
425       cmocka_unit_test(test_builder_string_callback_append_alloc_failure),
426       cmocka_unit_test(test_builder_string_callback_append_item_alloc_failure),
427       cmocka_unit_test(
428           test_builder_string_callback_append_parent_alloc_failure),
429       cmocka_unit_test(test_append_array_failure),
430       cmocka_unit_test(test_append_map_failure),
431       cmocka_unit_test(test_invalid_indef_break),
432       cmocka_unit_test(test_invalid_state_indef_break),
433   };
434 
435   cmocka_run_group_tests(tests, NULL, NULL);
436 }
437