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 ** _CBOR_UNUSED (_state))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};
test_builder_byte_string_callback_append(void ** _CBOR_UNUSED (_state))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
test_builder_byte_string_callback_append_alloc_failure(void ** _CBOR_UNUSED (_state))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
test_builder_byte_string_callback_append_item_alloc_failure(void ** _CBOR_UNUSED (_state))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
test_builder_byte_string_callback_append_parent_alloc_failure(void ** _CBOR_UNUSED (_state))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};
test_builder_string_callback_append(void ** _CBOR_UNUSED (_state))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
test_builder_string_callback_append_alloc_failure(void ** _CBOR_UNUSED (_state))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
test_builder_string_callback_append_item_alloc_failure(void ** _CBOR_UNUSED (_state))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
test_builder_string_callback_append_parent_alloc_failure(void ** _CBOR_UNUSED (_state))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
test_append_array_failure(void ** _CBOR_UNUSED (_state))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
test_append_map_failure(void ** _CBOR_UNUSED (_state))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};
test_invalid_indef_break(void ** _CBOR_UNUSED (_state))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
test_invalid_state_indef_break(void ** _CBOR_UNUSED (_state))374 static void test_invalid_state_indef_break(void** _CBOR_UNUSED(_state)) {
375 struct _cbor_stack stack = _cbor_stack_init();
376 assert_non_null(_cbor_stack_push(&stack, cbor_new_int8(), /*subitems=*/0));
377 struct _cbor_decoder_context context = {
378 .creation_failed = false,
379 .syntax_error = false,
380 .root = NULL,
381 .stack = &stack,
382 };
383
384 cbor_builder_indef_break_callback(&context);
385
386 assert_false(context.creation_failed);
387 assert_true(context.syntax_error);
388 assert_size_equal(context.stack->size, 1);
389 // The stack remains unchanged
390 cbor_item_t* small_int = stack.top->item;
391 assert_size_equal(cbor_refcount(small_int), 1);
392 assert_true(cbor_isa_uint(small_int));
393
394 cbor_decref(&small_int);
395 _cbor_stack_pop(&stack);
396 }
397
main(void)398 int main(void) {
399 const struct CMUnitTest tests[] = {
400 cmocka_unit_test(test_default_callbacks),
401 cmocka_unit_test(test_builder_byte_string_callback_append),
402 cmocka_unit_test(test_builder_byte_string_callback_append_alloc_failure),
403 cmocka_unit_test(
404 test_builder_byte_string_callback_append_item_alloc_failure),
405 cmocka_unit_test(
406 test_builder_byte_string_callback_append_parent_alloc_failure),
407 cmocka_unit_test(test_builder_string_callback_append),
408 cmocka_unit_test(test_builder_string_callback_append_alloc_failure),
409 cmocka_unit_test(test_builder_string_callback_append_item_alloc_failure),
410 cmocka_unit_test(
411 test_builder_string_callback_append_parent_alloc_failure),
412 cmocka_unit_test(test_append_array_failure),
413 cmocka_unit_test(test_append_map_failure),
414 cmocka_unit_test(test_invalid_indef_break),
415 cmocka_unit_test(test_invalid_state_indef_break),
416 };
417
418 cmocka_run_group_tests(tests, NULL, NULL);
419 }
420