diff --git a/src/nunavut/cli/__init__.py b/src/nunavut/cli/__init__.py index 3aa29e8f..3e49f23b 100644 --- a/src/nunavut/cli/__init__.py +++ b/src/nunavut/cli/__init__.py @@ -809,6 +809,22 @@ def extension_type(raw_arg: str) -> str: ).lstrip(), ) + ln_opt_group.add_argument( + "--disable-serialization-buffer-check", + action="store_true", + help=textwrap.dedent( + """ + + Instruct support header generators to disable entry buffer checks in serialization routines. + Serialization will be still safe (no buffer overflows) but it might fail during the operation + with NUNAVUT_ERROR_SERIALIZATION_BUFFER_TOO_SMALL error if provided buffer ends up being too small. + This option useful for systems with limited resources where messages are known to be small, + and smaller serialization buffers can be used (comparing to the maximum possible capacity). + + """ + ).lstrip(), + ) + ln_opt_group.add_argument( "--language-standard", "-std", diff --git a/src/nunavut/cli/parsers.py b/src/nunavut/cli/parsers.py index 89feb005..10a06feb 100644 --- a/src/nunavut/cli/parsers.py +++ b/src/nunavut/cli/parsers.py @@ -366,6 +366,10 @@ def _create_language_options(cls, args: argparse.Namespace) -> Dict[str, Any]: True if args.enable_override_variable_array_capacity else DefaultValue(False) ) + language_options["disable_serialization_buffer_check"] = ( + True if args.disable_serialization_buffer_check else DefaultValue(False) + ) + if args.language_standard is not None: language_options["std"] = args.language_standard diff --git a/src/nunavut/lang/c/templates/serialization.j2 b/src/nunavut/lang/c/templates/serialization.j2 index cd14f8b2..ce2c4caa 100644 --- a/src/nunavut/lang/c/templates/serialization.j2 +++ b/src/nunavut/lang/c/templates/serialization.j2 @@ -28,6 +28,7 @@ {# ----------------------------------------------------------------------------------------------------------------- #} {% macro _serialize_impl(t) %} const {{ typename_unsigned_length }} capacity_bytes = *inout_buffer_size_bytes; +{%- if not options.disable_serialization_buffer_check %} {%- if options.enable_override_variable_array_capacity %} #ifndef {{ t | full_reference_name }}_DISABLE_SERIALIZATION_BUFFER_CHECK_ {% endif %} @@ -37,6 +38,7 @@ } {%- if options.enable_override_variable_array_capacity %} #endif +{% endif %} {% endif %} // Notice that fields that are not an integer number of bytes long may overrun the space allocated for them // in the serialization buffer up to the next byte boundary. This is by design and is guaranteed to be safe. @@ -116,8 +118,11 @@ {{ assert('offset_bits % 8U == 0U') }} {% endif %} {# NOTICE: If this is a delimited type, we will be requiring the buffer to be at least extent-sized. - # This is a bit wasteful because when serializing we can often use a smaller buffer. #} + # This is a bit wasteful because when serializing we can often use a smaller buffer. + # `disable_serialization_buffer_check` option allows to avoid such waste for variable length arrays. #} + {% if not (t is VariableLengthArrayType and options.disable_serialization_buffer_check) %} {{ assert('(offset_bits + %dULL) <= (capacity_bytes * 8U)'|format(t.bit_length_set.max)) }} + {% endif %} {% if t is VoidType %} {{- _serialize_void(t, offset) }} {% elif t is BooleanType %} {{- _serialize_boolean(t, reference, offset) }} diff --git a/src/nunavut/lang/cpp/templates/serialization.j2 b/src/nunavut/lang/cpp/templates/serialization.j2 index fe8d5280..543c00a3 100644 --- a/src/nunavut/lang/cpp/templates/serialization.j2 +++ b/src/nunavut/lang/cpp/templates/serialization.j2 @@ -23,17 +23,18 @@ {# ----------------------------------------------------------------------------------------------------------------- #} {% macro _serialize_impl(t) %} - const {{ typename_unsigned_length }} capacity_bits = out_buffer.size(); - +{%- if not options.disable_serialization_buffer_check %} {%- if options.enable_override_variable_array_capacity %} #ifndef {{ t | full_macro_name }}_DISABLE_SERIALIZATION_BUFFER_CHECK_ {% endif %} + const {{ typename_unsigned_length }} capacity_bits = out_buffer.size(); if ((static_cast<{{ typename_unsigned_bit_length }}>(capacity_bits)) < {{ t.inner_type.bit_length_set.max }}UL) { return -nunavut::support::Error::SerializationBufferTooSmall; } {%- if options.enable_override_variable_array_capacity %} #endif // ndef {{ t | full_macro_name }}_DISABLE_SERIALIZATION_BUFFER_CHECK_ +{% endif %} {% endif %} // Notice that fields that are not an integer number of bytes long may overrun the space allocated for them @@ -113,8 +114,10 @@ {{ assert('out_buffer.offset_alings_to_byte()') }} {% endif %} {# NOTICE: If this is a delimited type, we will be requiring the buffer to be at least extent-sized. - # This is a bit wasteful because when serializing we can often use a smaller buffer. #} - {% if t.bit_length_set.max > 0 %} + # This is a bit wasteful because when serializing we can often use a smaller buffer. + # `disable_serialization_buffer_check` option allows to avoid such waste for variable length arrays. #} + {% if (t.bit_length_set.max > 0) and + not (t is VariableLengthArrayType and options.disable_serialization_buffer_check) %} {{ assert('%dULL <= out_buffer.size()'|format(t.bit_length_set.max)) }} {% endif %} diff --git a/src/nunavut/lang/properties.json b/src/nunavut/lang/properties.json index dfca4868..0e050d98 100644 --- a/src/nunavut/lang/properties.json +++ b/src/nunavut/lang/properties.json @@ -249,6 +249,7 @@ "omit_serialization_support": false, "enable_serialization_asserts": false, "enable_override_variable_array_capacity": false, + "disable_serialization_buffer_check": false, "cast_format": "(({type}) {value})" } }, @@ -505,6 +506,7 @@ "omit_serialization_support": false, "enable_serialization_asserts": false, "enable_override_variable_array_capacity": false, + "disable_serialization_buffer_check": false, "std": "c++14", "std_flavor": "std", "cast_format": "static_cast<{type}>({value})", diff --git a/test/gentest_nnvg/templates/Any.j2 b/test/gentest_nnvg/templates/Any.j2 index 8d2ac3b2..48ebd351 100644 --- a/test/gentest_nnvg/templates/Any.j2 +++ b/test/gentest_nnvg/templates/Any.j2 @@ -12,4 +12,7 @@ {%- if options.enable_override_variable_array_capacity is defined %}, "enable_override_variable_array_capacity": {{ options.enable_override_variable_array_capacity | ln.js.to_true_or_false }} {% endif %} +{%- if options.disable_serialization_buffer_check is defined %}, + "disable_serialization_buffer_check": {{ options.disable_serialization_buffer_check | ln.js.to_true_or_false }} +{% endif %} }