Commit Graph
406 Commits
Author SHA1 Message Date
Nicolas Iooss 4682eaa1e0 Pretty: ensure recursionsLeft is not zero before decrementing it
When value_to_pretty is called with recursionsLeft=0 and an Array or Map
type, container_to_pretty is called with recursionsLeft - 1 = -1. This
breaks the recursion limit check.

In practice, this can be triggered with a CBOR data containing 1023
Arrays, a Tag and many more Arrays:

    $ python3 -c 'import sys;sys.stdout.buffer.write(b"\x9f" * 1023 + b"\xc0\x9f" + b"\x9f" * 100000 + b"\xff" * 101024)' | ./bin/cbordump
    Segmentation fault (core dumped)

This segmentation fault is due to the stack growing too much, due to the
quantity of recursive calls.

Fix this by reporting a proper error when recursionsLeft <= 0, instead
of when recursionsLeft == 0. The same input now produces:

    [_ [_ [_ ... [_ 0([
    -: internal error: too many nested containers found in recursive function
    _ <nesting too deep, recursion stopped>

Moreover, using fewer nested arrays works fine:

    $ python3 -c 'import sys;sys.stdout.buffer.write(b"\x9f" * 1023 + b"\xc0\x9f" + b"\x9f" * 1024 + b"\xff" * 2048)' |./bin/cbordump
    [_ [_ [_ ... [_ 0([_ <nesting too deep, recursion stopped>])] ... ]]]

Also modify the test when formatting CborTagType to ensure
value_to_pretty is never called with a negative recursionsLeft.
2025-03-18 10:49:39 -07:00
Nicolas Iooss f96502575f Pretty: fix Undefined Behavior with NaN floats
When printing CBOR data containing NaN, function convertToUint64 does an
undefined behavior. This can be reproduced using test cases from
tests/parser/data.cpp:

    $ make CC='clang -fsanitize=undefined'
    $ printf "\xfb\x7f\xf8\0\0\0\0\0\0" | ./bin/cbordump
    src/cborpretty.c:171:17: runtime error: nan is outside the range of
    representable values of type 'unsigned long'
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/cborpretty.c:171:17 in
    nan

    $ printf "\xf9\x7e\x00" | ./bin/cbordump
    src/cborpretty.c:171:17: runtime error: nan is outside the range of
    representable values of type 'unsigned long'
    SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior src/cborpretty.c:171:17 in
    nan

Fix this by checking whether the value to convert is not NaN.
2025-03-18 08:07:34 -07:00
Thiago Macieira 8684cdef61 Move the source-selection macros to a common header
Avoids having to repeat ourselves.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-14 10:11:20 -07:00
Nicolas Iooss 6d31efad9a CBOR-to-JSON: fix integer overflow when computing allocation size
Use add_check_overflow and mul_check_overflow to ensure the arithmetic
operations do not overflow when computing the size to allocate.
2025-03-14 09:44:54 -07:00
Nicolas Iooss 628dee0d65 CBOR-to-JSON: fix memory leak when parsing invalid CBOR
When function text_string_to_escaped successfully parses a string and
fails to parse the next value (cbor_value_finish_string_iteration
returns an error), it correctly propagates the error but the string is
never freed.

This can be reproduced with:

    make CC='clang -g -fsanitize=address'
    printf '\x82\x60\xff' | ./bin/cbordump -j

clang's Address Sanitizer reports:

    =================================================================
    ==20317==ERROR: LeakSanitizer: detected memory leaks

    Direct leak of 1 byte(s) in 1 object(s) allocated from:
        #0 0x560b654b9916 in __interceptor_realloc (/tinycbor/bin/cbordump+0xa4916) (BuildId: f9933666b5d987b21f68c2887de4aebe93bc2bef)
        #1 0x560b654f5c18 in escape_text_string /tinycbor/src/cbortojson.c:331:15
        #2 0x560b654f3e29 in text_string_to_escaped /tinycbor/src/cbortojson.c:377:19
        #3 0x560b654f267d in value_to_json /tinycbor/src/cbortojson.c:674:19
        #4 0x560b654f34c2 in array_to_json /tinycbor/src/cbortojson.c:545:25
        #5 0x560b654f2085 in value_to_json /tinycbor/src/cbortojson.c:627:19
        #6 0x560b654f1baf in cbor_value_to_json_advance /tinycbor/src/cbortojson.c:816:12
        #7 0x560b654ea928 in dumpFile /tinycbor/tools/cbordump/cbordump.c:76:19
        #8 0x560b654ead2b in main /tinycbor/tools/cbordump/cbordump.c:149:9
        #9 0x7fa9d7629d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

    SUMMARY: AddressSanitizer: 1 byte(s) leaked in 1 allocation(s).

Fix this by freeing the string when cbor_value_finish_string_iteration
fails.

Fixes: e072bc1d78 ("CBOR-to-JSON: do properly escape JSON strings")
2025-03-14 09:31:03 -07:00
Thiago Macieira d0a6def07b CBOR-to-JSON: fix UB in converting out-of-bounds FP to integer
Both the C and C++ standards say it is Undefined Behavior to convert a
floating point number to integer if the input is out of bounds of the
destination type.

And indeed this started failing in recent builds, with
  val = 18446744073709551616  (2^64)
it has probably been producing ival = 18446744073709551615 for a while,
but the conversion back to floating point now rounded up and compared
equal to the input.

So let's just fix it.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-12 19:35:44 -07:00
Thiago Macieira c52d731e5e cbor.h: let tinycbor-export.h define CBOR_API
And make CBOR_PRIVATE_API fall back to it.

We also need to provide the file for the old Makefile build too.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-12 16:49:17 -07:00
Thiago Macieira 582423c9d9 CMake: Fix build: add new sources since CMakeLists.txt was created 2025-03-12 16:49:17 -07:00
Samuel Debionne 37d1a6dee3 Add CMake support 2025-03-12 16:49:17 -07:00
Thiago Macieira c60b710ff0 tst_Parser: fix build: define CBOR_PARSER_MAX_RECURSIONS
I don't know how this was compiling.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-12 15:39:02 -07:00
Thiago Macieira 4050fa58c2 tst_Parser: add some testing rows for floating point data
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-12 15:21:35 -07:00
Thiago Macieira 1577f3b538 tst_ToJson: add a test for the ExpectedBase64url tag too
Just to confirm it works.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-12 15:21:35 -07:00
Thiago Macieira 0f3008d54c AppVeyor: replace Qt 5.13+MSVC 2017 with Qt 6.8+MSVC 2022
MSVC 2017 is way too old now.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-12 15:21:35 -07:00
Thiago Macieira 6e3333ebe0 Encoder: add unit test for cbor_encode_raw
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-12 15:21:35 -07:00
TSonono abb7b3fe35 Added the method cbor_encode_raw to the API
This method allows for writing raw data directly to the encoding buffer. This can be useful if you have something stored as CBOR encoded data.

Fixes #162.

Signed-off-by: Tofik Sonono <tofiksonono@msn.com>
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-12 15:21:35 -07:00
Thiago Macieira c0aad2fb21 cborparser_dup_string: don't modify *buffer until success
We were returning from the function with the memory we had allocated and
freed, if the second iteration over the string produced a failure that
didn't happen on the first one. This can't happen with pure memory
buffers, but can happen with an external data source that fails to
produce the same contents twice.

I'm documenting that the values in all error conditions except for OOM
are undefined, so one mustn't attempt to use them, even to free. This
does not change behaviour of the library, just documents.

But this commit does make it clear the OOM condition will return a valid
`*buflen` and `next`, the latter of which is new behaviour with this
commit.

Fixes #258.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
v0.6.1
2025-03-11 18:32:15 -07:00
Thiago Macieira 2fc4c35f9d json2cbor: don't use the buffer variable after realloc()
There's a discussion in the C and C++ communities whether you're allowed
to use the values of pointers that have been deallocated, if you don't
dereference them. Some argue that it is Undefined Behaviour in spite of
the numeric value stored in the variable not having changed.

Instead of arguing, let's just make sure we don't use the pointers after
they have become dangling. We only needed the offset of how far we've
written into the buffer to restore the state and we have a function that
returns exactly that.

Seen while debugging #259.

Drive-by keep the `buffersize` global variable unchanged until after
`realloc()` has returned with success.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-11 18:24:45 -07:00
Thiago Macieira e072bc1d78 CBOR-to-JSON: do properly escape JSON strings
We hadn't bothered, as this was just example-like code to show how one
could convert from CBOR to JSON. But as it was added to the library (no
extra dependency), we should Do The Right Thing (DTRT) and escape.

This patch could have used cbor_value_to_pretty() to print the string,
which has better support for UTF-8 escaping and thus checks for UTF-8
correctness, but that would make map_to_json()'s metadata functionality
much more complex, especially since we cannot rely on open_memstream()
always being available. Therefore, we are partially duplicating
cborpretty.c's utf8EscapedDump().

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-11 14:42:41 -07:00
Thiago Macieira e6924451a9 CBOR-to-JSON: Limit how deep we process nested containers
1024 levels will probably be good enough for everyone, like
cborparser.c. For those for whom it isn't, they can set the limit during
the build.

We already had this for the plain parser, so TinyCBOR wouldn't cause a
stack overflow in case of a malformed stream (intentionally or not) when
simply parsing and advancing over the stream. This same protection
wasn't applied to the content converting from CBOR to JSON.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-03-11 10:55:26 -07:00
Marc Mutz 5bdc6ea3fe Always init CborEncoder::data in cbor_encoder_init_writer()
Coverity complains that, when CBOR_ENCODER_WRITE_FUNCTION is defined,
enc.data is read in cbor_encoder_create_map() when
cbor_encoder_init_writer() didn't write to it.

While 'data' is merely copied in cbor_encoder_create_map(), Coverity
is right, though: reading an uninitialized value is UB.

Fix by setting data.writer to nullptr (abstracting the difference
between C and C++ behind a new macro).
2025-03-10 13:00:39 -07:00
Thiago Macieira 53ff130af9 tst_Parser: replace Q_ASSERT(false) with Q_UNREACHABLE()
`Q_ASSERT()` disappears in release mode, leading Clang to print a static
analysis warning about an impossible condition:
```
tst_parser.cpp:251:16: warning: variable 'err' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
  251 |     } else if (ourType == CborTextStringType) {
      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tst_parser.cpp:263:12: note: uninitialized use occurs here
  263 |     return err;
      |            ^~~
tst_parser.cpp:251:12: note: remove the 'if' if its condition is always true
```

`Q_UNREACHABLE()` becomes a plain `__builtin_unreachable()` in release
mode.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-02-13 17:19:28 -08:00
Thiago Macieira 92a02529d2 compilersupport_p.h: add a macro for the fallthrough attribute
The /* fallthrough */ comment isn't always handled, causing some
compilers to complain about falling through.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-02-10 14:37:44 -08:00
Thiago Macieira b2dbc005c3 CI: Remove .travis.yml file
Travis CI doesn't work any more

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-02-08 09:35:31 -08:00
Thiago Macieira ba42254b01 Enable CI checking in the dev branch too
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2025-02-07 12:52:14 -08:00
linraymond2006 1bcde8771b Use cbor_value_get_next_byte instead of accessing structure directly
Signed-off-by: linraymond2006 <linraymond2006@gmail.com>
2025-01-22 09:22:10 -08:00
LinRaymond2006 aa86c9d08e Corrected syntax error in examples/simplereader.c 2025-01-22 09:22:10 -08:00
Giuseppe D'Angelo 2dde97f0db Prevent a -Wundef warning
Follow the same "pattern" as for the rest of the #if directive: first
test if a macro is defined, then test the value. Otherwise the code
triggers a -Wundef warning (e.g. when building in C++).
2025-01-21 09:34:31 -08:00
Thiago Macieira 26c63e3d59 CI: add 'permissions' token to the GitHub actions file
Intel says this is needed

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2024-05-13 13:27:59 -07:00
Robert Dower 7520449b79 add required SECURITY.md file for OSSF Scorecard compliance 2024-05-06 17:56:41 -07:00
Thiago Macieira 268a61ed17 Makefile: disable cJSON support when building without math support
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2024-05-01 18:35:40 -07:00
Thiago Macieira 64ce7adff0 CI: Run the configure step in verbose mode and print the config output
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2024-05-01 18:29:45 -07:00
Thiago Macieira ccdd9c1cf4 CI: unbreak macOS: need to have CXX set
Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2024-05-01 18:29:45 -07:00
Thiago Macieira db9f29d499 CI/Makefile: do allow Qt 6
I don't think we need to worry about Qt 4 any more.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2024-05-01 18:29:45 -07:00
Thiago Macieira ffc3bd6f84 CI: remove Valgrind on macOS: it doesn't work
```
==21147== Valgrind: debuginfo reader: ensure_valid failed:
==21147== Valgrind:   during call to ML_(img_get)
==21147== Valgrind:   request for range [18446744069408125024, +16) exceeds
==21147== Valgrind:   valid image size of 140733057859584 for image:
==21147== Valgrind:   "/usr/local/Cellar/icu4c/74.2/lib/libicudata.74.2.dylib"
```

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2024-05-01 18:29:45 -07:00
Thiago Macieira 24de1b065d CI: Get Homebrew to use a bottle (precompiled) Qt
Homebrew no longer carries precompiled versions of Qt for macos-11, so
switch to macos-13, the last on x86 CPUs (so we can still run
Valgrind). It's also going away after the end of June.

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2024-05-01 18:29:45 -07:00
Thiago Macieira 4df5e4f700 Tests: disable the C90 test
We don't support this any more.
```
../../src/cbor.h:255:69: error: '_Bool' is a C99 extension [-Werror,-Wc99-extensions]
CBOR_INLINE_API CborError cbor_encode_boolean(CborEncoder *encoder, bool value)
                                                                    ^
```

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2024-05-01 18:29:45 -07:00
lightyear15 b768196eb5 follow-up commit to 75eaa19
facilitate replacement of malloc/free functions

open_memstream functions are left out of this change as they require
other functions from stdlib.
2024-05-01 16:59:08 -07:00
Peter A. Jonsson 4dcad260cb CI: add Github CI 2024-05-01 16:43:17 -07:00
Peter A. Jonsson c8e12e9075 CI: add dependabot configuration
Dependabot can provide automatic pull requests
for things in the repository that should
be updated.

Example PR from dependabot against a repo owned
by the github organization:

https://github.com/github/opensource.guide/pull/2248

Documentation:

https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates
2024-05-01 16:43:17 -07:00
Thiago Macieira 0d5538277d Makefile: Fix build with Clang
It doesn't know -Wdiscarded-qualifiers. Reported by @pjonsson on #247.

I really need to switch to CMake - #242

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2023-11-26 17:27:09 -07:00
Martin Jansa fd2f6cf9a7 tinycbor: fix build with gcc-13
* fixes:
  http://errors.yoctoproject.org/Errors/Details/701753/

qtbase/6.5.0-r0/git/tests/auto/corelib/serialization/qcborstreamwriter/../../../../../src/3rdparty/tinycbor/tests/encoder/data.cpp:242:90: error: invalid user-defined conversion from 'float' to 'const qfloat16&' [-fpermissive]
  242 |     QTest::newRow("nan_f16") << raw("\xf9\x7e\0") << QVariant::fromValue<qfloat16>(myNaNf());
      |                                                                                    ~~~~~~^~
n file included from TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtCore/qmetatype.h:14,
                 from TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtTest/qtestcase.h:11,
                 from TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtTest/qtest.h:13,
                 from TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtTest/QTest:1,
                 from TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/git/tests/auto/corelib/serialization/qcborstreamwriter/tst_qcborstreamwriter.cpp:4:
TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtCore/qfloat16.h:81:22: note: candidate is: 'constexpr qfloat16::qfloat16(NativeType)' (near match)
   81 |     constexpr inline qfloat16(NativeType f) : f(f) {}
      |                      ^~~~~~~~
TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtCore/qfloat16.h:81:22: note:   conversion of argument 1 would be ill-formed:
TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/git/tests/auto/corelib/serialization/qcborstreamwriter/../../../../../src/3rdparty/tinycbor/tests/encoder/data.cpp:242:90: warning: converting to 'qfloat16::NativeType' {aka '_Float16'} from 'float' with greater conversion rank
  242 |     QTest::newRow("nan_f16") << raw("\xf9\x7e\0") << QVariant::fromValue<qfloat16>(myNaNf());
      |                                                                                    ~~~~~~^~
TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/git/tests/auto/corelib/serialization/qcborstreamwriter/../../../../../src/3rdparty/tinycbor/tests/encoder/data.cpp:242:90: warning: converting to 'qfloat16::NativeType' {aka '_Float16'} from 'float' with greater conversion rank
TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtCore/qfloat16.h:81:42: note:   initializing argument 1 of 'constexpr qfloat16::qfloat16(NativeType)'
   81 |     constexpr inline qfloat16(NativeType f) : f(f) {}
      |                               ~~~~~~~~~~~^
In file included from TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtCore/qmetaobject.h:9,
                 from TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtTest/qtestcase.h:12:
TOPDIR/tmp-glibc/work/core2-64-oe-linux/qtbase/6.5.0-r0/image/usr/include/QtCore/qvariant.h:435:43: note:   initializing argument 1 of 'static std::enable_if_t<(is_copy_constructible_v<T> && is_destructible_v<T>), QVariant> QVariant::fromValue(const T&) [with T = qfloat16; std::enable_if_t<(is_copy_constructible_v<T> && is_destructible_v<T>), QVariant> = QVariant]'
  435 |     static inline auto fromValue(const T &value)
      |                                  ~~~~~~~~~^~~~~

Signed-off-by: Thiago Macieira <thiago.macieira@intel.com>
2023-11-26 17:27:09 -07:00
Peter A. Jonsson 65a4147021 Fix Doxygen warnings
The \c and \b commands accept a single word,
and there are no \section1 or \list commands
according to the Doxygen manual.
2023-10-30 11:10:56 -07:00
Brian 8b3e97d60e Update .appveyor.yml from QT v6.1 --> v6.5
Looks like AppVeyor dropped support for v6.1 QT as shown in https://www.appveyor.com/docs/windows-images-software/

Update to latest QT version
2023-10-27 08:02:45 -07:00
Piotr Wierciński 04b306c447 Use internal linkage for data.cpp files
The Qt uses test batching and potentially encoder/data.cpp
and parser/data.cpp can end up in the same translation unit.
This can be problematic as they declare symbols with the
same names.
Change both files to use internal linkage in order to avoid
symbols clashing.
2023-08-14 07:58:57 -07:00
Marc Mutz aee4f97f52 tst_Encoder: port away from Q_FOREACH
Qt is defaulting to QT_NO_FOREACH these days, so make sure we
integrate nicely with downstream and fix the single Q_FOREACH/foreach
user, in tst_encoder.cpp.

Unfortunately, the container's initialization code doesn't exactly
lend itself to making the container const (not even IILE
(Immediately-Invoked Lambda Expression) would help here, due to the
interdependency with `len`), so the idiomatic solution would be to use
std::as_const()/qAsConst().

The former is available from C++17, which we don't require, yet, and
the latter is not available under QT_NO_AS_CONST (the default for Qt
these days), so grab the nettle and implement a t17::as_const() that
switches between a manual implementation of std::as_const and the real
thing, depending on __cpp_lib_as_const. The `t17` here mimicks the qNN
(q20::remove_cvref_t/q23::forward_like/etc) mechanism used in Qt
itself for backports, with s/q/t/ because ... _T_inyCbor.

The t17 implementation is local to tst_encoder.cpp, but can easily be
extracted into a separate header once more users emerge.
2023-08-07 09:08:56 -07:00
piotreklc60 0b2e66d276 Added possibility to include external config file.
Recently I was working on a project where I had to define CBOR_PARSER_ADVANCE_BYTES_FUNCTION and CBOR_PARSER_TRANSFER_STRING_FUNCTION macros. Unfortunately the library doesn't include any external config file and building system I am using provides only possibility to add simple preprocessor definitions (like definition = value) on building script level. Adding macros is not possible. For this reason I am asking if we can add above change - if I add simple definition CBOR_EXTERNAL_CFG by build system then cbor will require cbor_cfg.h file where I can add needed macros.
2023-04-28 08:33:00 -07:00
Kal Conley 3cba6b11aa Use _Float16 for half conversions if available
Implement support for half-precision floating-point conversions using
`_Float16` introduced in C11 extension ISO/IEC TS 18661-3.
2023-02-23 17:13:37 -08:00
Nicolas Chataing 2455693393 fix(pretty): advance to the end of the iterator if recursion limit was hit 2023-02-13 11:22:04 -08:00
Nicolas Iooss 9c57e53a2f Tools: fix JSON misspelling in cbordump
Signed-off-by: Nicolas Iooss <nicolas.iooss@ledger.fr>
2023-02-11 18:22:52 -08:00
Frederic-Philippe Metz cd3cfc3bc9 Add support for ICCARM 2022-10-03 09:42:44 -07:00