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