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
13unsigned 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 */
23static 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
32unsigned char bytestring_data[] = {0x01, 0x02, 0x03};
33static 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
73static 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
105static 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
139static 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
173unsigned char string_data[] = {0x61, 0x62, 0x63};
174static 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
210static 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
241static 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
273static 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
305static 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
334static 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
364unsigned char invalid_indef_break_data[] = {0x81, 0xFF};
365static 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
374static 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
398int 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