aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2026-03-22 14:31:52 +0000
committerEd Maste <emaste@FreeBSD.org>2026-03-22 14:32:11 +0000
commit0427abbc78cf28d98d8f1393669ba96e4018a77b (patch)
tree2829de4b4ccdc1c7c36c38d40266a14b3bafd5c7
parentaa1599ed2bad271ece23ac2d2ca14c6540fa5ffa (diff)
Vendor import of libcbor 0.13.0vendor/libcbor/0.13.0vendor/libcbor
Sponsored by: The FreeBSD Foundation
-rw-r--r--.circleci/config.yml16
-rw-r--r--.cirrus.yml1
-rw-r--r--.gitignore3
-rw-r--r--.vscode/settings.json6
-rw-r--r--CHANGELOG.md68
-rw-r--r--CMakeLists.txt109
-rw-r--r--Doxyfile2
-rw-r--r--README.md53
-rw-r--r--doc/source/api/item_reference_counting.rst1
-rw-r--r--doc/source/conf.py4
-rw-r--r--doc/source/development.rst15
-rw-r--r--doc/source/getting_started.rst3
-rw-r--r--doc/source/index.rst4
-rw-r--r--doc/source/requirements.in5
-rw-r--r--doc/source/requirements.txt88
-rw-r--r--doc/source/tutorial.rst66
-rw-r--r--doc/source/using.rst174
-rw-r--r--examples/CMakeLists.txt6
-rw-r--r--examples/bazel/third_party/libcbor/cbor/configuration.h2
-rw-r--r--examples/cbor_sequence.c109
-rw-r--r--examples/crash_course.c183
-rw-r--r--misc/asan_suppressions.osx.supp3
-rwxr-xr-xrelease.sh1
-rw-r--r--src/cbor.c149
-rw-r--r--src/cbor.h11
-rw-r--r--src/cbor/arrays.c3
-rw-r--r--src/cbor/arrays.h3
-rw-r--r--src/cbor/common.c32
-rw-r--r--src/cbor/common.h82
-rw-r--r--src/cbor/floats_ctrls.c8
-rw-r--r--src/cbor/floats_ctrls.h5
-rw-r--r--src/cbor/ints.c7
-rw-r--r--src/cbor/serialization.c40
-rw-r--r--src/cbor/serialization.h5
-rw-r--r--src/cbor/streaming.c4
-rw-r--r--src/cbor/strings.h7
-rw-r--r--test/callbacks_test.c49
-rw-r--r--test/copy_test.c344
-rw-r--r--test/float_ctrl_test.c21
-rw-r--r--test/map_test.c16
40 files changed, 1334 insertions, 374 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 2d3d1ea8fcc1..ea030d6b7b8e 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -44,7 +44,9 @@ commands:
- run: make -j 16 VERBOSE=1
test:
steps:
- - run: ctest -VV
+ - run: ctest -VV --output-junit ctest_out.xml
+ - store_test_results:
+ path: ctest_out.xml
orbs:
codecov: codecov/codecov@3.2.2
@@ -238,6 +240,17 @@ jobs:
docker:
- image: dockcross/linux-mipsel-lts
+
+ build-and-test-riscv64: &dockcross-job
+ docker:
+ - image: dockcross/linux-riscv64
+ steps:
+ - checkout
+ - attach_workspace:
+ at: /home/circleci/project
+ - build-with-cmocka-from-source
+ - test
+
workflows:
build-and-test:
jobs:
@@ -250,6 +263,7 @@ workflows:
- build-and-test-win
- build-and-test-mips
- build-and-test-mipsel
+ - build-and-test-riscv64
- build-bazel
- llvm-coverage
# OSX builds are expensive, run only on master
diff --git a/.cirrus.yml b/.cirrus.yml
index d3be21bc1d4c..beaea2a0b6ee 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -5,7 +5,6 @@ freebsd_task:
- mkdir build
- cd build
- cmake -GNinja -DWITH_TESTS=ON
- -DCBOR_CUSTOM_ALLOC=ON
-DCMAKE_BUILD_TYPE=Debug
-DSANITIZE=OFF
..
diff --git a/.gitignore b/.gitignore
index a927c86360a3..cfc2f906bd0a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,8 @@ doxygen_docs
cmake-build-debug
venv
**.DS_Store
-.vscode
+.vscode/tmp
+.vscode/c_cpp_properties.json
doc/build
# No top-level requirements, see doc/source
requirements.txt
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 000000000000..1efd1526d101
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,6 @@
+{
+ "C_Cpp.clang_format_style": "file",
+ "editor.formatOnSave": true,
+ "cmake.configureOnOpen": true,
+ "cmake.buildDirectory": "${workspaceFolder}/.vscode/tmp/build_${buildType}",
+} \ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8acd3265e490..7509569b414f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,21 +1,36 @@
Template:
+
- [Fix issue X in feature Y](https://github.com/PJK/libcbor/pull/XXX) (by [YYY](https://github.com/YYY))
Next
---------------------
+0.13.0 (2025-08-30)
+---------------------
+
+- [Fix `cbor_is_null`, `cbor_is_undef`, `cbor_is_bool` assertion failing on non-ctrl floats in debug mode](https://github.com/PJK/libcbor/issues/352) (bug discovered by <https://github.com/psturm-swift>)
+- [Add an example for handling of CBOR Sequences](https://github.com/PJK/libcbor/pull/358)
+- [Use C23/c2x if available](https://github.com/PJK/libcbor/pull/361)
+ - libcbor remains C99 compatible
+ - When the compiler does not support new standard, C99 will be used, so the change should be backwards compatible
+- [Improved introduction documentation and examples](https://github.com/PJK/libcbor/pull/363)
+- [Add cbor_copy_definite to turn indefinite items into definite equivalents](https://github.com/PJK/libcbor/pull/364/files) (proposed by Jacob Teplitsky)
+- BUILD BREAKING: [Minimum CMake version set to 3.5](https://github.com/PJK/libcbor/pull/355) to [be compatible with CMake 4](https://github.com/eclipse-ecal/ecal/issues/2041) ([suggestion](https://github.com/PJK/libcbor/commit/1183292d4695300785b272532c1e02d68840e4b8#commitcomment-164507943) by <https://github.com/hnyman>)
+ - See <https://repology.org/project/cmake/versions> for support; the vast majority of users should not be affected.
+
0.12.0 (2025-03-16)
---------------------
-- BUILD BREAKING: [Respect `INTERPROCEDURAL_OPTIMIZATION` and use the default value](https://github.com/PJK/libcbor/issues/315)
+
+- BUILD BREAKING: [Respect `INTERPROCEDURAL_OPTIMIZATION` and use the default value](https://github.com/PJK/libcbor/issues/315)
- BREAKING: Changes to NaN encoding
- [Fix NaN encoding on Windows](https://github.com/PJK/libcbor/issues/271)
- [Fix NaN encoding on mips/mipsel](https://github.com/PJK/libcbor/issues/329)
- [Signaling NaNs will from now on be encoded as canonical quiet NaNs](https://github.com/PJK/libcbor/pull/335). This was already the existing behavior for half-precision floats
- Decoding is unchanged
- - Please note that this is an intermediate state and likely to be revisited (https://github.com/PJK/libcbor/issues/336)
+ - Please note that this is an intermediate state and likely to be revisited (<https://github.com/PJK/libcbor/issues/336>)
- [Make build compatible with CMake FetchContent](https://github.com/PJK/libcbor/pull/341) (by [Jan200101](https://github.com/Jan200101))
- [Support Bzlmod for Bazel builds](https://github.com/PJK/libcbor/pull/340)
- - This should significantly simplify including libcbor as a dependency/module in Bazel projects, see https://bazel.build/external/migration
+ - This should significantly simplify including libcbor as a dependency/module in Bazel projects, see <https://bazel.build/external/migration>
- Code quality improvements
- [Fix compiler pragmas](https://github.com/PJK/libcbor/pull/347) (by [brooksdavis](https://github.com/brooksdavis))
- [Fix code style issues](https://github.com/PJK/libcbor/pull/321)
@@ -23,35 +38,39 @@ Next
0.11.0 (2024-02-04)
---------------------
+
- [Updated documentation to refer to RFC 8949](https://github.com/PJK/libcbor/issues/269)
- Improvements to `cbor_describe`
- [Bytestring data will now be printed as well](https://github.com/PJK/libcbor/pull/281) by [akallabeth](https://github.com/akallabeth)
- [Formatting consistency and clarity improvements](https://github.com/PJK/libcbor/pull/285)
- [Fix `cbor_string_set_handle` not setting the codepoint count](https://github.com/PJK/libcbor/pull/286)
- BREAKING: [`cbor_load` will no longer fail on input strings that are well-formed but not valid UTF-8](https://github.com/PJK/libcbor/pull/286)
- - If you were relying on the validation, please check the result using `cbor_string_codepoint_count` instead
+ - If you were relying on the validation, please check the result using `cbor_string_codepoint_count` instead
- BREAKING: [All decoders like `cbor_load` and `cbor_stream_decode` will accept all well-formed tag values](https://github.com/PJK/libcbor/pull/308) (bug discovered by [dskern-github](https://github.com/dskern-github))
- Previously, decoding of certain values would fail with `CBOR_ERR_MALFORMATED` or `CBOR_DECODER_ERROR`
- This also makes decoding symmetrical with serialization, which already accepts all values
0.10.2 (2023-01-31)
---------------------
+
- [Fixed minor test bug causing failures for x86 Linux](https://github.com/PJK/libcbor/pull/266) (discovered by [trofi](https://github.com/PJK/libcbor/issues/263))
- Actual libcbor functionality not affected, bug was in the test suite
- [Made tests platform-independent](https://github.com/PJK/libcbor/pull/272)
0.10.1 (2022-12-30)
---------------------
+
- [Fix a regression in `cbor_serialize_alloc` that caused serialization of zero-length strings and bytestrings or byte/strings with zero-length chunks to fail](https://github.com/PJK/libcbor/pull/260) (discovered by [martelletto](https://github.com/martelletto))
0.10.0 (2022-12-29)
---------------------
+
- Make the buffer_size optional in `cbor_serialize_alloc` [[#205]](https://github.com/PJK/libcbor/pull/205) (by [hughsie](https://github.com/hughsie))
- BREAKING: Improved half-float encoding for denormalized numbers. [[#208]](https://github.com/PJK/libcbor/pull/208) (by [ranvis](https://github.com/ranvis))
- Denormalized half-floats will now preserve data in the mantissa
- - Note: Half-float NaNs still lose data (https://github.com/PJK/libcbor/issues/215)
+ - Note: Half-float NaNs still lose data (<https://github.com/PJK/libcbor/issues/215>)
- BUILD BREAKING: Minimum CMake version is 3.0 [[#201]](https://github.com/PJK/libcbor/pull/201) (by [thewtex@](https://github.com/thewtex))
- - See https://repology.org/project/cmake/versions for support; the vast majority of users should not be affected.
+ - See <https://repology.org/project/cmake/versions> for support; the vast majority of users should not be affected.
- Fix a potential memory leak when the allocator fails during array or map decoding [[#224]](https://github.com/PJK/libcbor/pull/224) (by [James-ZHANG](https://github.com/James-ZHANG))
- [Fix a memory leak when the allocator fails when adding chunks to indefinite bytestrings.](https://github.com/PJK/libcbor/pull/242) ([discovered](https://github.com/PJK/libcbor/pull/228) by [James-ZHANG](https://github.com/James-ZHANG))
- [Fix a memory leak when the allocator fails when adding chunks to indefinite strings](https://github.com/PJK/libcbor/pull/246)
@@ -70,57 +89,62 @@ Next
0.9.0 (2021-11-14)
---------------------
+
- Improved pkg-config paths handling [[#164]](https://github.com/PJK/libcbor/pull/164) (by [jtojnar@](https://github.com/jtojnar))
- Use explicit math.h linkage [[#170]](https://github.com/PJK/libcbor/pull/170)
- BREAKING: Fixed handling of items that exceed the host size_t range [[#186]](https://github.com/PJK/libcbor/pull/186hg)
- - Callbacks for bytestrings, strings, arrays, and maps use uint64_t instead of size_t to allow handling of large items that exceed size_t even if size_t < uint64_t
- - cbor_decode explicitly checks size to avoid overflows (previously broken, potentially resulting in erroneous decoding on affected systems)
- - The change should be a noop for 64b systems
+ - Callbacks for bytestrings, strings, arrays, and maps use uint64_t instead of size_t to allow handling of large items that exceed size_t even if size_t < uint64_t
+ - cbor_decode explicitly checks size to avoid overflows (previously broken, potentially resulting in erroneous decoding on affected systems)
+ - The change should be a noop for 64b systems
- Added a [Bazel](https://bazel.build/) build example [[#196]](https://github.com/PJK/libcbor/pull/196) (by [andyjgf@](https://github.com/andyjgf))
0.8.0 (2020-09-20)
---------------------
+
- BUILD BREAKING: Use BUILD_SHARED_LIBS to determine how to build libraries (fixed Windows linkage) [[#148]](https://github.com/PJK/libcbor/pull/148) (by [intelligide@](https://github.com/intelligide))
- BREAKING: Fix `cbor_tag_item` not increasing the reference count on the tagged item reference it returns [[Fixes #109](https://github.com/PJK/libcbor/issues/109)] (discovered bt [JohnGilmour](https://github.com/JohnGilmour))
- If you have previously relied on the broken behavior, you can use `cbor_move` to emulate as long as the returned handle is an "rvalue"
- BREAKING: [`CBOR_DECODER_EBUFFER` removed from `cbor_decoder_status`](https://github.com/PJK/libcbor/pull/156)
- - `cbor_stream_decode` will set `CBOR_DECODER_NEDATA` instead if the input buffer is empty
+ - `cbor_stream_decode` will set `CBOR_DECODER_NEDATA` instead if the input buffer is empty
- [Fix `cbor_stream_decode`](https://github.com/PJK/libcbor/pull/156) to set `cbor_decoder_result.required` to the minimum number of input bytes necessary to receive the next callback (as long as at least one byte was passed) (discovered by [woefulwabbit](https://github.com/woefulwabbit))
- Fixed several minor manpage issues [[#159]](https://github.com/PJK/libcbor/pull/159) (discovered by [kloczek@](https://github.com/kloczek))
0.7.0 (2020-04-25)
---------------------
+
- Fix bad encoding of NaN half-floats [[Fixes #53]](https://github.com/PJK/libcbor/issues/53) (discovered by [BSipos-RKF](https://github.com/BSipos-RKF))
- - **Warning**: Previous versions encoded NaNs as `0xf9e700` instead of `0xf97e00`; if you rely on the broken behavior, this will be a breaking change
+ - **Warning**: Previous versions encoded NaNs as `0xf9e700` instead of `0xf97e00`; if you rely on the broken behavior, this will be a breaking change
- Fix potentially bad encoding of negative half-float with exponent < -14 [[Fixes #112]](https://github.com/PJK/libcbor/issues/112) (discovered by [yami36](https://github.com/yami36))
- BREAKING: Improved bool support [[Fixes #63]](https://github.com/PJK/libcbor/issues/63)
- - Rename `cbor_ctrl_is_bool` to `cbor_get_bool` and fix the behavior
- - Add `cbor_set_bool`
+ - Rename `cbor_ctrl_is_bool` to `cbor_get_bool` and fix the behavior
+ - Add `cbor_set_bool`
- Fix memory_allocation_test breaking the build without CBOR_CUSTOM_ALLOC [[Fixes #128]](https://github.com/PJK/libcbor/issues/128) (by [panlinux](https://github.com/panlinux))
- [Fix a potential build issue where cJSON includes may be misconfigured](https://github.com/PJK/libcbor/pull/132)
- Breaking: [Add a limit on the size of the decoding context stack](https://github.com/PJK/libcbor/pull/138) (by [James-ZHANG](https://github.com/James-ZHANG))
- - If your usecase requires parsing very deeply nested structures, you might need to increase the default 2k limit via `CBOR_MAX_STACK_SIZE`
+ - If your usecase requires parsing very deeply nested structures, you might need to increase the default 2k limit via `CBOR_MAX_STACK_SIZE`
- Enable LTO/IPO based on [CheckIPOSupported](https://cmake.org/cmake/help/latest/module/CheckIPOSupported.html#module:CheckIPOSupported) [[#143]](https://github.com/PJK/libcbor/pull/143) (by [xanderlent](https://github.com/xanderlent))
- - If you rely on LTO being enabled and use CMake version older than 3.9, you will need to re-enable it manually or upgrade your CMake
+ - If you rely on LTO being enabled and use CMake version older than 3.9, you will need to re-enable it manually or upgrade your CMake
0.6.1 (2020-03-26)
---------------------
+
- [Fix bad shared library version number](https://github.com/PJK/libcbor/pull/131)
- - **Warning**: Shared library built from the 0.6.0 release is erroneously marked as version "0.6.0", which makes it incompatible with future releases *including the v0.6.X line* even though they may be compatible API/ABI-wise. Refer to the documentation for the new SO versioning scheme.
+ - **Warning**: Shared library built from the 0.6.0 release is erroneously marked as version "0.6.0", which makes it incompatible with future releases *including the v0.6.X line* even though they may be compatible API/ABI-wise. Refer to the documentation for the new SO versioning scheme.
0.6.0 (2020-03-15)
---------------------
-- Correctly set .so version [[Fixes #52]](https://github.com/PJK/libcbor/issues/52).
- - **Warning**: All previous releases will be identified as 0.0 by the linker.
+
+- Correctly set .so version [[Fixes #52]](https://github.com/PJK/libcbor/issues/52).
+ - **Warning**: All previous releases will be identified as 0.0 by the linker.
- Fix & prevent heap overflow error in example code [[#74]](https://github.com/PJK/libcbor/pull/74) [[#76]](https://github.com/PJK/libcbor/pull/76) (by @nevun)
- Correctly set OSX dynamic library version [[Fixes #75]](https://github.com/PJK/libcbor/issues/75)
- [Fix misplaced 0xFF bytes in maps possibly causing memory corruption](https://github.com/PJK/libcbor/pull/82)
- BREAKING: Fix handling & cleanup of failed memory allocation in constructor
and builder helper functions [[Fixes #84]](https://github.com/PJK/libcbor/issues/84)
- - All cbor_new_* and cbor_build_* functions will now explicitly return NULL when memory allocation fails
+ - All cbor_new_*and cbor_build_* functions will now explicitly return NULL when memory allocation fails
- It is up to the client to handle such cases
- Globally enforced code style [[Fixes #83]](https://github.com/PJK/libcbor/issues/83)
-- Fix issue possible memory corruption bug on repeated
+- Fix issue possible memory corruption bug on repeated
cbor_(byte)string_add_chunk calls with intermittently failing realloc calls
- Fix possibly misaligned reads and writes when endian.h is uses or when
running on a big-endian machine [[Fixes #99](https://github.com/PJK/libcbor/issues/99), [#100](https://github.com/PJK/libcbor/issues/100)]
@@ -129,6 +153,7 @@ Next
0.5.0 (2017-02-06)
---------------------
+
- Remove cmocka from the subtree (always rely on system or user-provided version)
- Windows CI
- Only build tests if explicitly enabled (`-DWITH_TESTS=ON`)
@@ -144,6 +169,7 @@ Next
0.4.0 (2015-12-25)
---------------------
+
Breaks build & header compatibility due to:
- Improved build configuration and feature check macros
@@ -154,6 +180,7 @@ Breaks build & header compatibility due to:
0.3.1 (2015-05-21)
---------------------
+
- documentation and comments improvements, mostly for the API reference
0.3.0 (2015-05-21)
@@ -169,6 +196,7 @@ Breaks build & header compatibility due to:
0.2.1 (2015-05-17)
---------------------
+
- C99 support
0.2.0 (2015-05-17)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 815675edd81a..a7e133a3e888 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,13 +1,13 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.5)
-project(libcbor)
+project(libcbor LANGUAGES C CXX)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules/")
include(CTest)
include(GNUInstallDirs) # Provides CMAKE_INSTALL_ variables
set(CBOR_VERSION_MAJOR "0")
-set(CBOR_VERSION_MINOR "12")
+set(CBOR_VERSION_MINOR "13")
set(CBOR_VERSION_PATCH "0")
set(CBOR_VERSION
${CBOR_VERSION_MAJOR}.${CBOR_VERSION_MINOR}.${CBOR_VERSION_PATCH})
@@ -79,13 +79,44 @@ set(CPACK_PACKAGE_VERSION_PATCH ${CBOR_VERSION_PATCH})
include(CPack)
+#
+# Configure compilation flags and language features
+#
+
+include(CheckCSourceCompiles)
+
+check_c_source_compiles("
+ #include <stdio.h>
+ [[nodiscard]] int f(void) { return 42; }
+ int main(void) { return f(); }
+" HAS_NODISCARD_ATTRIBUTE)
+
+if (HAS_NODISCARD_ATTRIBUTE)
+ message(STATUS "[[nodiscard]] is supported.")
+ add_definitions(-D_CBOR_HAS_NODISCARD_ATTRIBUTE)
+ # Assume that if we have [[nodiscard]], we have some C23 support. May fail.
+ if(NOT DEFINED CMAKE_C_STANDARD)
+ message(STATUS "Switching to C23-like mode. To prevent this, pass -DCMAKE_C_STANDARD explicitly.")
+ # On Clang 16, this is resolved to -std=c2x
+ set(CMAKE_C_STANDARD 23 CACHE STRING "C language standard")
+ endif()
+endif()
+
if(MINGW)
# https://github.com/PJK/libcbor/issues/13
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
elseif(NOT MSVC)
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -pedantic")
+ # Default to C99
+ if(NOT DEFINED CMAKE_C_STANDARD)
+ set(CMAKE_C_STANDARD 99 CACHE STRING "C language standard")
+ endif()
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pedantic")
endif()
+# CMAKE_C_STANDARD set above
+set(CMAKE_C_STANDARD_REQUIRED ON)
+set(CMAKE_C_EXTENSIONS OFF)
+
if(MSVC)
# This just doesn't work right --
# https://msdn.microsoft.com/en-us/library/5ft82fed.aspx
@@ -98,8 +129,8 @@ else()
set(CBOR_RESTRICT_SPECIFIER "restrict")
set(CMAKE_C_FLAGS_DEBUG
- "${CMAKE_C_FLAGS_DEBUG} -O0 -pedantic -Wall -Wextra -g -ggdb -DDEBUG=true")
- set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -pedantic -Wall -Wextra -DNDEBUG")
+ "${CMAKE_C_FLAGS_DEBUG} -O0 -Wall -Wextra -g -ggdb -DDEBUG=true")
+ set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3 -Wall -Wextra -DNDEBUG")
if(SANITIZE)
set(CMAKE_C_FLAGS_DEBUG
@@ -124,8 +155,6 @@ else()
add_definitions(-DEIGHT_BYTE_SIZE_T)
endif()
-include(CheckCSourceCompiles)
-
check_c_source_compiles("
int main() {
__builtin_unreachable();
@@ -137,6 +166,36 @@ if (HAS_BUILTIN_UNREACHABLE)
add_definitions(-D_CBOR_HAS_BUILTIN_UNREACHABLE)
endif()
+# CMake >= 3.9.0 enables LTO for GCC and Clang with INTERPROCEDURAL_OPTIMIZATION
+# Policy CMP0069 enables this behavior when we set the minimum CMake version <
+# 3.9.0 Checking for LTO support before setting INTERPROCEDURAL_OPTIMIZATION is
+# mandatory with CMP0069 set to NEW.
+set(LTO_SUPPORTED FALSE)
+if(${CMAKE_VERSION} VERSION_GREATER "3.9.0" OR ${CMAKE_VERSION} VERSION_EQUAL
+ "3.9.0")
+ cmake_policy(SET CMP0069 NEW)
+ # Require LTO support to build libcbor with newer CMake versions
+ include(CheckIPOSupported)
+ check_ipo_supported(RESULT LTO_SUPPORTED)
+endif()
+
+if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
+ set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
+endif()
+
+if(LTO_SUPPORTED)
+ message(
+ STATUS
+ "LTO is supported and CMAKE_INTERPROCEDURAL_OPTIMIZATION=${CMAKE_INTERPROCEDURAL_OPTIMIZATION}"
+ )
+else()
+ message(STATUS "LTO is not supported")
+endif()
+
+#
+# Testing and validation
+#
+
enable_testing()
set(CTEST_MEMORYCHECK_COMMAND "/usr/bin/valgrind")
@@ -180,8 +239,6 @@ add_custom_target(
VERBATIM
COMMENT "Generate coverage report using the LLVM toolchain")
-include_directories(src)
-
option(COVERAGE "Enable code coverage instrumentation" OFF)
if(COVERAGE)
message("Configuring code coverage instrumentation")
@@ -205,6 +262,12 @@ if(COVERAGE)
endif()
endif()
+#
+# Configure build and targets
+#
+
+include_directories(src)
+
# We want to generate configuration.h from the template and make it so that it
# is accessible using the same path during both library build and installed
# header use, without littering the source dir.
@@ -213,32 +276,6 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/cbor/configuration.h.in
install(FILES ${PROJECT_BINARY_DIR}/cbor/configuration.h
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cbor)
-# CMake >= 3.9.0 enables LTO for GCC and Clang with INTERPROCEDURAL_OPTIMIZATION
-# Policy CMP0069 enables this behavior when we set the minimum CMake version <
-# 3.9.0 Checking for LTO support before setting INTERPROCEDURAL_OPTIMIZATION is
-# mandatory with CMP0069 set to NEW.
-set(LTO_SUPPORTED FALSE)
-if(${CMAKE_VERSION} VERSION_GREATER "3.9.0" OR ${CMAKE_VERSION} VERSION_EQUAL
- "3.9.0")
- cmake_policy(SET CMP0069 NEW)
- # Require LTO support to build libcbor with newer CMake versions
- include(CheckIPOSupported)
- check_ipo_supported(RESULT LTO_SUPPORTED)
-endif()
-
-if(NOT DEFINED CMAKE_INTERPROCEDURAL_OPTIMIZATION)
- set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
-endif()
-
-if(LTO_SUPPORTED)
- message(
- STATUS
- "LTO is supported and CMAKE_INTERPROCEDURAL_OPTIMIZATION=${CMAKE_INTERPROCEDURAL_OPTIMIZATION}"
- )
-else()
- message(STATUS "LTO is not supported")
-endif()
-
add_subdirectory(src)
if(LTO_SUPPORTED)
set_property(DIRECTORY src PROPERTY INTERPROCEDURAL_OPTIMIZATION CMAKE_INTERPROCEDURAL_OPTIMIZATION)
diff --git a/Doxyfile b/Doxyfile
index e612afb4b199..04964e73d5c3 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = libcbor
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.12.0
+PROJECT_NUMBER = 0.13.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/README.md b/README.md
index ea54bed9437b..62d37b6b957d 100644
--- a/README.md
+++ b/README.md
@@ -8,16 +8,35 @@
**libcbor** is a C library for parsing and generating [CBOR](https://cbor.io/), the general-purpose schema-less binary data format.
## Main features
- - Complete [IETF RFC 8949 (STD 94)](https://www.rfc-editor.org/info/std94) conformance
- - Robust platform-independent C99 implementation
- - Layered architecture offers both control and convenience
- - Flexible memory management
- - No shared global state - threading friendly
- - Proper handling of UTF-8
- - Full support for streams & incremental processing
- - Extensive documentation and test suite
- - No runtime dependencies, small footprint
-
+
+- Complete CBOR [IETF RFC 8949 (STD 94)](https://www.rfc-editor.org/info/std94) specification conformance (previously known as [RFC 7049](https://www.rfc-editor.org/info/rfc7049))
+- Supports CBOR Sequences ([RFC 8742](https://datatracker.ietf.org/doc/html/rfc8742))
+- Robust platform-independent C99 implementation, tested on
+ - Linux, OS X, Windows, BSD
+ - x86(_64), arm(64), mips(el), riscv64
+- Layered architecture offers both control and convenience
+- Flexible memory management
+- No shared global state - threading friendly
+- Proper handling of UTF-8
+- Full support for streams & incremental processing
+- Extensive documentation and test suite
+- No runtime dependencies, small footprint
+
+## References
+
+libcbor is most prominently used in:
+
+- Yubico's [libfido2](https://developers.yubico.com/libfido2/) 2FA security key implementation
+- Amazon's [AWS C SDK](https://github.com/awslabs/aws-c-common)
+- Gnome [fwdup](https://github.com/fwupd/fwupd/blob/main/meson.build#L339)
+- Alibaba's [Inclavare librats](https://github.com/inclavare-containers/librats)
+- [QEMU](https://wiki.qemu.org/ChangeLog/9.2)
+- [ITK](https://docs.itk.org/projects/wasm/en/latest/introduction/parts.html)
+
+It found its way into many open source an proprietary projects. If you run among others [OpenSSH](https://www.matbra.com/2020/02/17/using-fido2-with-ssh.html), [Microsoft PowerShell](https://github.com/PowerShell/libcbor), [SteamOS](https://github.com/randombk/steamos-teardown/blob/5a37d977fae55d9c41eaf1d07528fa965740bb26/docs/packages.md?plain=1#L461), or [MySQL](https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-34.html) -- you might be indirectly running libcbor too.
+
+Also, thank you for the shout out in <https://github.com/oz123/awesome-c?tab=readme-ov-file#others>!
+
## Getting started
### Compile from source
@@ -48,7 +67,15 @@ sudo apt-get install libcbor-dev
yum install libcbor-devel
```
-### Others
+### Include git repository using using CMake
+
+See e.g. <https://github.com/inclavare-containers/librats/blob/master/cmake/LibCBOR.cmake>.
+
+## Include git repository using Bazel
+
+See <https://github.com/PJK/libcbor/tree/master/examples/bazel>.
+
+### Others
<details>
<summary>Packaged libcbor is available from 15+ major repositories. Click here for more detail</summary>
@@ -89,6 +116,9 @@ int main(void) {
```
## Documentation
+
+Crash course: <https://libcbor.readthedocs.io/en/latest/tutorial.html#crash-course>
+
Get the latest documentation at [libcbor.readthedocs.org](http://libcbor.readthedocs.org/)
## Contributions
@@ -98,6 +128,7 @@ Bug reports and contributions are welcome. Please see [CONTRIBUTING.md](https://
Kudos to all the [contributors](https://github.com/PJK/libcbor/graphs/contributors)!
## License
+
The MIT License (MIT)
Copyright (c) Pavel Kalvoda, 2014-2020
diff --git a/doc/source/api/item_reference_counting.rst b/doc/source/api/item_reference_counting.rst
index 70075cb67e5b..f590ac2e2292 100644
--- a/doc/source/api/item_reference_counting.rst
+++ b/doc/source/api/item_reference_counting.rst
@@ -36,3 +36,4 @@ The destruction is synchronous and renders any pointers to items with refcount z
.. doxygenfunction:: cbor_refcount
.. doxygenfunction:: cbor_move
.. doxygenfunction:: cbor_copy
+.. doxygenfunction:: cbor_copy_definite
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 4574669505e8..52c19154d04e 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -77,8 +77,8 @@ copyright = '2014 - 2020, Pavel Kalvoda'
# built documents.
#
# The short X.Y version.
-version = '0.12'
-release = '0.12.0'
+version = '0.13'
+release = '0.13.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/doc/source/development.rst b/doc/source/development.rst
index 5471047317af..9715476a55d6 100644
--- a/doc/source/development.rst
+++ b/doc/source/development.rst
@@ -108,13 +108,16 @@ Installing *sphinx*
.. code-block:: bash
- pip install sphinx
- pip install sphinx_rtd_theme
- pip install breathe
- pip install https://github.com/lepture/python-livereload/archive/master.zip
- pip install sphinx-autobuild
+ pip install -r doc/source/requirements.txt
-Further instructions on configuring advanced features can be found at `<http://read-the-docs.readthedocs.org/en/latest/install.html>`_.
+
+To update the Python dependencies:
+
+.. code-block:: bash
+
+ pip-compile --upgrade doc/source/requirements.in
+
+Sphinx reference: `<http://read-the-docs.readthedocs.org/en/latest/install.html>`_.
Live preview of docs
diff --git a/doc/source/getting_started.rst b/doc/source/getting_started.rst
index ee57c094458d..5f67a86f66c1 100644
--- a/doc/source/getting_started.rst
+++ b/doc/source/getting_started.rst
@@ -102,6 +102,9 @@ The following configuration options will also be defined as macros [#]_ in ``<cb
If you want to pass other custom configuration options, please refer to `<http://www.cmake.org/Wiki/CMake_Useful_Variables>`_.
+.. note::
+ When ``CMAKE_INTERPROCEDURAL_OPTIMIZATION`` is enabled, the generated static library (`libcbor.a`) should be used with an LTO-enabled linker downstream. On LLVM toolchains without bitcode embedding (`-fembed-bitcode`), the archive will contain LLVM IR only and linking without LTO `will not work <https://github.com/PJK/libcbor/issues/372>`_.
+
.. warning::
``CBOR_CUSTOM_ALLOC`` has been `removed <https://github.com/PJK/libcbor/pull/237>`_.
Custom allocators (historically a controlled by a build flag) are always enabled.
diff --git a/doc/source/index.rst b/doc/source/index.rst
index d3d62cf75c41..06ef1a059891 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -3,6 +3,8 @@ libcbor
Documentation for version |release|, updated on |today|.
+Git repo: https://github.com/PJK/libcbor
+
Overview
--------
*libcbor* is a C library for parsing and generating CBOR_, the general-purpose schema-less binary data format.
@@ -28,7 +30,7 @@ Contents
.. toctree::
getting_started
- using
+ tutorial
api
tests
standard_conformance
diff --git a/doc/source/requirements.in b/doc/source/requirements.in
new file mode 100644
index 000000000000..000ba6286d17
--- /dev/null
+++ b/doc/source/requirements.in
@@ -0,0 +1,5 @@
+sphinx
+sphinx_rtd_theme
+breathe
+livereload
+sphinx-autobuild
diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt
index 1b34e120b8b2..44b77ded4f36 100644
--- a/doc/source/requirements.txt
+++ b/doc/source/requirements.txt
@@ -1,47 +1,91 @@
+#
+# This file is autogenerated by pip-compile with Python 3.13
+# by the following command:
+#
+# pip-compile doc/source/requirements.in
+#
alabaster==1.0.0
-anyio==4.8.0
+ # via sphinx
+anyio==4.9.0
+ # via
+ # starlette
+ # watchfiles
babel==2.17.0
+ # via sphinx
breathe==4.36.0
-build==1.2.2.post1
+ # via -r doc/source/requirements.in
certifi==2025.1.31
+ # via requests
charset-normalizer==3.4.1
+ # via requests
click==8.1.8
+ # via uvicorn
colorama==0.4.6
+ # via sphinx-autobuild
docutils==0.21.2
+ # via
+ # sphinx
+ # sphinx-rtd-theme
h11==0.14.0
+ # via uvicorn
idna==3.10
+ # via
+ # anyio
+ # requests
imagesize==1.4.1
-importlib_metadata==8.6.1
-Jinja2==3.1.6
-livereload @ https://github.com/lepture/python-livereload/archive/master.zip#sha256=95371213cf9107242808ea6e1353b524d7c38d96e299604e651e43271263352c
-MarkupSafe==3.0.2
-packaging==24.2
-pip-tools==7.4.1
-Pygments==2.19.1
-pyparsing==3.2.1
-pyproject_hooks==1.2.0
-pytz==2025.1
+ # via sphinx
+jinja2==3.1.6
+ # via sphinx
+livereload==2.7.1
+ # via -r doc/source/requirements.in
+markupsafe==3.0.2
+ # via jinja2
+packaging==25.0
+ # via sphinx
+pygments==2.19.1
+ # via sphinx
requests==2.32.3
+ # via sphinx
roman-numerals-py==3.1.0
-setuptools==75.8.2
-six==1.17.0
+ # via sphinx
sniffio==1.3.1
+ # via anyio
snowballstemmer==2.2.0
-Sphinx==8.2.3
+ # via sphinx
+sphinx==8.2.3
+ # via
+ # -r doc/source/requirements.in
+ # breathe
+ # sphinx-autobuild
+ # sphinx-rtd-theme
+ # sphinxcontrib-jquery
sphinx-autobuild==2024.10.3
+ # via -r doc/source/requirements.in
sphinx-rtd-theme==3.0.2
+ # via -r doc/source/requirements.in
sphinxcontrib-applehelp==2.0.0
+ # via sphinx
sphinxcontrib-devhelp==2.0.0
+ # via sphinx
sphinxcontrib-htmlhelp==2.1.0
+ # via sphinx
sphinxcontrib-jquery==4.1
+ # via sphinx-rtd-theme
sphinxcontrib-jsmath==1.0.1
+ # via sphinx
sphinxcontrib-qthelp==2.0.0
+ # via sphinx
sphinxcontrib-serializinghtml==2.0.0
-starlette==0.46.0
+ # via sphinx
+starlette==0.46.2
+ # via sphinx-autobuild
tornado==6.4.2
-urllib3==2.3.0
-uvicorn==0.34.0
-watchfiles==1.0.4
-websockets==15.0
-wheel==0.45.1
-zipp==3.21.0
+ # via livereload
+urllib3==2.4.0
+ # via requests
+uvicorn==0.34.2
+ # via sphinx-autobuild
+watchfiles==1.0.5
+ # via sphinx-autobuild
+websockets==15.0.1
+ # via sphinx-autobuild
diff --git a/doc/source/tutorial.rst b/doc/source/tutorial.rst
new file mode 100644
index 000000000000..81859ccb2192
--- /dev/null
+++ b/doc/source/tutorial.rst
@@ -0,0 +1,66 @@
+Tutorial
+===========================
+
+*libcbor* is a C library to encode, decode, and manipulate CBOR data. It is to CBOR to what `cJSON <https://github.com/DaveGamble/cJSON>`_ is to JSON. We assume you are familiar with the CBOR standard. If not, we recommend `cbor.io <http://cbor.io/>`_.
+
+
+Where to start
+--------------
+
+- Skim through the Crash course section below.
+- Examples of of how to read, write, manipulate, and translate data to and from JSON using *libcbor* are in the `examples directory <https://github.com/PJK/libcbor/tree/master/examples>`_.
+- The :doc:`API documentation <api>` is a complete reference of *libcbor*.
+
+
+Crash course
+----------------
+
+CBOR data objects are ``cbor_item_t``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. literalinclude:: ../../examples/crash_course.c
+ :language: C
+ :start-after: // Part 1: Begin
+ :end-before: // Part 1: End
+
+
+Objects can be serialized and deserialized
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. literalinclude:: ../../examples/crash_course.c
+ :language: C
+ :start-after: // Part 2: Begin
+ :end-before: // Part 2: End
+
+
+Reference counting
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. literalinclude:: ../../examples/crash_course.c
+ :language: C
+ :start-after: // Part 3: Begin
+ :end-before: // Part 3: End
+
+
+Moving intermediate values
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. literalinclude:: ../../examples/crash_course.c
+ :language: C
+ :start-after: // Part 4: Begin
+ :end-before: // Part 4: End
+
+
+Ownership
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. literalinclude:: ../../examples/crash_course.c
+ :language: C
+ :start-after: // Part 5: Begin
+ :end-before: // Part 5: End
+
+
+Streaming IO
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+See https://github.com/PJK/libcbor/blob/master/examples/streaming_array.c, https://github.com/PJK/libcbor/blob/master/examples/streaming_parser.c \ No newline at end of file
diff --git a/doc/source/using.rst b/doc/source/using.rst
deleted file mode 100644
index c6688bbad7bd..000000000000
--- a/doc/source/using.rst
+++ /dev/null
@@ -1,174 +0,0 @@
-Usage & preliminaries
-=======================
-
-Version information
---------------------
-
-libcbor exports its version using three self-explanatory macros:
-
- - ``CBOR_MAJOR_VERSION``
- - ``CBOR_MINOR_VERSION``
- - ``CBOR_PATCH_VERSION``
-
-The ``CBOR_VERSION`` is a string concatenating these three identifiers into one (e.g. ``0.2.0``).
-
-In order to simplify version comparisons, the version is also exported as
-
-.. code-block:: c
-
- #define CBOR_HEX_VERSION ((CBOR_MAJOR_VERSION << 16) | (CBOR_MINOR_VERSION << 8) | CBOR_PATCH_VERSION)
-
-Since macros are difficult to work with through FFIs, the same information is also available through three ``uint8_t`` constants,
-namely
-
- - ``cbor_major_version``
- - ``cbor_minor_version``
- - ``cbor_patch_version``
-
-
-Headers to include
----------------------
-
-The ``cbor.h`` header includes all the symbols. If, for any reason, you don't want to include all the exported symbols,
-feel free to use just some of the ``cbor/*.h`` headers:
-
- - ``cbor/arrays.h`` - :doc:`api/type_4_arrays`
- - ``cbor/bytestrings.h`` - :doc:`api/type_2_byte_strings`
- - ``cbor/callbacks.h`` - Callbacks used for :doc:`api/streaming_decoding`
- - ``cbor/common.h`` - Common utilities - always transitively included
- - ``cbor/data.h`` - Data types definitions - always transitively included
- - ``cbor/encoding.h`` - Streaming encoders for :doc:`api/streaming_encoding`
- - ``cbor/floats_ctrls.h`` - :doc:`api/type_7_floats_ctrls`
- - ``cbor/ints.h`` - :doc:`api/type_0_1_integers`
- - ``cbor/maps.h`` - :doc:`api/type_5_maps`
- - ``cbor/serialization.h`` - High level serialization such as :func:`cbor_serialize`
- - ``cbor/streaming.h`` - Home of :func:`cbor_stream_decode`
- - ``cbor/strings.h`` - :doc:`api/type_3_strings`
- - ``cbor/tags.h`` - :doc:`api/type_6_tags`
-
-
-Using libcbor
---------------
-
-If you want to get more familiar with CBOR, we recommend the `cbor.io <http://cbor.io/>`_ website. Once you get the grasp
-of what is it CBOR does, the examples (located in the ``examples`` directory) should give you a good feel of the API. The
-:doc:`API documentation <api>` should then provide with all the information you may need.
-
-
-**Creating and serializing items**
-
-.. code-block:: c
-
- #include "cbor.h"
- #include <stdio.h>
-
- int main(int argc, char * argv[])
- {
- /* Preallocate the map structure */
- cbor_item_t * root = cbor_new_definite_map(2);
- /* Add the content */
- cbor_map_add(root, (struct cbor_pair) {
- .key = cbor_move(cbor_build_string("Is CBOR awesome?")),
- .value = cbor_move(cbor_build_bool(true))
- });
- cbor_map_add(root, (struct cbor_pair) {
- .key = cbor_move(cbor_build_uint8(42)),
- .value = cbor_move(cbor_build_string("Is the answer"))
- });
- /* Output: `buffer_size` bytes of data in the `buffer` */
- unsigned char * buffer;
- size_t buffer_size;
- cbor_serialize_alloc(root, &buffer, &buffer_size);
-
- fwrite(buffer, 1, buffer_size, stdout);
- free(buffer);
-
- fflush(stdout);
- cbor_decref(&root);
- }
-
-
-**Reading serialized data**
-
-.. code-block:: c
-
- #include "cbor.h"
- #include <stdio.h>
-
- /*
- * Reads data from a file. Example usage:
- * $ ./examples/readfile examples/data/nested_array.cbor
- */
-
- int main(int argc, char * argv[])
- {
- FILE * f = fopen(argv[1], "rb");
- fseek(f, 0, SEEK_END);
- size_t length = (size_t)ftell(f);
- fseek(f, 0, SEEK_SET);
- unsigned char * buffer = malloc(length);
- fread(buffer, length, 1, f);
-
- /* Assuming `buffer` contains `info.st_size` bytes of input data */
- struct cbor_load_result result;
- cbor_item_t * item = cbor_load(buffer, length, &result);
- /* Pretty-print the result */
- cbor_describe(item, stdout);
- fflush(stdout);
- /* Deallocate the result */
- cbor_decref(&item);
-
- fclose(f);
- }
-
-
-**Using the streaming parser**
-
-.. code-block:: c
-
- #include "cbor.h"
- #include <stdio.h>
- #include <string.h>
-
- /*
- * Illustrates how one might skim through a map (which is assumed to have
- * string keys and values only), looking for the value of a specific key
- *
- * Use the examples/data/map.cbor input to test this.
- */
-
- const char * key = "a secret key";
- bool key_found = false;
-
- void find_string(void * _ctx, cbor_data buffer, size_t len)
- {
- if (key_found) {
- printf("Found the value: %*s\n", (int) len, buffer);
- key_found = false;
- } else if (len == strlen(key)) {
- key_found = (memcmp(key, buffer, len) == 0);
- }
- }
-
- int main(int argc, char * argv[])
- {
- FILE * f = fopen(argv[1], "rb");
- fseek(f, 0, SEEK_END);
- size_t length = (size_t)ftell(f);
- fseek(f, 0, SEEK_SET);
- unsigned char * buffer = malloc(length);
- fread(buffer, length, 1, f);
-
- struct cbor_callbacks callbacks = cbor_empty_callbacks;
- struct cbor_decoder_result decode_result;
- size_t bytes_read = 0;
- callbacks.string = find_string;
- while (bytes_read < length) {
- decode_result = cbor_stream_decode(buffer + bytes_read,
- length - bytes_read,
- &callbacks, NULL);
- bytes_read += decode_result.read;
- }
-
- fclose(f);
- }
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 5ef9162c12d1..f0d9e9749963 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -16,6 +16,12 @@ target_link_libraries(sort cbor)
add_executable(hello hello.c)
target_link_libraries(hello cbor)
+add_executable(cbor_sequence cbor_sequence.c)
+target_link_libraries(cbor_sequence cbor)
+
+add_executable(crash_course crash_course.c)
+target_link_libraries(crash_course cbor)
+
find_package(CJSON)
if(CJSON_FOUND)
diff --git a/examples/bazel/third_party/libcbor/cbor/configuration.h b/examples/bazel/third_party/libcbor/cbor/configuration.h
index 070b54d9c2ae..c0122ff9fcfc 100644
--- a/examples/bazel/third_party/libcbor/cbor/configuration.h
+++ b/examples/bazel/third_party/libcbor/cbor/configuration.h
@@ -2,7 +2,7 @@
#define LIBCBOR_CONFIGURATION_H
#define CBOR_MAJOR_VERSION 0
-#define CBOR_MINOR_VERSION 12
+#define CBOR_MINOR_VERSION 13
#define CBOR_PATCH_VERSION 0
#define CBOR_BUFFER_GROWTH 2
diff --git a/examples/cbor_sequence.c b/examples/cbor_sequence.c
new file mode 100644
index 000000000000..02c43185ff58
--- /dev/null
+++ b/examples/cbor_sequence.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
+ *
+ * libcbor is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "cbor.h"
+
+void write_cbor_sequence(const char* filename) {
+ FILE* file = fopen(filename, "wb");
+ if (!file) {
+ fprintf(stderr, "Error: Could not open file %s for writing\n", filename);
+ return;
+ }
+
+ // Create example CBOR items
+ cbor_item_t* int_item = cbor_build_uint32(42);
+ cbor_item_t* string_item = cbor_build_string("Hello, CBOR!");
+ cbor_item_t* array_item = cbor_new_definite_array(2);
+ assert(cbor_array_push(array_item, cbor_build_uint8(1)));
+ assert(cbor_array_push(array_item, cbor_build_uint8(2)));
+
+ // Serialize and write items to the file
+ unsigned char* buffer;
+ size_t buffer_size;
+
+ cbor_serialize_alloc(int_item, &buffer, &buffer_size);
+ fwrite(buffer, 1, buffer_size, file);
+ free(buffer);
+ cbor_decref(&int_item);
+
+ cbor_serialize_alloc(string_item, &buffer, &buffer_size);
+ fwrite(buffer, 1, buffer_size, file);
+ free(buffer);
+ cbor_decref(&string_item);
+
+ cbor_serialize_alloc(array_item, &buffer, &buffer_size);
+ fwrite(buffer, 1, buffer_size, file);
+ free(buffer);
+ cbor_decref(&array_item);
+
+ fclose(file);
+ printf("CBOR sequence written to %s\n", filename);
+}
+
+void read_cbor_sequence(const char* filename) {
+ FILE* file = fopen(filename, "rb");
+ if (!file) {
+ fprintf(stderr, "Error: Could not open file %s\n", filename);
+ return;
+ }
+
+ fseek(file, 0, SEEK_END);
+ size_t file_size = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ unsigned char* buffer = malloc(file_size);
+ if (!buffer) {
+ fprintf(stderr, "Error: Could not allocate memory\n");
+ fclose(file);
+ return;
+ }
+
+ fread(buffer, 1, file_size, file);
+ fclose(file);
+
+ struct cbor_load_result result;
+ size_t offset = 0;
+
+ while (offset < file_size) {
+ cbor_item_t* item = cbor_load(buffer + offset, file_size - offset, &result);
+ if (result.error.code != CBOR_ERR_NONE) {
+ fprintf(stderr, "Error: Failed to parse CBOR item at offset %zu\n",
+ offset);
+ break;
+ }
+
+ cbor_describe(item, stdout);
+ printf("\n");
+
+ offset += result.read;
+ cbor_decref(&item);
+ }
+
+ free(buffer);
+}
+
+int main(int argc, char* argv[]) {
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <r|w> <file>\n", argv[0]);
+ return 1;
+ }
+
+ if (strcmp(argv[1], "w") == 0) {
+ write_cbor_sequence(argv[2]);
+ } else if (strcmp(argv[1], "r") == 0) {
+ read_cbor_sequence(argv[2]);
+ } else {
+ fprintf(stderr,
+ "Error: First argument must be 'r' (read) or 'w' (write)\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/examples/crash_course.c b/examples/crash_course.c
new file mode 100644
index 000000000000..4bd9f9379d26
--- /dev/null
+++ b/examples/crash_course.c
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
+ *
+ * libcbor is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include "cbor.h"
+
+// Part 1: Begin
+void item_examples() {
+ // A cbor_item_t can contain any CBOR data type
+ cbor_item_t* float_item = cbor_build_float4(3.14f);
+ cbor_item_t* string_item = cbor_build_string("Hello World!");
+ cbor_item_t* array_item = cbor_new_indefinite_array();
+
+ // They can be inspected
+ assert(cbor_is_float(float_item));
+ assert(cbor_typeof(string_item) == CBOR_TYPE_STRING);
+ assert(cbor_array_is_indefinite(array_item));
+ assert(cbor_array_size(array_item) == 0);
+
+ // The data can be accessed
+ assert(cbor_float_get_float4(float_item) == 3.14f);
+ assert(memcmp(cbor_string_handle(string_item), "Hello World!",
+ cbor_string_length(string_item)) == 0);
+
+ // And they can be modified
+ assert(cbor_array_push(array_item, float_item));
+ assert(cbor_array_push(array_item, string_item));
+ assert(cbor_array_size(array_item) == 2);
+
+ // At the end of their lifetime, items must be freed
+ cbor_decref(&float_item);
+ cbor_decref(&string_item);
+ cbor_decref(&array_item);
+}
+// Part 1: End
+
+// Part 2: Begin
+void encode_decode() {
+ cbor_item_t* item = cbor_build_uint8(42);
+
+ // Serialize the item to a buffer (it will be allocated by libcbor)
+ unsigned char* buffer;
+ size_t buffer_size;
+ cbor_serialize_alloc(item, &buffer, &buffer_size);
+ assert(buffer_size == 2);
+ assert(buffer[0] == 0x18); // Encoding byte for uint8
+ assert(buffer[1] == 42); // The value itself
+
+ // And deserialize bytes back to an item
+ struct cbor_load_result result;
+ cbor_item_t* decoded_item = cbor_load(buffer, buffer_size, &result);
+ assert(result.error.code == CBOR_ERR_NONE);
+ assert(cbor_isa_uint(decoded_item));
+ assert(cbor_get_uint8(decoded_item) == 42);
+
+ // Free the allocated buffer and items
+ free(buffer);
+ cbor_decref(&decoded_item);
+ cbor_decref(&item);
+}
+// Part 2: End
+
+// Part 3: Begin
+void reference_counting() {
+ // cbor_item_t is a reference counted pointer under the hood
+ cbor_item_t* item = cbor_build_uint8(42);
+
+ // Reference count starts at 1
+ assert(cbor_refcount(item) == 1);
+
+ // Most operations have reference semantics
+ cbor_item_t* array_item = cbor_new_definite_array(1);
+ assert(cbor_array_push(array_item, item));
+ assert(cbor_refcount(item) == 2); // item and array_item reference it
+ cbor_item_t* first_array_element = cbor_array_get(array_item, 0);
+ assert(first_array_element == item); // same item under the hood
+ assert(cbor_refcount(item) ==
+ 3); // and now first_array_element also points to it
+
+ // To release the reference, use cbor_decref
+ cbor_decref(&first_array_element);
+
+ // When reference count reaches 0, the item is freed
+ assert(cbor_refcount(array_item) == 1);
+ cbor_decref(&array_item);
+ assert(array_item == NULL);
+ assert(cbor_refcount(item) == 1);
+
+ // Be careful, loops leak memory!
+
+ // Deep copy copies the whole item tree
+ cbor_item_t* item_copy = cbor_copy(item);
+ assert(cbor_refcount(item) == 1);
+ assert(cbor_refcount(item_copy) == 1);
+ assert(item_copy != item);
+ cbor_decref(&item);
+ cbor_decref(&item_copy);
+}
+// Part 3: End
+
+// Part 4: Begin
+void moving_values() {
+ {
+ // Move the "42" into an array.
+ cbor_item_t* array_item = cbor_new_definite_array(1);
+ // The line below leaks memory!
+ assert(cbor_array_push(array_item, cbor_build_uint8(42)));
+ cbor_item_t* first_array_element = cbor_array_get(array_item, 0);
+ assert(cbor_refcount(first_array_element) == 3); // Should be 2!
+ cbor_decref(&first_array_element);
+ cbor_decref(&array_item);
+ assert(cbor_refcount(first_array_element) == 1); // Shouldn't exist!
+ // Clean up
+ cbor_decref(&first_array_element);
+ }
+
+ {
+ // A correct way to move values is to decref them in the caller scope.
+ cbor_item_t* array_item = cbor_new_definite_array(1);
+ cbor_item_t* item = cbor_build_uint8(42);
+ assert(cbor_array_push(array_item, item));
+ assert(cbor_refcount(item) == 2);
+ // "Give up" the item
+ cbor_decref(&item);
+ cbor_decref(&array_item);
+ // item is a dangling pointer at this point
+ }
+
+ {
+ // cbor_move avoids the need to decref and the dangling pointer
+ cbor_item_t* array_item = cbor_new_definite_array(1);
+ assert(cbor_array_push(array_item, cbor_move(cbor_build_uint8(42))));
+ cbor_item_t* first_array_element = cbor_array_get(array_item, 0);
+ assert(cbor_refcount(first_array_element) == 2);
+ cbor_decref(&first_array_element);
+ cbor_decref(&array_item);
+ }
+}
+// Part 4: End
+
+// Part 5: Begin
+// Refcount can be managed in conjunction with ownership
+static cbor_item_t* global_item = NULL;
+
+// This function takes shared ownership of the item
+void borrow_item(cbor_item_t* item) {
+ global_item = item;
+ // Mark the extra reference
+ cbor_incref(item);
+}
+
+void return_item() {
+ cbor_decref(&global_item);
+ global_item = NULL;
+}
+
+void reference_ownership() {
+ cbor_item_t* item = cbor_build_uint8(42);
+
+ // Lend the item
+ borrow_item(item);
+ assert(cbor_refcount(item) == 2);
+ cbor_decref(&item);
+
+ // Release the shared ownership. return_item will deallocate the item.
+ return_item();
+}
+// Part 5: End
+
+int main(void) {
+ item_examples();
+ encode_decode();
+ reference_counting();
+ moving_values();
+ reference_ownership();
+ return 0;
+}
diff --git a/misc/asan_suppressions.osx.supp b/misc/asan_suppressions.osx.supp
new file mode 100644
index 000000000000..5503d9412a53
--- /dev/null
+++ b/misc/asan_suppressions.osx.supp
@@ -0,0 +1,3 @@
+leak:initializeNonMetaClass
+# via _cmocka_run_group_tests
+leak:tlv_get_addr \ No newline at end of file
diff --git a/release.sh b/release.sh
index e16bcbc99b31..790c650de4f0 100755
--- a/release.sh
+++ b/release.sh
@@ -80,7 +80,6 @@ git checkout master
git pull
prompt "Will proceed to tag the release with $TAG_NAME."
-git commit -a -m "Release $TAG_NAME"
git tag "$TAG_NAME"
git push --set-upstream origin $(git rev-parse --abbrev-ref HEAD)
git push --tags
diff --git a/src/cbor.c b/src/cbor.c
index 819ff6077c34..93a3709f5423 100644
--- a/src/cbor.c
+++ b/src/cbor.c
@@ -5,6 +5,9 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
+#include <stdbool.h>
+#include <string.h>
+
#include "cbor.h"
#include "cbor/internal/builder_callbacks.h"
#include "cbor/internal/loaders.h"
@@ -115,6 +118,9 @@ error:
}
static cbor_item_t* _cbor_copy_int(cbor_item_t* item, bool negative) {
+ CBOR_ASSERT(cbor_isa_uint(item) || cbor_isa_negint(item));
+ CBOR_ASSERT(cbor_int_get_width(item) >= CBOR_INT_8 &&
+ cbor_int_get_width(item) <= CBOR_INT_64);
cbor_item_t* res = NULL;
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
@@ -137,6 +143,9 @@ static cbor_item_t* _cbor_copy_int(cbor_item_t* item, bool negative) {
}
static cbor_item_t* _cbor_copy_float_ctrl(cbor_item_t* item) {
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_float_get_width(item) >= CBOR_FLOAT_0 &&
+ cbor_float_get_width(item) <= CBOR_FLOAT_64);
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
return cbor_build_ctrl(cbor_ctrl_value(item));
@@ -146,13 +155,14 @@ static cbor_item_t* _cbor_copy_float_ctrl(cbor_item_t* item) {
return cbor_build_float4(cbor_float_get_float4(item));
case CBOR_FLOAT_64:
return cbor_build_float8(cbor_float_get_float8(item));
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return NULL;
+ return NULL; // LCOV_EXCL_START
}
}
cbor_item_t* cbor_copy(cbor_item_t* item) {
+ CBOR_ASSERT_VALID_TYPE(cbor_typeof(item));
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT:
return _cbor_copy_int(item, false);
@@ -283,9 +293,138 @@ cbor_item_t* cbor_copy(cbor_item_t* item) {
}
case CBOR_TYPE_FLOAT_CTRL:
return _cbor_copy_float_ctrl(item);
- default:
+ default: // LCOV_EXCL_START
+ _CBOR_UNREACHABLE;
+ return NULL; // LCOV_EXCL_STOP
+ }
+}
+
+cbor_item_t* cbor_copy_definite(cbor_item_t* item) {
+ CBOR_ASSERT_VALID_TYPE(cbor_typeof(item));
+ switch (cbor_typeof(item)) {
+ case CBOR_TYPE_UINT:
+ case CBOR_TYPE_NEGINT:
+ return cbor_copy(item);
+ case CBOR_TYPE_BYTESTRING:
+ if (cbor_bytestring_is_definite(item)) {
+ return cbor_copy(item);
+ } else {
+ size_t total_length = 0;
+ for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
+ total_length +=
+ cbor_bytestring_length(cbor_bytestring_chunks_handle(item)[i]);
+ }
+
+ unsigned char* combined_data = _cbor_malloc(total_length);
+ if (combined_data == NULL) {
+ return NULL;
+ }
+
+ size_t offset = 0;
+ for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
+ cbor_item_t* chunk = cbor_bytestring_chunks_handle(item)[i];
+ memcpy(combined_data + offset, cbor_bytestring_handle(chunk),
+ cbor_bytestring_length(chunk));
+ offset += cbor_bytestring_length(chunk);
+ }
+
+ cbor_item_t* res = cbor_new_definite_bytestring();
+ cbor_bytestring_set_handle(res, combined_data, total_length);
+ return res;
+ }
+ case CBOR_TYPE_STRING:
+ if (cbor_string_is_definite(item)) {
+ return cbor_copy(item);
+ } else {
+ size_t total_length = 0;
+ for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
+ total_length +=
+ cbor_string_length(cbor_string_chunks_handle(item)[i]);
+ }
+
+ unsigned char* combined_data = _cbor_malloc(total_length);
+ if (combined_data == NULL) {
+ return NULL;
+ }
+
+ size_t offset = 0;
+ for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
+ cbor_item_t* chunk = cbor_string_chunks_handle(item)[i];
+ memcpy(combined_data + offset, cbor_string_handle(chunk),
+ cbor_string_length(chunk));
+ offset += cbor_string_length(chunk);
+ }
+
+ cbor_item_t* res = cbor_new_definite_string();
+ cbor_string_set_handle(res, combined_data, total_length);
+ return res;
+ }
+ case CBOR_TYPE_ARRAY: {
+ cbor_item_t* res = cbor_new_definite_array(cbor_array_size(item));
+ if (res == NULL) {
+ return NULL;
+ }
+
+ for (size_t i = 0; i < cbor_array_size(item); i++) {
+ cbor_item_t* entry_copy =
+ cbor_copy_definite(cbor_array_handle(item)[i]);
+ if (entry_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ // Cannot fail since we have a definite array preallocated
+ // cppcheck-suppress syntaxError
+ const bool item_pushed _CBOR_UNUSED = cbor_array_push(res, entry_copy);
+ CBOR_ASSERT(item_pushed);
+ cbor_decref(&entry_copy);
+ }
+ return res;
+ }
+ case CBOR_TYPE_MAP: {
+ cbor_item_t* res;
+ res = cbor_new_definite_map(cbor_map_size(item));
+ if (res == NULL) {
+ return NULL;
+ }
+
+ struct cbor_pair* it = cbor_map_handle(item);
+ for (size_t i = 0; i < cbor_map_size(item); i++) {
+ cbor_item_t* key_copy = cbor_copy_definite(it[i].key);
+ if (key_copy == NULL) {
+ cbor_decref(&res);
+ return NULL;
+ }
+ cbor_item_t* value_copy = cbor_copy_definite(it[i].value);
+ if (value_copy == NULL) {
+ cbor_decref(&res);
+ cbor_decref(&key_copy);
+ return NULL;
+ }
+ // Cannot fail since we have a definite map preallocated
+ // cppcheck-suppress syntaxError
+ const bool item_added _CBOR_UNUSED = cbor_map_add(
+ res, (struct cbor_pair){.key = key_copy, .value = value_copy});
+ CBOR_ASSERT(item_added);
+ cbor_decref(&key_copy);
+ cbor_decref(&value_copy);
+ }
+ return res;
+ }
+ case CBOR_TYPE_TAG: {
+ cbor_item_t* item_copy =
+ cbor_copy_definite(cbor_move(cbor_tag_item(item)));
+ if (item_copy == NULL) {
+ return NULL;
+ }
+ cbor_item_t* tag = cbor_build_tag(cbor_tag_value(item), item_copy);
+ cbor_decref(&item_copy);
+ return tag;
+ }
+ case CBOR_TYPE_FLOAT_CTRL:
+ return cbor_copy(item);
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return NULL;
+ return NULL; // LCOV_EXCL_STOP
}
}
@@ -309,6 +448,8 @@ static void _cbor_type_marquee(FILE* out, char* label, int indent) {
}
static void _cbor_nested_describe(cbor_item_t* item, FILE* out, int indent) {
+ CBOR_ASSERT(cbor_typeof(item) >= CBOR_TYPE_UINT &&
+ cbor_typeof(item) <= CBOR_TYPE_FLOAT_CTRL);
const int indent_offset = 4;
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT: {
diff --git a/src/cbor.h b/src/cbor.h
index 46ef8f267ac9..b2bb9771d13e 100644
--- a/src/cbor.h
+++ b/src/cbor.h
@@ -61,6 +61,17 @@ _CBOR_NODISCARD CBOR_EXPORT cbor_item_t* cbor_load(
*/
_CBOR_NODISCARD CBOR_EXPORT cbor_item_t* cbor_copy(cbor_item_t* item);
+/** Copy the item with all items converted to definite length equivalents
+ *
+ * Deep copy semantics follow #cbor_copy
+ *
+ * @param item item to copy
+ * @return Reference to the new item. The item's reference count is initialized
+ * to one.
+ * @return `NULL` if memory allocation fails
+ */
+_CBOR_NODISCARD CBOR_EXPORT cbor_item_t* cbor_copy_definite(cbor_item_t* item);
+
#if CBOR_PRETTY_PRINTER
#include <stdio.h>
diff --git a/src/cbor/arrays.c b/src/cbor/arrays.c
index 174c97e9a61e..5433037cfdb8 100644
--- a/src/cbor/arrays.c
+++ b/src/cbor/arrays.c
@@ -5,8 +5,9 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
+#include <stdbool.h>
+
#include "arrays.h"
-#include <string.h>
#include "internal/memory_utils.h"
size_t cbor_array_size(const cbor_item_t* item) {
diff --git a/src/cbor/arrays.h b/src/cbor/arrays.h
index db19e59d0624..891061ef765a 100644
--- a/src/cbor/arrays.h
+++ b/src/cbor/arrays.h
@@ -49,7 +49,8 @@ CBOR_EXPORT cbor_item_t* cbor_array_get(const cbor_item_t* item, size_t index);
* returned. Creating arrays with holes is not possible.
*
* @param item An array
- * @param value The item to assign
+ * @param value The item to assign. Its reference count will be increased by
+ * one.
* @param index The index (zero-based)
* @return `true` on success, `false` on allocation failure.
*/
diff --git a/src/cbor/common.c b/src/cbor/common.c
index 704dd0c3205d..1931b572fb32 100644
--- a/src/cbor/common.c
+++ b/src/cbor/common.c
@@ -19,56 +19,62 @@
bool _cbor_enable_assert = true;
#endif
+cbor_type cbor_typeof(const cbor_item_t* item) {
+ CBOR_ASSERT(item != NULL);
+ CBOR_ASSERT_VALID_TYPE(item->type);
+ return item->type;
+}
+
bool cbor_isa_uint(const cbor_item_t* item) {
- return item->type == CBOR_TYPE_UINT;
+ return cbor_typeof(item) == CBOR_TYPE_UINT;
}
bool cbor_isa_negint(const cbor_item_t* item) {
- return item->type == CBOR_TYPE_NEGINT;
+ return cbor_typeof(item) == CBOR_TYPE_NEGINT;
}
bool cbor_isa_bytestring(const cbor_item_t* item) {
- return item->type == CBOR_TYPE_BYTESTRING;
+ return cbor_typeof(item) == CBOR_TYPE_BYTESTRING;
}
bool cbor_isa_string(const cbor_item_t* item) {
- return item->type == CBOR_TYPE_STRING;
+ return cbor_typeof(item) == CBOR_TYPE_STRING;
}
bool cbor_isa_array(const cbor_item_t* item) {
- return item->type == CBOR_TYPE_ARRAY;
+ return cbor_typeof(item) == CBOR_TYPE_ARRAY;
}
bool cbor_isa_map(const cbor_item_t* item) {
- return item->type == CBOR_TYPE_MAP;
+ return cbor_typeof(item) == CBOR_TYPE_MAP;
}
bool cbor_isa_tag(const cbor_item_t* item) {
- return item->type == CBOR_TYPE_TAG;
+ return cbor_typeof(item) == CBOR_TYPE_TAG;
}
bool cbor_isa_float_ctrl(const cbor_item_t* item) {
- return item->type == CBOR_TYPE_FLOAT_CTRL;
+ return cbor_typeof(item) == CBOR_TYPE_FLOAT_CTRL;
}
-cbor_type cbor_typeof(const cbor_item_t* item) { return item->type; }
-
bool cbor_is_int(const cbor_item_t* item) {
return cbor_isa_uint(item) || cbor_isa_negint(item);
}
bool cbor_is_bool(const cbor_item_t* item) {
- return cbor_isa_float_ctrl(item) &&
+ return cbor_isa_float_ctrl(item) && cbor_float_ctrl_is_ctrl(item) &&
(cbor_ctrl_value(item) == CBOR_CTRL_FALSE ||
cbor_ctrl_value(item) == CBOR_CTRL_TRUE);
}
bool cbor_is_null(const cbor_item_t* item) {
- return cbor_isa_float_ctrl(item) && cbor_ctrl_value(item) == CBOR_CTRL_NULL;
+ return cbor_isa_float_ctrl(item) && cbor_float_ctrl_is_ctrl(item) &&
+ cbor_ctrl_value(item) == CBOR_CTRL_NULL;
}
bool cbor_is_undef(const cbor_item_t* item) {
- return cbor_isa_float_ctrl(item) && cbor_ctrl_value(item) == CBOR_CTRL_UNDEF;
+ return cbor_isa_float_ctrl(item) && cbor_float_ctrl_is_ctrl(item) &&
+ cbor_ctrl_value(item) == CBOR_CTRL_UNDEF;
}
bool cbor_is_float(const cbor_item_t* item) {
diff --git a/src/cbor/common.h b/src/cbor/common.h
index 89968db95442..d16002d9b651 100644
--- a/src/cbor/common.h
+++ b/src/cbor/common.h
@@ -77,14 +77,25 @@ extern bool _cbor_enable_assert;
} while (0)
#endif
+#define CBOR_ASSERT_VALID_TYPE(item_type) \
+ CBOR_ASSERT(item_type >= CBOR_TYPE_UINT && item_type <= CBOR_TYPE_FLOAT_CTRL);
+
#define _CBOR_TO_STR_(x) #x
#define _CBOR_TO_STR(x) _CBOR_TO_STR_(x) /* enables proper double expansion */
+#ifdef CBOR_HAS_NODISCARD_ATTRIBUTE
+#define CBOR_NODISCARD [[nodiscard]]
+#else
+#define CBOR_NODISCARD
+#endif
+
#ifdef __GNUC__
#define _CBOR_UNUSED __attribute__((__unused__))
-// TODO(https://github.com/PJK/libcbor/issues/247): Prefer [[nodiscard]] if
-// available
+// Fall back to __attribute__((warn_unused_result)) if we don't have
+// [[nodiscard]]
+#ifndef CBOR_HAS_NODISCARD_ATTRIBUTE
#define _CBOR_NODISCARD __attribute__((warn_unused_result))
+#endif
#elif defined(_MSC_VER)
#define _CBOR_UNUSED __pragma(warning(suppress : 4100 4101))
#define _CBOR_NODISCARD
@@ -115,7 +126,8 @@ CBOR_EXPORT extern _cbor_free_t _cbor_free;
} \
} while (0)
-// Macro to short-circuit builders when memory allocation of nested data fails
+// Macro to short-circuit builders when memory allocation of nested data
+// fails
#define _CBOR_DEPENDENT_NOTNULL(cbor_item, pointer) \
do { \
if (pointer == NULL) { \
@@ -126,18 +138,21 @@ CBOR_EXPORT extern _cbor_free_t _cbor_free;
/** Sets the memory management routines to use.
*
- * By default, libcbor will use the standard library `malloc`, `realloc`, and
- * `free`.
+ * By default, libcbor will use the standard library `malloc`, `realloc`,
+ * and `free`.
*
* \rst
- * .. warning:: This function modifies the global state and should therefore be
- * used accordingly. Changing the memory handlers while allocated items exist
- * will result in a ``free``/``malloc`` mismatch. This function is not thread
- * safe with respect to both itself and all the other *libcbor* functions that
- * work with the heap.
+ * .. warning::
+ * This function modifies the global state and should
+ * therefore be used accordingly. Changing the memory handlers while
+ * allocated items exist will result in a ``free``/``malloc`` mismatch.
+ * This function is not thread safe with respect to both itself and all
+ * the other *libcbor* functions that work with the heap.
+ *
+ * .. note::
+ * `realloc` implementation must correctly support `NULL`
+ * reallocation (see e.g. http://en.cppreference.com/w/c/memory/realloc)
*
- * .. note:: `realloc` implementation must correctly support `NULL` reallocation
- * (see e.g. http://en.cppreference.com/w/c/memory/realloc)
* \endrst
*
* @param custom_malloc malloc implementation
@@ -247,8 +262,9 @@ CBOR_EXPORT bool cbor_is_bool(const cbor_item_t* item);
/** Does this item represent `null`
*
* \rst
- * .. warning:: This is in no way related to the value of the pointer. Passing a
- * null pointer will most likely result in a crash.
+ * .. warning::
+ * This is in no way related to the value of the pointer.
+ * Passing a null pointer will most likely result in a crash.
* \endrst
*
* @param item the item
@@ -260,8 +276,8 @@ CBOR_EXPORT bool cbor_is_null(const cbor_item_t* item);
/** Does this item represent `undefined`
*
* \rst
- * .. warning:: Care must be taken to distinguish nulls and undefined values in
- * C.
+ * .. warning::
+ * Care must be taken to distinguish nulls and undefined values in C.
* \endrst
*
* @param item the item
@@ -278,8 +294,8 @@ CBOR_EXPORT bool cbor_is_undef(const cbor_item_t* item);
/** Increases the item's reference count by one
*
- * Constant complexity; items referring to this one or items being referred to
- * are not updated.
+ * Constant complexity; items referring to this one or items being
+ * referred to are not updated.
*
* This function can be used to extend reference counting to client code.
*
@@ -288,20 +304,22 @@ CBOR_EXPORT bool cbor_is_undef(const cbor_item_t* item);
*/
CBOR_EXPORT cbor_item_t* cbor_incref(cbor_item_t* item);
-/** Decreases the item's reference count by one, deallocating the item if needed
+/** Decreases the item's reference count by one, deallocating the item if
+ * needed
*
- * In case the item is deallocated, the reference count of all items this item
- * references will also be #cbor_decref 'ed recursively.
+ * In case the item is deallocated, the reference count of all items this
+ * item references will also be #cbor_decref 'ed recursively.
*
* @param item Reference to an item. Will be set to `NULL` if deallocated
*/
CBOR_EXPORT void cbor_decref(cbor_item_t** item);
-/** Decreases the item's reference count by one, deallocating the item if needed
- *
- * Convenience wrapper for #cbor_decref when its set-to-null behavior is not
+/** Decreases the item's reference count by one, deallocating the item if
* needed
*
+ * Convenience wrapper for #cbor_decref when its set-to-null behavior is
+ * not needed
+ *
* @param item Reference to an item
*/
CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t* item);
@@ -309,7 +327,8 @@ CBOR_EXPORT void cbor_intermediate_decref(cbor_item_t* item);
/** Get the item's reference count
*
* \rst
- * .. warning:: This does *not* account for transitive references.
+ * .. warning::
+ * This does *not* account for transitive references.
* \endrst
*
* @todo Add some inline examples for reference counting
@@ -322,14 +341,15 @@ CBOR_EXPORT size_t cbor_refcount(const cbor_item_t* item);
/** Provides CPP-like move construct
*
- * Decreases the reference count by one, but does not deallocate the item even
- * if its refcount reaches zero. This is useful for passing intermediate values
- * to functions that increase reference count. Should only be used with
- * functions that `incref` their arguments.
+ * Decreases the reference count by one, but does not deallocate the item
+ * even if its refcount reaches zero. This is useful for passing
+ * intermediate values to functions that increase reference count. Should
+ * only be used with functions that `incref` their arguments.
*
* \rst
- * .. warning:: If the item is moved without correctly increasing the reference
- * count afterwards, the memory will be leaked.
+ * .. warning::
+ * If the item is moved without correctly increasing the
+ * reference count afterwards, the memory will be leaked.
* \endrst
*
* @param item Reference to an item
diff --git a/src/cbor/floats_ctrls.c b/src/cbor/floats_ctrls.c
index 705e78cb20ca..cae4abee2186 100644
--- a/src/cbor/floats_ctrls.c
+++ b/src/cbor/floats_ctrls.c
@@ -44,7 +44,9 @@ double cbor_float_get_float8(const cbor_item_t* item) {
}
double cbor_float_get_float(const cbor_item_t* item) {
- CBOR_ASSERT(cbor_is_float(item));
+ CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_float_get_width(item) >= CBOR_FLOAT_0 &&
+ cbor_float_get_width(item) <= CBOR_FLOAT_64);
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
return NAN;
@@ -54,9 +56,9 @@ double cbor_float_get_float(const cbor_item_t* item) {
return cbor_float_get_float4(item);
case CBOR_FLOAT_64:
return cbor_float_get_float8(item);
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
}
diff --git a/src/cbor/floats_ctrls.h b/src/cbor/floats_ctrls.h
index 6a7925346951..1c1d0ba5b494 100644
--- a/src/cbor/floats_ctrls.h
+++ b/src/cbor/floats_ctrls.h
@@ -152,8 +152,9 @@ _CBOR_NODISCARD CBOR_EXPORT cbor_item_t* cbor_build_bool(bool value);
/** Assign a control value
*
* \rst
- * .. warning:: It is possible to produce an invalid CBOR value by assigning a
- * invalid value using this mechanism. Please consult the standard before use.
+ * .. warning::
+ * It is possible to produce an invalid CBOR value by assigning an invalid
+ * value using this mechanism. Please consult the standard before use.
* \endrst
*
* @param item A ctrl item
diff --git a/src/cbor/ints.c b/src/cbor/ints.c
index 272d82550c48..140d688f8215 100644
--- a/src/cbor/ints.c
+++ b/src/cbor/ints.c
@@ -38,7 +38,8 @@ uint64_t cbor_get_uint64(const cbor_item_t* item) {
uint64_t cbor_get_int(const cbor_item_t* item) {
CBOR_ASSERT(cbor_is_int(item));
- // cppcheck-suppress missingReturn
+ CBOR_ASSERT(cbor_int_get_width(item) >= CBOR_INT_8 &&
+ cbor_int_get_width(item) <= CBOR_INT_64);
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
return cbor_get_uint8(item);
@@ -48,9 +49,9 @@ uint64_t cbor_get_int(const cbor_item_t* item) {
return cbor_get_uint32(item);
case CBOR_INT_64:
return cbor_get_uint64(item);
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
}
diff --git a/src/cbor/serialization.c b/src/cbor/serialization.c
index dbfc8c371382..b0f681c0c383 100644
--- a/src/cbor/serialization.c
+++ b/src/cbor/serialization.c
@@ -19,6 +19,7 @@
size_t cbor_serialize(const cbor_item_t* item, unsigned char* buffer,
size_t buffer_size) {
+ CBOR_ASSERT_VALID_TYPE(cbor_typeof(item));
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT:
return cbor_serialize_uint(item, buffer, buffer_size);
@@ -36,9 +37,9 @@ size_t cbor_serialize(const cbor_item_t* item, unsigned char* buffer,
return cbor_serialize_tag(item, buffer, buffer_size);
case CBOR_TYPE_FLOAT_CTRL:
return cbor_serialize_float_ctrl(item, buffer, buffer_size);
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
}
@@ -61,9 +62,12 @@ size_t _cbor_encoded_header_size(uint64_t size) {
}
size_t cbor_serialized_size(const cbor_item_t* item) {
+ CBOR_ASSERT_VALID_TYPE(cbor_typeof(item));
switch (cbor_typeof(item)) {
case CBOR_TYPE_UINT:
case CBOR_TYPE_NEGINT:
+ CBOR_ASSERT(cbor_int_get_width(item) >= CBOR_INT_8 &&
+ cbor_int_get_width(item) <= CBOR_INT_64);
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
if (cbor_get_uint8(item) <= kMaxEmbeddedInt) return 1;
@@ -74,9 +78,9 @@ size_t cbor_serialized_size(const cbor_item_t* item) {
return 5;
case CBOR_INT_64:
return 9;
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
// Note: We do not _cbor_safe_signaling_add zero-length definite strings,
// they would cause zeroes to propagate. All other items are at least one
@@ -142,6 +146,8 @@ size_t cbor_serialized_size(const cbor_item_t* item) {
cbor_serialized_size(cbor_move(cbor_tag_item(item))));
}
case CBOR_TYPE_FLOAT_CTRL:
+ CBOR_ASSERT(cbor_float_get_width(item) >= CBOR_FLOAT_0 &&
+ cbor_float_get_width(item) <= CBOR_FLOAT_64);
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
return _cbor_encoded_header_size(cbor_ctrl_value(item));
@@ -151,13 +157,13 @@ size_t cbor_serialized_size(const cbor_item_t* item) {
return 5;
case CBOR_FLOAT_64:
return 9;
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
}
@@ -184,6 +190,8 @@ size_t cbor_serialize_alloc(const cbor_item_t* item, unsigned char** buffer,
size_t cbor_serialize_uint(const cbor_item_t* item, unsigned char* buffer,
size_t buffer_size) {
CBOR_ASSERT(cbor_isa_uint(item));
+ CBOR_ASSERT(cbor_int_get_width(item) >= CBOR_INT_8 &&
+ cbor_int_get_width(item) <= CBOR_INT_64);
// cppcheck-suppress missingReturn
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
@@ -194,15 +202,17 @@ size_t cbor_serialize_uint(const cbor_item_t* item, unsigned char* buffer,
return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);
case CBOR_INT_64:
return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
}
size_t cbor_serialize_negint(const cbor_item_t* item, unsigned char* buffer,
size_t buffer_size) {
CBOR_ASSERT(cbor_isa_negint(item));
+ CBOR_ASSERT(cbor_int_get_width(item) >= CBOR_INT_8 &&
+ cbor_int_get_width(item) <= CBOR_INT_64);
// cppcheck-suppress missingReturn
switch (cbor_int_get_width(item)) {
case CBOR_INT_8:
@@ -213,9 +223,9 @@ size_t cbor_serialize_negint(const cbor_item_t* item, unsigned char* buffer,
return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);
case CBOR_INT_64:
return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
}
@@ -367,6 +377,8 @@ size_t cbor_serialize_tag(const cbor_item_t* item, unsigned char* buffer,
size_t cbor_serialize_float_ctrl(const cbor_item_t* item, unsigned char* buffer,
size_t buffer_size) {
CBOR_ASSERT(cbor_isa_float_ctrl(item));
+ CBOR_ASSERT(cbor_float_get_width(item) >= CBOR_FLOAT_0 &&
+ cbor_float_get_width(item) <= CBOR_FLOAT_64);
// cppcheck-suppress missingReturn
switch (cbor_float_get_width(item)) {
case CBOR_FLOAT_0:
@@ -380,8 +392,8 @@ size_t cbor_serialize_float_ctrl(const cbor_item_t* item, unsigned char* buffer,
case CBOR_FLOAT_64:
return cbor_encode_double(cbor_float_get_float8(item), buffer,
buffer_size);
- default:
+ default: // LCOV_EXCL_START
_CBOR_UNREACHABLE;
- return 0;
+ return 0; // LCOV_EXCL_STOP
}
}
diff --git a/src/cbor/serialization.h b/src/cbor/serialization.h
index 10f5784a5b2f..66cb1ef4d696 100644
--- a/src/cbor/serialization.h
+++ b/src/cbor/serialization.h
@@ -51,8 +51,9 @@ cbor_serialized_size(const cbor_item_t* item);
* ignore the return value.
*
* \rst
- * .. warning:: It is the caller's responsibility to free the buffer using an
- * appropriate ``free`` implementation.
+ * .. warning::
+ * It is the caller's responsibility to free the buffer using an appropriate
+ * ``free`` implementation.
* \endrst
*
* @param item A data item
diff --git a/src/cbor/streaming.c b/src/cbor/streaming.c
index 595c85805f19..426df78b7318 100644
--- a/src/cbor/streaming.c
+++ b/src/cbor/streaming.c
@@ -593,9 +593,9 @@ struct cbor_decoder_result cbor_stream_decode(
/* Break */
callbacks->indef_break(context);
return result;
- default:
+ default: // LCOV_EXCL_START
// Never happens, the switch statement is exhaustive on the 1B range
_CBOR_UNREACHABLE;
- return result;
+ return result; // LCOV_EXCL_STOP
}
}
diff --git a/src/cbor/strings.h b/src/cbor/strings.h
index a21133b30129..a026f4e5c95a 100644
--- a/src/cbor/strings.h
+++ b/src/cbor/strings.h
@@ -76,9 +76,10 @@ cbor_string_handle(const cbor_item_t* item);
* and invalid, `cbor_string_codepoint_count` will return 0.
*
* \rst
- * .. warning:: Using a pointer to a stack allocated constant is a common
- * mistake. Lifetime of the string will expire when it goes out of scope and
- * the CBOR item will be left inconsistent.
+ * .. warning::
+ * Using a pointer to a stack allocated constant is a common mistake.
+ * Lifetime of the string will expire when it goes out of scope and the CBOR
+ * item will be left inconsistent.
* \endrst
*
* @param item A definite string
diff --git a/test/callbacks_test.c b/test/callbacks_test.c
index c2b5ecfe8fe0..1045ed1bc254 100644
--- a/test/callbacks_test.c
+++ b/test/callbacks_test.c
@@ -33,8 +33,9 @@ unsigned char bytestring_data[] = {0x01, 0x02, 0x03};
static void test_builder_byte_string_callback_append(
void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(
- _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -73,8 +74,9 @@ static void test_builder_byte_string_callback_append(
static void test_builder_byte_string_callback_append_alloc_failure(
void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(
- _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -105,8 +107,9 @@ static void test_builder_byte_string_callback_append_alloc_failure(
static void test_builder_byte_string_callback_append_item_alloc_failure(
void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(
- _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -139,8 +142,9 @@ static void test_builder_byte_string_callback_append_item_alloc_failure(
static void test_builder_byte_string_callback_append_parent_alloc_failure(
void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(
- _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_bytestring(), 0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -173,7 +177,9 @@ static void test_builder_byte_string_callback_append_parent_alloc_failure(
unsigned char string_data[] = {0x61, 0x62, 0x63};
static void test_builder_string_callback_append(void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_string(), 0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -210,7 +216,9 @@ static void test_builder_string_callback_append(void** _state _CBOR_UNUSED) {
static void test_builder_string_callback_append_alloc_failure(
void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_string(), 0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -241,7 +249,9 @@ static void test_builder_string_callback_append_alloc_failure(
static void test_builder_string_callback_append_item_alloc_failure(
void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_string(), 0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -273,7 +283,9 @@ static void test_builder_string_callback_append_item_alloc_failure(
static void test_builder_string_callback_append_parent_alloc_failure(
void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(_cbor_stack_push(&stack, cbor_new_indefinite_string(), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_string(), 0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -304,7 +316,9 @@ static void test_builder_string_callback_append_parent_alloc_failure(
static void test_append_array_failure(void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(_cbor_stack_push(&stack, cbor_new_definite_array(0), 0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_definite_array(0), 0);
+ assert_non_null(stack_top);
stack.top->subitems = 1;
struct _cbor_decoder_context context = {
.creation_failed = false,
@@ -333,8 +347,9 @@ static void test_append_array_failure(void** _state _CBOR_UNUSED) {
static void test_append_map_failure(void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(
- _cbor_stack_push(&stack, cbor_new_indefinite_map(), /*subitems=*/0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_indefinite_map(), /*subitems=*/0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
@@ -373,7 +388,9 @@ static void test_invalid_indef_break(void** _state _CBOR_UNUSED) {
static void test_invalid_state_indef_break(void** _state _CBOR_UNUSED) {
struct _cbor_stack stack = _cbor_stack_init();
- assert_non_null(_cbor_stack_push(&stack, cbor_new_int8(), /*subitems=*/0));
+ struct _cbor_stack_record* stack_top =
+ _cbor_stack_push(&stack, cbor_new_int8(), /*subitems=*/0);
+ assert_non_null(stack_top);
struct _cbor_decoder_context context = {
.creation_failed = false,
.syntax_error = false,
diff --git a/test/copy_test.c b/test/copy_test.c
index ef58fecd5a9f..727791c2834d 100644
--- a/test/copy_test.c
+++ b/test/copy_test.c
@@ -182,6 +182,326 @@ static void test_floats(void** _state _CBOR_UNUSED) {
cbor_decref(&copy);
}
+static void test_definite_uints(void** _state _CBOR_UNUSED) {
+ item = cbor_build_uint8(10);
+ assert_uint8(copy = cbor_copy_definite(item), 10);
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_negints(void** _state _CBOR_UNUSED) {
+ item = cbor_build_negint16(10);
+ assert_true(cbor_get_uint16(copy = cbor_copy_definite(item)) == 10);
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_bytestring(void** _state _CBOR_UNUSED) {
+ item = cbor_build_bytestring((cbor_data) "abc", 3);
+ assert_memory_equal(cbor_bytestring_handle(copy = cbor_copy_definite(item)),
+ cbor_bytestring_handle(item), 3);
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_indef_bytestring(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_bytestring();
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "abc", 3))));
+
+ assert_memory_equal(cbor_bytestring_handle(copy = cbor_copy_definite(item)),
+ "abc", 3);
+ assert_true(cbor_isa_bytestring(copy));
+ assert_true(cbor_bytestring_is_definite(copy));
+ assert_size_equal(cbor_bytestring_length(copy), 3);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_bytestring_alloc_failure(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_bytestring();
+ assert_true(cbor_bytestring_add_chunk(
+ item, cbor_move(cbor_build_bytestring((cbor_data) "abc", 3))));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy_definite(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_definite_string(void** _state _CBOR_UNUSED) {
+ item = cbor_build_string("abc");
+ assert_memory_equal(cbor_string_handle(copy = cbor_copy_definite(item)),
+ cbor_string_handle(item), 3);
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_indef_string(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_string();
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string("abc"))));
+
+ assert_memory_equal(cbor_string_handle(copy = cbor_copy_definite(item)),
+ "abc", 3);
+ assert_true(cbor_isa_string(copy));
+ assert_true(cbor_string_is_definite(copy));
+ assert_size_equal(cbor_string_length(copy), 3);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_string_alloc_failure(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_string();
+ assert_true(cbor_string_add_chunk(item, cbor_move(cbor_build_string("abc"))));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy_definite(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_definite_array(void** _state _CBOR_UNUSED) {
+ item = cbor_new_definite_array(1);
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
+
+ copy = cbor_copy_definite(item);
+ assert_true(cbor_isa_array(copy));
+ assert_true(cbor_array_is_definite(copy));
+ assert_size_equal(cbor_array_size(copy), 1);
+ assert_uint8(tmp = cbor_array_get(copy, 0), 42);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+ cbor_decref(&tmp);
+}
+
+static void test_definite_indef_array(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_array();
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
+
+ copy = cbor_copy_definite(item);
+ assert_true(cbor_isa_array(copy));
+ assert_true(cbor_array_is_definite(copy));
+ assert_uint8(tmp = cbor_array_get(copy, 0), 42);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+ cbor_decref(&tmp);
+}
+
+static void test_definite_indef_array_nested(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_array();
+ cbor_item_t* nested_array = cbor_new_indefinite_array();
+ assert_true(cbor_array_push(item, cbor_move(nested_array)));
+
+ copy = cbor_copy_definite(item);
+ assert_true(cbor_isa_array(copy));
+ assert_true(cbor_array_is_definite(copy));
+ assert_size_equal(cbor_array_size(copy), 1);
+
+ tmp = cbor_array_get(copy, 0);
+ assert_true(cbor_isa_array(tmp));
+ assert_true(cbor_array_is_definite(tmp));
+ assert_size_equal(cbor_array_size(tmp), 0);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+ cbor_decref(&tmp);
+}
+
+static void test_definite_array_alloc_failure(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_array();
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy_definite(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_definite_array_item_alloc_failure(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_array();
+ assert_true(cbor_array_push(item, cbor_move(cbor_build_uint8(42))));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy_definite(item)); }, 3,
+ // New array, new array data, item copy
+ MALLOC, MALLOC, MALLOC_FAIL);
+
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_definite_map(void** _state _CBOR_UNUSED) {
+ item = cbor_new_definite_map(1);
+ assert_true(cbor_map_add(item, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_uint8(43)),
+ }));
+
+ copy = cbor_copy_definite(item);
+ assert_true(cbor_isa_map(copy));
+ assert_true(cbor_map_is_definite(copy));
+ assert_size_equal(cbor_map_size(copy), 1);
+ assert_uint8(cbor_map_handle(copy)[0].key, 42);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_indef_map(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_map();
+ assert_true(cbor_map_add(item, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_uint8(43)),
+ }));
+
+ copy = cbor_copy_definite(item);
+ assert_true(cbor_isa_map(copy));
+ assert_true(cbor_map_is_definite(copy));
+ assert_size_equal(cbor_map_size(copy), 1);
+ assert_uint8(cbor_map_handle(copy)[0].key, 42);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_indef_map_nested(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_map();
+ cbor_item_t* key = cbor_new_indefinite_array();
+ cbor_item_t* value = cbor_new_indefinite_array();
+ assert_true(cbor_map_add(item, (struct cbor_pair){
+ .key = cbor_move(key),
+ .value = cbor_move(value),
+ }));
+
+ copy = cbor_copy_definite(item);
+ assert_true(cbor_isa_map(copy));
+ assert_true(cbor_map_is_definite(copy));
+ assert_size_equal(cbor_map_size(copy), 1);
+
+ assert_true(cbor_isa_array(cbor_map_handle(copy)[0].key));
+ assert_true(cbor_array_is_definite(cbor_map_handle(copy)[0].key));
+ assert_size_equal(cbor_array_size(cbor_map_handle(copy)[0].key), 0);
+
+ assert_true(cbor_isa_array(cbor_map_handle(copy)[0].value));
+ assert_true(cbor_array_is_definite(cbor_map_handle(copy)[0].value));
+ assert_size_equal(cbor_array_size(cbor_map_handle(copy)[0].value), 0);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_map_alloc_failure(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_map();
+ assert_true(cbor_map_add(item, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_uint8(43)),
+ }));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy_definite(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_definite_map_key_alloc_failure(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_map();
+ assert_true(cbor_map_add(item, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_uint8(43)),
+ }));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy_definite(item)); }, 3,
+ // New map, map data, key copy
+ MALLOC, MALLOC, MALLOC_FAIL);
+
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_definite_map_value_alloc_failure(void** _state _CBOR_UNUSED) {
+ item = cbor_new_indefinite_map();
+ assert_true(cbor_map_add(item, (struct cbor_pair){
+ .key = cbor_move(cbor_build_uint8(42)),
+ .value = cbor_move(cbor_build_uint8(43)),
+ }));
+
+ WITH_MOCK_MALLOC({ assert_null(cbor_copy_definite(item)); }, 4,
+ // New map, map data, key copy, value copy
+ MALLOC, MALLOC, MALLOC, MALLOC_FAIL);
+
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_definite_tag(void** _state _CBOR_UNUSED) {
+ item = cbor_build_tag(10, cbor_move(cbor_build_uint8(42)));
+
+ copy = cbor_copy_definite(item);
+ assert_uint8(tmp = cbor_tag_item(copy), 42);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+ cbor_decref(&tmp);
+}
+
+static void test_definite_tag_nested(void** _state _CBOR_UNUSED) {
+ item = cbor_build_tag(10, cbor_move(cbor_new_indefinite_array()));
+
+ copy = cbor_copy_definite(item);
+ assert_true(cbor_isa_tag(copy));
+
+ tmp = cbor_tag_item(copy);
+ assert_true(cbor_isa_array(tmp));
+ assert_true(cbor_array_is_definite(tmp));
+ assert_size_equal(cbor_array_size(tmp), 0);
+
+ cbor_decref(&item);
+ cbor_decref(&copy);
+ cbor_decref(&tmp);
+}
+
+static void test_definite_tag_alloc_failure(void** _state _CBOR_UNUSED) {
+ item = cbor_build_tag(10, cbor_move(cbor_build_uint8(42)));
+
+ WITH_FAILING_MALLOC({ assert_null(cbor_copy_definite(item)); });
+ assert_size_equal(cbor_refcount(item), 1);
+
+ cbor_decref(&item);
+}
+
+static void test_definite_ctrls(void** _state _CBOR_UNUSED) {
+ item = cbor_new_null();
+ assert_true(cbor_is_null(copy = cbor_copy_definite(item)));
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
+static void test_definite_floats(void** _state _CBOR_UNUSED) {
+ item = cbor_build_float2(3.14f);
+ assert_true(cbor_float_get_float2(copy = cbor_copy_definite(item)) ==
+ cbor_float_get_float2(item));
+ cbor_decref(&item);
+ cbor_decref(&copy);
+
+ item = cbor_build_float4(3.14f);
+ assert_true(cbor_float_get_float4(copy = cbor_copy_definite(item)) ==
+ cbor_float_get_float4(item));
+ cbor_decref(&item);
+ cbor_decref(&copy);
+
+ item = cbor_build_float8(3.14);
+ assert_true(cbor_float_get_float8(copy = cbor_copy_definite(item)) ==
+ cbor_float_get_float8(item));
+ cbor_decref(&item);
+ cbor_decref(&copy);
+}
+
static void test_alloc_failure_simple(void** _state _CBOR_UNUSED) {
item = cbor_build_uint8(10);
@@ -469,6 +789,30 @@ int main(void) {
cmocka_unit_test(test_map_second_key_failure),
cmocka_unit_test(test_tag_item_alloc_failure),
cmocka_unit_test(test_tag_alloc_failure),
+ cmocka_unit_test(test_definite_uints),
+ cmocka_unit_test(test_definite_negints),
+ cmocka_unit_test(test_definite_bytestring),
+ cmocka_unit_test(test_definite_bytestring_alloc_failure),
+ cmocka_unit_test(test_definite_indef_bytestring),
+ cmocka_unit_test(test_definite_string),
+ cmocka_unit_test(test_definite_indef_string),
+ cmocka_unit_test(test_definite_string_alloc_failure),
+ cmocka_unit_test(test_definite_array),
+ cmocka_unit_test(test_definite_indef_array),
+ cmocka_unit_test(test_definite_indef_array_nested),
+ cmocka_unit_test(test_definite_array_alloc_failure),
+ cmocka_unit_test(test_definite_array_item_alloc_failure),
+ cmocka_unit_test(test_definite_map),
+ cmocka_unit_test(test_definite_indef_map),
+ cmocka_unit_test(test_definite_indef_map_nested),
+ cmocka_unit_test(test_definite_map_alloc_failure),
+ cmocka_unit_test(test_definite_map_key_alloc_failure),
+ cmocka_unit_test(test_definite_map_value_alloc_failure),
+ cmocka_unit_test(test_definite_tag),
+ cmocka_unit_test(test_definite_tag_nested),
+ cmocka_unit_test(test_definite_tag_alloc_failure),
+ cmocka_unit_test(test_definite_ctrls),
+ cmocka_unit_test(test_definite_floats),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/float_ctrl_test.c b/test/float_ctrl_test.c
index 927bf567bdc3..5a19d58b68e1 100644
--- a/test/float_ctrl_test.c
+++ b/test/float_ctrl_test.c
@@ -69,6 +69,8 @@ unsigned char null_data[] = {0xF6};
static void test_null(void** _state _CBOR_UNUSED) {
float_ctrl = cbor_load(null_data, 1, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
+ assert_true(cbor_float_ctrl_is_ctrl(float_ctrl));
+ assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_0);
assert_true(cbor_is_null(float_ctrl));
cbor_decref(&float_ctrl);
assert_null(float_ctrl);
@@ -79,6 +81,8 @@ unsigned char undef_data[] = {0xF7};
static void test_undef(void** _state _CBOR_UNUSED) {
float_ctrl = cbor_load(undef_data, 1, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
+ assert_true(cbor_float_ctrl_is_ctrl(float_ctrl));
+ assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_0);
assert_true(cbor_is_undef(float_ctrl));
cbor_decref(&float_ctrl);
assert_null(float_ctrl);
@@ -90,6 +94,8 @@ static void test_bool(void** _state _CBOR_UNUSED) {
_CBOR_TEST_DISABLE_ASSERT({
float_ctrl = cbor_load(bool_data, 1, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
+ assert_true(cbor_float_ctrl_is_ctrl(float_ctrl));
+ assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_0);
assert_true(cbor_is_bool(float_ctrl));
assert_false(cbor_get_bool(float_ctrl));
cbor_set_bool(float_ctrl, true);
@@ -100,6 +106,8 @@ static void test_bool(void** _state _CBOR_UNUSED) {
float_ctrl = cbor_load(bool_data + 1, 1, &res);
assert_true(cbor_isa_float_ctrl(float_ctrl));
+ assert_true(cbor_float_ctrl_is_ctrl(float_ctrl));
+ assert_true(cbor_float_get_width(float_ctrl) == CBOR_FLOAT_0);
assert_true(cbor_is_bool(float_ctrl));
assert_true(cbor_get_bool(float_ctrl));
cbor_set_bool(float_ctrl, false);
@@ -125,6 +133,18 @@ static void test_float_ctrl_creation(void** _state _CBOR_UNUSED) {
WITH_FAILING_MALLOC({ assert_null(cbor_build_ctrl(0xAF)); });
}
+static void test_ctrl_on_float(void** _state _CBOR_UNUSED) {
+ float_ctrl = cbor_build_float4(3.14f);
+ assert_non_null(float_ctrl);
+ assert_true(cbor_is_float(float_ctrl));
+ assert_false(cbor_float_ctrl_is_ctrl(float_ctrl));
+ assert_false(cbor_is_null(float_ctrl));
+ assert_false(cbor_is_undef(float_ctrl));
+ assert_false(cbor_is_bool(float_ctrl));
+ cbor_decref(&float_ctrl);
+ assert_null(float_ctrl);
+}
+
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_float2),
@@ -134,6 +154,7 @@ int main(void) {
cmocka_unit_test(test_undef),
cmocka_unit_test(test_bool),
cmocka_unit_test(test_float_ctrl_creation),
+ cmocka_unit_test(test_ctrl_on_float),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}
diff --git a/test/map_test.c b/test/map_test.c
index 3c41456079a0..1e8492ef49ea 100644
--- a/test/map_test.c
+++ b/test/map_test.c
@@ -246,11 +246,24 @@ static void test_indef_map_decode(void** _state _CBOR_UNUSED) {
map = cbor_load(test_indef_map, 6, &res);
assert_null(map);
- assert_size_equal(res.error.code, CBOR_ERR_MEMERROR);
+ assert_int_equal(res.error.code, CBOR_ERR_MEMERROR);
},
4, MALLOC, MALLOC, MALLOC, REALLOC_FAIL);
}
+// The value in the third pair is missing, 0xFF instead.
+static unsigned char test_break_in_def_map[] = {0xA3, 0x30, 0x30, 0x30,
+ 0x30, 0x00, 0xFF};
+static void test_break_in_def_map_decode(void** _state _CBOR_UNUSED) {
+ cbor_item_t* map;
+ struct cbor_load_result res;
+ map = cbor_load(test_break_in_def_map, 7, &res);
+
+ assert_null(map);
+ assert_int_equal(res.error.code, CBOR_ERR_SYNTAXERROR);
+ assert_size_equal(res.error.position, 7);
+}
+
int main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_empty_map),
@@ -265,6 +278,7 @@ int main(void) {
cmocka_unit_test(test_map_creation),
cmocka_unit_test(test_map_add),
cmocka_unit_test(test_indef_map_decode),
+ cmocka_unit_test(test_break_in_def_map_decode),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}