NordicSemiconductor / zcbor

Low footprint C/C++ CBOR library and Python tool providing code generation from CDDL descriptions.
Apache License 2.0
105 stars 34 forks source link

Incorrect encoding for CDDL arrays with keys #340

Closed maxd-nordic closed 1 year ago

maxd-nordic commented 1 year ago

Consider the following CDDL schema:

rsrp = 7
rsrp-message = [
    message-type : rsrp,
    timestamp : uint .size 4, ; UNIX timestamp
    rsrp : int .size 2, ; RSRP in dBm
]

This is similar to RFC 8610 3.5.1, where keys are used for expressiveness, but ignored in the encoding.

The zcbor code generator gives me the following code:

static bool encode_rsrp_message(
        zcbor_state_t *state, const struct rsrp_message *input)
{
    zcbor_print("%s\r\n", __func__);

    bool tmp_result = (((zcbor_list_start_encode(state, 3) && ((((zcbor_uint32_put(state, (7))))
    && (((((*input)._rsrp_message_timestamp <= 4294967295)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))
    && (zcbor_uint32_encode(state, (&(*input)._rsrp_message_timestamp))))
    && (((zcbor_uint32_put(state, (7))))
    && ((((*input)._rsrp_message_rsrp >= -32767)
    && ((*input)._rsrp_message_rsrp <= 32767)) || (zcbor_error(state, ZCBOR_ERR_WRONG_RANGE), false))
    && (zcbor_int32_encode(state, (&(*input)._rsrp_message_rsrp))))) || (zcbor_list_map_end_force_encode(state), false)) && zcbor_list_end_encode(state, 3))));

    if (!tmp_result)
        zcbor_trace();

    return tmp_result;
}

zcbor_uint32_put(state, (7) is called twice, resulting in an incorrect encoding. This will generate [7, timestamp, 7, rsrp], but should do [7, timestamp, rsrp].

maxd-nordic commented 1 year ago

Nevermind, this was with version 0.4.0. With 0.7.0, it doesn't pass validation:

Parsing files: from-device.cddl, /home/maxd/.local/lib/python3.8/site-packages/zcbor/cddl/prelude.cddl
Traceback (most recent call last):
  File "/home/maxd/.local/bin/zcbor", line 8, in <module>
    sys.exit(main())
  File "/home/maxd/.local/lib/python3.8/site-packages/zcbor/zcbor.py", line 3168, in main
    args.process(args)
  File "/home/maxd/.local/lib/python3.8/site-packages/zcbor/zcbor.py", line 3025, in process_code
    cddl_res[mode] = CodeGenerator.from_cddl(
  File "/home/maxd/.local/lib/python3.8/site-packages/zcbor/zcbor.py", line 1730, in from_cddl
    cddl_res = super(CodeGenerator, cddl_class).from_cddl(*args, **kwargs)
  File "/home/maxd/.local/lib/python3.8/site-packages/zcbor/zcbor.py", line 283, in from_cddl
    my_types[my_type].post_validate()
  File "/home/maxd/.local/lib/python3.8/site-packages/zcbor/zcbor.py", line 917, in post_validate
    raise TypeError(
TypeError: LIST[   message-type://OTHER'rsrp',
        timestamp:UINT,
        rsrp://OTHER'rsrp' => INT]
List member(s) cannot have key: [rsrp://OTHER'rsrp' => INT] pointing to []

Solution is to have different names.