/work/include/cbor/common.h
Line | Count | Source |
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 | | |
8 | | #ifndef LIBCBOR_COMMON_H |
9 | | #define LIBCBOR_COMMON_H |
10 | | |
11 | | #include <assert.h> |
12 | | #include <stdbool.h> |
13 | | #include <stddef.h> |
14 | | #include <stdint.h> |
15 | | #include <stdlib.h> |
16 | | #include <string.h> |
17 | | |
18 | | #include "cbor/cbor_export.h" |
19 | | #include "cbor/configuration.h" |
20 | | #include "data.h" |
21 | | |
22 | | #ifdef __cplusplus |
23 | | extern "C" { |
24 | | |
25 | | /** |
26 | | * C99 is not a subset of C++ -- 'restrict' qualifier is not a part of the |
27 | | * language. This is a workaround to keep it in C headers -- compilers allow |
28 | | * linking non-restrict signatures with restrict implementations. |
29 | | * |
30 | | * If you know a nicer way, please do let me know. |
31 | | */ |
32 | | #define CBOR_RESTRICT_POINTER |
33 | | |
34 | | #else |
35 | | |
36 | | // MSVC + C++ workaround |
37 | | #define CBOR_RESTRICT_POINTER CBOR_RESTRICT_SPECIFIER |
38 | | |
39 | | #endif |
40 | | |
41 | | static const uint8_t cbor_major_version = CBOR_MAJOR_VERSION; |
42 | | static const uint8_t cbor_minor_version = CBOR_MINOR_VERSION; |
43 | | static const uint8_t cbor_patch_version = CBOR_PATCH_VERSION; |
44 | | |
45 | | #define CBOR_VERSION \ |
46 | | _CBOR_TO_STR(CBOR_MAJOR_VERSION) \ |
47 | | "." _CBOR_TO_STR(CBOR_MINOR_VERSION) "." _CBOR_TO_STR(CBOR_PATCH_VERSION) |
48 | | #define CBOR_HEX_VERSION \ |
49 | | ((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION) |
50 | | |
51 | | /* http://stackoverflow.com/questions/1644868/c-define-macro-for-debug-printing |
52 | | */ |
53 | | #ifdef DEBUG |
54 | | #include <stdio.h> |
55 | | #define _cbor_debug_print(fmt, ...) \ |
56 | | do { \ |
57 | | if (DEBUG) \ |
58 | | fprintf(stderr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __func__, \ |
59 | | __VA_ARGS__); \ |
60 | | } while (0) |
61 | | extern bool _cbor_enable_assert; |
62 | | // Like `assert`, but can be dynamically disabled in tests to allow testing |
63 | | // invalid behaviors. |
64 | | #define CBOR_ASSERT(e) assert(!_cbor_enable_assert || (e)) |
65 | | #define _CBOR_TEST_DISABLE_ASSERT(block) \ |
66 | | do { \ |
67 | | _cbor_enable_assert = false; \ |
68 | | block _cbor_enable_assert = true; \ |
69 | | } while (0) |
70 | | #else |
71 | | #define debug_print(fmt, ...) \ |
72 | | do { \ |
73 | | } while (0) |
74 | | #define CBOR_ASSERT(e) |
75 | | #define _CBOR_TEST_DISABLE_ASSERT(block) \ |
76 | | do { \ |
77 | | block \ |
78 | | } while (0) |
79 | | #endif |
80 | | |
81 | | #define CBOR_ASSERT_VALID_TYPE(item_type) \ |
82 | | CBOR_ASSERT(item_type >= CBOR_TYPE_UINT && item_type <= CBOR_TYPE_FLOAT_CTRL); |
83 | | |
84 | | #define _CBOR_TO_STR_(x) #x |
85 | | #define _CBOR_TO_STR(x) _CBOR_TO_STR_(x) /* enables proper double expansion */ |
86 | | |
87 | | #ifdef CBOR_HAS_NODISCARD_ATTRIBUTE |
88 | | #define CBOR_NODISCARD [[nodiscard]] |
89 | | #else |
90 | | #define CBOR_NODISCARD |
91 | | #endif |
92 | | |
93 | | #ifdef __GNUC__ |
94 | | #define _CBOR_UNUSED __attribute__((__unused__)) |
95 | | // Fall back to __attribute__((warn_unused_result)) if we don't have |
96 | | // [[nodiscard]] |
97 | | #ifdef CBOR_HAS_NODISCARD_ATTRIBUTE |
98 | | #define _CBOR_NODISCARD CBOR_NODISCARD |
99 | | #else |
100 | | #define _CBOR_NODISCARD __attribute__((warn_unused_result)) |
101 | | #endif |
102 | | #elif defined(_MSC_VER) |
103 | | #define _CBOR_UNUSED __pragma(warning(suppress : 4100 4101)) |
104 | | #define _CBOR_NODISCARD |
105 | | #else |
106 | | #define _CBOR_UNUSED |
107 | | #define _CBOR_NODISCARD |
108 | | #endif |
109 | | |
110 | | #ifdef CBOR_HAS_BUILTIN_UNREACHABLE |
111 | | #define _CBOR_UNREACHABLE __builtin_unreachable() |
112 | | #else |
113 | | #define _CBOR_UNREACHABLE |
114 | | #endif |
115 | | |
116 | | typedef void* (*_cbor_malloc_t)(size_t); |
117 | | typedef void* (*_cbor_realloc_t)(void*, size_t); |
118 | | typedef void (*_cbor_free_t)(void*); |
119 | | |
120 | | CBOR_EXPORT extern _cbor_malloc_t _cbor_malloc; |
121 | | CBOR_EXPORT extern _cbor_realloc_t _cbor_realloc; |
122 | | CBOR_EXPORT extern _cbor_free_t _cbor_free; |
123 | | |
124 | | // Macro to short-circuit builder functions when memory allocation fails |
125 | | #define _CBOR_NOTNULL(cbor_item) \ |
126 | | do { \ |
127 | | if (cbor_item == NULL) { \ |
128 | | return NULL; \ |
129 | | } \ |
130 | | } while (0) |
131 | | |
132 | | // Macro to short-circuit builders when memory allocation of nested data |
133 | | // fails |
134 | | #define _CBOR_DEPENDENT_NOTNULL(cbor_item, pointer) \ |
135 | | do { \ |
136 | | if (pointer == NULL) { \ |
137 | | _cbor_free(cbor_item); \ |
138 | | return NULL; \ |
139 | | } \ |
140 | | } while (0) |
141 | | |
142 | | /** Sets the memory management routines to use. |
143 | | * |
144 | | * By default, libcbor will use the standard library `malloc`, `realloc`, |
145 | | * and `free`. |
146 | | * |
147 | | * A custom allocator is the intended mechanism for limiting memory |
148 | | * consumption when parsing untrusted CBOR data. Because definite-length |
149 | | * collections pre-allocate storage sized by the declared element count, |
150 | | * a crafted input can request a very large allocation before any element |
151 | | * data is read. A capping `custom_malloc` that returns NULL above a chosen |
152 | | * threshold will cause `cbor_load` to return `CBOR_ERR_MEMERROR` instead of |
153 | | * attempting the allocation. See `examples/capped_alloc.c` for a |
154 | | * self-contained demonstration. |
155 | | * |
156 | | * \rst |
157 | | * .. warning:: |
158 | | * This function modifies the global state and should |
159 | | * therefore be used accordingly. Changing the memory handlers while |
160 | | * allocated items exist will result in a ``free``/``malloc`` mismatch. |
161 | | * This function is not thread safe with respect to both itself and all |
162 | | * the other *libcbor* functions that work with the heap. |
163 | | * |
164 | | * .. note:: |
165 | | * `realloc` implementation must correctly support `NULL` |
166 | | * reallocation (see e.g. http://en.cppreference.com/w/c/memory/realloc) |
167 | | * |
168 | | * \endrst |
169 | | * |
170 | | * @param custom_malloc malloc implementation |
171 | | * @param custom_realloc realloc implementation |
172 | | * @param custom_free free implementation |
173 | | */ |
174 | | CBOR_EXPORT void cbor_set_allocs(_cbor_malloc_t custom_malloc, |
175 | | _cbor_realloc_t custom_realloc, |
176 | | _cbor_free_t custom_free); |
177 | | |
178 | | /* |
179 | | * ============================================================================ |
180 | | * Type manipulation |
181 | | * ============================================================================ |
182 | | */ |
183 | | |
184 | | /** Get the type of the item |
185 | | * |
186 | | * @param item |
187 | | * @return The type |
188 | | */ |
189 | | _CBOR_NODISCARD |
190 | | CBOR_EXPORT cbor_type cbor_typeof( |
191 | | const cbor_item_t* item); /* Will be inlined iff link-time opt is enabled */ |
192 | | |
193 | | /* Standard CBOR Major item types */ |
194 | | |
195 | | /** Does the item have the appropriate major type? |
196 | | * @param item the item |
197 | | * @return Is the item an #CBOR_TYPE_UINT? |
198 | | */ |
199 | | _CBOR_NODISCARD |
200 | | CBOR_EXPORT bool cbor_isa_uint(const cbor_item_t* item); |
201 | | |
202 | | /** Does the item have the appropriate major type? |
203 | | * @param item the item |
204 | | * @return Is the item a #CBOR_TYPE_NEGINT? |
205 | | */ |
206 | | _CBOR_NODISCARD |
207 | | CBOR_EXPORT bool cbor_isa_negint(const cbor_item_t* item); |
208 | | |
209 | | /** Does the item have the appropriate major type? |
210 | | * @param item the item |
211 | | * @return Is the item a #CBOR_TYPE_BYTESTRING? |
212 | | */ |
213 | | _CBOR_NODISCARD |
214 | | CBOR_EXPORT bool cbor_isa_bytestring(const cbor_item_t* item); |
215 | | |
216 | | /** Does the item have the appropriate major type? |
217 | | * @param item the item |
218 | | * @return Is the item a #CBOR_TYPE_STRING? |
219 | | */ |
220 | | _CBOR_NODISCARD |
221 | | CBOR_EXPORT bool cbor_isa_string(const cbor_item_t* item); |
222 | | |
223 | | /** Does the item have the appropriate major type? |
224 | | * @param item the item |
225 | | * @return Is the item an #CBOR_TYPE_ARRAY? |
226 | | */ |
227 | | _CBOR_NODISCARD |
228 | | CBOR_EXPORT bool cbor_isa_array(const cbor_item_t* item); |
229 | | |
230 | | /** Does the item have the appropriate major type? |
231 | | * @param item the item |
232 | | * @return Is the item a #CBOR_TYPE_MAP? |
233 | | */ |
234 | | _CBOR_NODISCARD |
235 | | CBOR_EXPORT bool cbor_isa_map(const cbor_item_t* item); |
236 | | |
237 | | /** Does the item have the appropriate major type? |
238 | | * @param item the item |
239 | | * @return Is the item a #CBOR_TYPE_TAG? |
240 | | */ |
241 | | _CBOR_NODISCARD |
242 | | CBOR_EXPORT bool cbor_isa_tag(const cbor_item_t* item); |
243 | | |
244 | | /** Does the item have the appropriate major type? |
245 | | * @param item the item |
246 | | * @return Is the item a #CBOR_TYPE_FLOAT_CTRL? |
247 | | */ |
248 | | _CBOR_NODISCARD |
249 | | CBOR_EXPORT bool cbor_isa_float_ctrl(const cbor_item_t* item); |
250 | | |
251 | | /* Practical types with respect to their semantics (but not tag values) */ |
252 | | |
253 | | /** Is the item an integer, either positive or negative? |
254 | | * @param item the item |
255 | | * @return Is the item an integer, either positive or negative? |
256 | | */ |
257 | | _CBOR_NODISCARD |
258 | | CBOR_EXPORT bool cbor_is_int(const cbor_item_t* item); |
259 | | |
260 | | /** Is the item an a floating point number? |
261 | | * @param item the item |
262 | | * @return Is the item a floating point number? |
263 | | */ |
264 | | _CBOR_NODISCARD |
265 | | CBOR_EXPORT bool cbor_is_float(const cbor_item_t* item); |
266 | | |
267 | | /** Is the item an a boolean? |
268 | | * @param item the item |
269 | | * @return Is the item a boolean? |
270 | | */ |
271 | | _CBOR_NODISCARD |
272 | | CBOR_EXPORT bool cbor_is_bool(const cbor_item_t* item); |
273 | | |
274 | | /** Does this item represent `null` |
275 | | * |
276 | | * \rst |
277 | | * .. warning:: |
278 | | * This is in no way related to the value of the pointer. |
279 | | * Passing a null pointer will most likely result in a crash. |
280 | | * \endrst |
281 | | * |
282 | | * @param item the item |
283 | | * @return Is the item (CBOR logical) null? |
284 | | */ |
285 | | _CBOR_NODISCARD |
286 | | CBOR_EXPORT bool cbor_is_null(const cbor_item_t* item); |
287 | | |
288 | | /** Does this item represent `undefined` |
289 | | * |
290 | | * \rst |
291 | | * .. warning:: |
292 | | * Care must be taken to distinguish nulls and undefined values in C. |
293 | | * \endrst |
294 | | * |
295 | | * @param item the item |
296 | | * @return Is the item (CBOR logical) undefined? |
297 | | */ |
298 | | _CBOR_NODISCARD |
299 | | CBOR_EXPORT bool cbor_is_undef(const cbor_item_t* item); |
300 | | |
301 | | /* |
302 | | * ============================================================================ |
303 | | * Memory management |
304 | | * ============================================================================ |
305 | | */ |
306 | | |
307 | | /** Increases the item's reference count by one |
308 | | * |
309 | | * Constant complexity; items referring to this one or items being |
310 | | * referred to are not updated. |
311 | | * |
312 | | * This function can be used to extend reference counting to client code. |
313 | | * |
314 | | * Defined `static inline` so the single-instruction increment is emitted |
315 | | * directly at the call site — meaningful for hot loops that build |
316 | | * #cbor_item_t trees, where every constructed item touches the refcount. |
317 | | * |
318 | | * @param item Reference to an item |
319 | | * @return The input \p item |
320 | | */ |
321 | 0 | static inline cbor_item_t* cbor_incref(cbor_item_t* item) { |
322 | 0 | item->refcount++; |
323 | 0 | return item; |
324 | 0 | } |
325 | | |
326 | | /** Slow path of #cbor_decref: performs the actual deallocation once the |
327 | | * reference count reaches zero. Do not call directly; use #cbor_decref. |
328 | | * |
329 | | * Split from #cbor_decref so the fast path (decrement + zero check) can |
330 | | * inline while the recursive free logic — which dominates code size — |
331 | | * stays out of line. |
332 | | */ |
333 | | CBOR_EXPORT void _cbor_decref_free(cbor_item_t* item); |
334 | | |
335 | | /** Decreases the item's reference count by one, deallocating the item if |
336 | | * needed |
337 | | * |
338 | | * In case the item is deallocated, the reference count of all items this |
339 | | * item references will also be #cbor_decref 'ed recursively. |
340 | | * |
341 | | * The fast path (decrement, check for zero) is `static inline`; only the |
342 | | * uncommon deallocation branch calls into #_cbor_decref_free. This keeps |
343 | | * every non-final decref a couple of instructions at the call site. |
344 | | * |
345 | | * @param item Reference to an item. Will be set to `NULL` if deallocated |
346 | | */ |
347 | 2.49k | static inline void cbor_decref(cbor_item_t** item_ref) { |
348 | 2.49k | cbor_item_t* item = *item_ref; |
349 | 2.49k | CBOR_ASSERT(item->refcount > 0); |
350 | 2.49k | if (--item->refcount == 0) { |
351 | 2.49k | _cbor_decref_free(item); |
352 | | *item_ref = NULL; |
353 | 2.49k | } |
354 | 2.49k | } |
355 | | |
356 | | /** Decreases the item's reference count by one, deallocating the item if |
357 | | * needed |
358 | | * |
359 | | * Convenience wrapper for #cbor_decref when its set-to-null behavior is |
360 | | * not needed |
361 | | * |
362 | | * @param item Reference to an item |
363 | | */ |
364 | | CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t* item); |
365 | | |
366 | | /** Get the item's reference count |
367 | | * |
368 | | * \rst |
369 | | * .. warning:: |
370 | | * This does *not* account for transitive references. |
371 | | * \endrst |
372 | | * |
373 | | * @todo Add some inline examples for reference counting |
374 | | * |
375 | | * @param item the item |
376 | | * @return the reference count |
377 | | */ |
378 | | _CBOR_NODISCARD |
379 | | CBOR_EXPORT size_t cbor_refcount(const cbor_item_t* item); |
380 | | |
381 | | /** Provides CPP-like move construct |
382 | | * |
383 | | * Decreases the reference count by one, but does not deallocate the item |
384 | | * even if its refcount reaches zero. This is useful for passing |
385 | | * intermediate values to functions that increase reference count. Should |
386 | | * only be used with functions that `incref` their arguments. |
387 | | * |
388 | | * \rst |
389 | | * .. warning:: |
390 | | * If the item is moved without correctly increasing the |
391 | | * reference count afterwards, the memory will be leaked. |
392 | | * \endrst |
393 | | * |
394 | | * @param item Reference to an item |
395 | | * @return the item with reference count decreased by one |
396 | | */ |
397 | | _CBOR_NODISCARD |
398 | | CBOR_EXPORT cbor_item_t* cbor_move(cbor_item_t* item); |
399 | | |
400 | | /** Compares two items for structural (encoding-level) equality |
401 | | * |
402 | | * Two items are structurally equal when they would produce identical bytes |
403 | | * if serialized by a correct CBOR encoder that preserves the in-memory |
404 | | * representation. Every aspect of the encoding counts: |
405 | | * |
406 | | * - **Major type**: `CBOR_TYPE_UINT` and `CBOR_TYPE_NEGINT` are distinct even |
407 | | * if the argument bytes happen to be the same. |
408 | | * - **Integer encoding width**: `cbor_build_uint8(1)` and |
409 | | * `cbor_build_uint16(1)` are *not* structurally equal, even though both |
410 | | * represent the integer 1. Use the integer value accessors (`cbor_get_uint64` |
411 | | * etc.) if you need value-level comparison. |
412 | | * - **Definite vs. indefinite length**: a definite-length array and an |
413 | | * indefinite-length array with the same elements are *not* structurally |
414 | | * equal. |
415 | | * - **Chunk boundaries**: two indefinite bytestrings or strings that carry the |
416 | | * same bytes but split them across a different number of chunks are *not* |
417 | | * structurally equal. |
418 | | * - **Map entry order**: maps are compared positionally — entry at index i in |
419 | | * \p item1 must match entry at index i in \p item2. Maps that carry the same |
420 | | * key-value pairs in a different order are *not* structurally equal. (CBOR |
421 | | * maps are unordered in the data model; for data-model equality see RFC 8949 |
422 | | * §5.6.1.) |
423 | | * - **Float encoding width**: `cbor_build_float2(1.5)` and |
424 | | * `cbor_build_float4(1.5)` are *not* structurally equal. |
425 | | * - **NaN payload**: floating-point NaN values with different bit patterns are |
426 | | * *not* structurally equal. |
427 | | * - **Tag number**: tags with different tag numbers are *not* structurally |
428 | | * equal. |
429 | | * |
430 | | * Runs in time linear in the encoded byte size of the items and performs no |
431 | | * additional memory allocations. |
432 | | * |
433 | | * \rst |
434 | | * .. note:: |
435 | | * This function implements *structural* equality, not the data-model equality |
436 | | * defined by RFC 8949. In the CBOR data model, encoding width is invisible |
437 | | * and maps are unordered sets of key-value pairs. If you need data-model |
438 | | * equality (e.g., ``uint8(1) == uint64(1)``), you must implement it on top |
439 | | * of this library. |
440 | | * \endrst |
441 | | * |
442 | | * Neither \p item1 nor \p item2 may be `NULL`. Passing `NULL` is a |
443 | | * programming error and will trigger an assertion failure in debug builds. |
444 | | * |
445 | | * @param item1 First item; must not be `NULL` |
446 | | * @param item2 Second item; must not be `NULL` |
447 | | * @return `true` if \p item1 and \p item2 are structurally equal |
448 | | */ |
449 | | _CBOR_NODISCARD |
450 | | CBOR_EXPORT bool cbor_structurally_equal(const cbor_item_t* item1, |
451 | | const cbor_item_t* item2); |
452 | | |
453 | | #ifdef __cplusplus |
454 | | } |
455 | | #endif |
456 | | |
457 | | #endif // LIBCBOR_COMMON_H |