Skip to content

Commit

Permalink
Introduced new --disable-serialization-buffer-check option for C & …
Browse files Browse the repository at this point in the history
…CPP languages.

Allows to use a smaller buffers than otherwise it will be required. Serialization is still safe (no buffer overflows!) but it might fail during the operation with NUNAVUT_ERROR_SERIALIZATION_BUFFER_TOO_SMALL error.
  • Loading branch information
serges147 committed Dec 10, 2024
1 parent 8b67b5f commit a0ca830
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 6 deletions.
16 changes: 16 additions & 0 deletions src/nunavut/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 is known to be small,
and so much smaller buffers can be used (comparing to the maximum possible capacity).
"""
).lstrip(),
)

ln_opt_group.add_argument(
"--language-standard",
"-std",
Expand Down
4 changes: 4 additions & 0 deletions src/nunavut/cli/parsers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
9 changes: 7 additions & 2 deletions src/nunavut/lang/c/templates/serialization.j2
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,18 @@

{# ----------------------------------------------------------------------------------------------------------------- #}
{% 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 %}
const {{ typename_unsigned_length }} capacity_bytes = *inout_buffer_size_bytes;
if ((8U * ({{ typename_unsigned_bit_length }}) capacity_bytes) < {{ t.inner_type.bit_length_set.max }}UL)
{
return -NUNAVUT_ERROR_SERIALIZATION_BUFFER_TOO_SMALL;
}
{%- 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.
Expand Down Expand Up @@ -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) }}
Expand Down
11 changes: 7 additions & 4 deletions src/nunavut/lang/cpp/templates/serialization.j2
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 %}

Expand Down
2 changes: 2 additions & 0 deletions src/nunavut/lang/properties.json
Original file line number Diff line number Diff line change
Expand Up @@ -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})"
}
},
Expand Down Expand Up @@ -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})",
Expand Down
3 changes: 3 additions & 0 deletions test/gentest_nnvg/templates/Any.j2
Original file line number Diff line number Diff line change
Expand Up @@ -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 %}
}

0 comments on commit a0ca830

Please sign in to comment.