diff --git a/src/nunavut/lang/c/templates/definitions.j2 b/src/nunavut/lang/c/templates/definitions.j2 index 360efba6..b4f7f6a7 100644 --- a/src/nunavut/lang/c/templates/definitions.j2 +++ b/src/nunavut/lang/c/templates/definitions.j2 @@ -215,7 +215,7 @@ static inline {{ typename_error_type }} {{ t | full_reference_name }}_serialize_ /// @returns Negative on error, zero on success. static inline {{ typename_error_type }} {{ t | full_reference_name }}_deserialize_( {{ t | full_reference_name }}* const out_obj, {# -#} - const {{ typename_byte }}* const buffer, {# -#} + const {{ typename_byte }}* buffer, {# -#} {{ typename_unsigned_length }}* const inout_buffer_size_bytes) { {% from 'deserialization.j2' import deserialize -%} diff --git a/src/nunavut/lang/c/templates/deserialization.j2 b/src/nunavut/lang/c/templates/deserialization.j2 index ec128d2e..04c1fe34 100644 --- a/src/nunavut/lang/c/templates/deserialization.j2 +++ b/src/nunavut/lang/c/templates/deserialization.j2 @@ -11,11 +11,15 @@ {# ----------------------------------------------------------------------------------------------------------------- #} {% macro deserialize(t) %} - if ((out_obj == {{ valuetoken_null }}) || (buffer == {{ valuetoken_null }}) || {# -#} - (inout_buffer_size_bytes == {{ valuetoken_null }})) + if ((out_obj == {{ valuetoken_null }}) || (inout_buffer_size_bytes == {{ valuetoken_null }}) || {# -#} + ((buffer == {{ valuetoken_null }}) && (0 != *inout_buffer_size_bytes))) { return -NUNAVUT_ERROR_INVALID_ARGUMENT; } + if (buffer == {{ valuetoken_null }}) + { + buffer = (const {{ typename_byte }}*)""; + } {% if t.inner_type.bit_length_set.max > 0 %} {{ _deserialize_impl(t) }} {% else %} diff --git a/src/nunavut/version.py b/src/nunavut/version.py index 03292943..9215484a 100644 --- a/src/nunavut/version.py +++ b/src/nunavut/version.py @@ -7,7 +7,7 @@ .. autodata:: __version__ """ -__version__ = "1.6.1" #: The version number used in the release of nunavut to pypi. +__version__ = "1.6.2" #: The version number used in the release of nunavut to pypi. __license__ = "MIT" diff --git a/verification/c/suite/test_serialization.c b/verification/c/suite/test_serialization.c index 4e71e7cc..2b296c5a 100644 --- a/verification/c/suite/test_serialization.c +++ b/verification/c/suite/test_serialization.c @@ -8,6 +8,7 @@ #include #include #include +#include #include "unity.h" // Include 3rd-party headers afterward to ensure that our headers are self-sufficient. #include #include @@ -847,6 +848,45 @@ static void testPrimitiveArrayVariable(void) } } +/* + * Test that deserialization methods do not signal an error if a zero size is specified for a null output buffer. + */ +static void testIssue221(void) +{ + uint8_t buf[regulated_basics_Primitive_0_1_SERIALIZATION_BUFFER_SIZE_BYTES_]; + const size_t fixed_size = sizeof(buf); + size_t size = fixed_size; + + regulated_basics_Primitive_0_1 obj; + TEST_ASSERT_EQUAL(0, regulated_basics_Primitive_0_1_deserialize_(&obj, &buf[0], &size)); + size = fixed_size; + TEST_ASSERT_EQUAL(-NUNAVUT_ERROR_INVALID_ARGUMENT, + regulated_basics_Primitive_0_1_deserialize_(NULL, &buf[0], &size)); + size = fixed_size; + TEST_ASSERT_EQUAL(-NUNAVUT_ERROR_INVALID_ARGUMENT, + regulated_basics_Primitive_0_1_deserialize_(&obj, NULL, &size)); + TEST_ASSERT_EQUAL(-NUNAVUT_ERROR_INVALID_ARGUMENT, + regulated_basics_Primitive_0_1_deserialize_(&obj, &buf[0], NULL)); + size = 0; + TEST_ASSERT_EQUAL(0, + regulated_basics_Primitive_0_1_deserialize_(&obj, NULL, &size)); + TEST_ASSERT_EQUAL(0, size); +} + +/* + * Ensure that, where there is no input data, the deserialization method applies the zero-extension rule as defined + * in section 3.7.1.4 of the specification. + */ +static void testIssue221_zeroExtensionRule(void) +{ + size_t size = 0; + uavcan_pnp_NodeIDAllocationData_2_0 obj; + obj.node_id.value = 0xAAAA; + TEST_ASSERT_EQUAL(0, uavcan_pnp_NodeIDAllocationData_2_0_deserialize_(&obj, NULL, &size)); + TEST_ASSERT_EQUAL(0, obj.node_id.value); +} + + void setUp(void) { const unsigned seed = (unsigned) time(NULL); @@ -869,6 +909,8 @@ int main(void) RUN_TEST(testPrimitive); RUN_TEST(testPrimitiveArrayFixed); RUN_TEST(testPrimitiveArrayVariable); + RUN_TEST(testIssue221); + RUN_TEST(testIssue221_zeroExtensionRule); return UNITY_END(); }