Skip to content

Commit

Permalink
Fix for issue #338
Browse files Browse the repository at this point in the history
Fixing incorrect runtime asserts in generated C serialization code
  • Loading branch information
thirtytwobits committed Jun 6, 2024
1 parent bb8ff57 commit 118e86e
Show file tree
Hide file tree
Showing 7 changed files with 256 additions and 46 deletions.
4 changes: 2 additions & 2 deletions src/nunavut/lang/c/support/serialization.j2
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,10 @@ static inline void nunavutCopyBits(void* const dst,
{{ typename_unsigned_bit_length }} dst_off = dst_offset_bits;
const {{ typename_unsigned_bit_length }} last_bit = src_off + length_bits;
{{ assert(
'((psrc < pdst) ? ((uintptr_t)(psrc + ((src_offset_bits + length_bits + 8U) / 8U)) <= (uintptr_t)pdst) : 1)'
'((psrc < pdst) ? ((uintptr_t)(psrc + ((src_offset_bits + length_bits + 7U) / 8U)) <= (uintptr_t)pdst) : 1)'
) }}
{{ assert(
'((psrc > pdst) ? ((uintptr_t)(pdst + ((dst_offset_bits + length_bits + 8U) / 8U)) <= (uintptr_t)psrc) : 1)'
'((psrc > pdst) ? ((uintptr_t)(pdst + ((dst_offset_bits + length_bits + 7U) / 8U)) <= (uintptr_t)psrc) : 1)'
) }}
while (last_bit > src_off)
{
Expand Down
54 changes: 31 additions & 23 deletions verification/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,20 @@ else()
set(NUNAVUT_VERIFICATION_LANG "unspecified" CACHE STRING "The Nunavut output language to verify.")
endif()

if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp")
set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/cpp")
message(STATUS "NUNAVUT_VERIFICATION_LANG is C++ (${NUNAVUT_VERIFICATION_LANG})")
message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}")
elseif(NUNAVUT_VERIFICATION_LANG STREQUAL "c")
set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/c")
message(STATUS "NUNAVUT_VERIFICATION_LANG is C (${NUNAVUT_VERIFICATION_LANG})")
message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}")
else()
message(FATAL_ERROR "Unknown or no verification language (${NUNAVUT_VERIFICATION_LANG}). Try cmake -DNUNAVUT_VERIFICATION_LANG:string=[cpp|c]")
endif()

string(TOLOWER ${NUNAVUT_VERIFICATION_LANG} LOCAL_VERIFICATION_LANG)

set(NUNAVUT_SUBMODULES_ROOT "${NUNAVUT_PROJECT_ROOT}/submodules" CACHE STRING "The path to git submodules for the project.")

if(NOT DEFINED NUNAVUT_VERIFICATION_LANG_STANDARD)
Expand All @@ -47,6 +61,12 @@ if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp" AND NOT NUNAVUT_VERIFICATION_LANG_S
set(NUNAVUT_VERIFICATION_LANG_STANDARD "c++20")
endif()

if (NUNAVUT_VERIFICATION_LANG STREQUAL "c" AND NOT NUNAVUT_VERIFICATION_LANG_STANDARD)
set(NUNAVUT_VERIFICATION_LANG_STANDARD "c11")
endif()

message(STATUS "NUNAVUT_VERIFICATION_LANG_STANDARD is ${NUNAVUT_VERIFICATION_LANG_STANDARD}")

if(NOT DEFINED NUNAVUT_VERIFICATION_TARGET_ENDIANNESS)
set(NUNAVUT_VERIFICATION_TARGET_ENDIANNESS "any" CACHE STRING "The endianess for the target verification architecture.")
endif()
Expand All @@ -63,20 +83,6 @@ if(NOT DEFINED NUNAVUT_VERIFICATION_OVR_VAR_ARRAY_ENABLE)
set(NUNAVUT_VERIFICATION_OVR_VAR_ARRAY_ENABLE OFF CACHE BOOL "Enable or disable override variable array capacity in generated support code.")
endif()

if (NUNAVUT_VERIFICATION_LANG STREQUAL "cpp")
set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/cpp")
message(STATUS "NUNAVUT_VERIFICATION_LANG is C++ (${NUNAVUT_VERIFICATION_LANG})")
message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}")
elseif(NUNAVUT_VERIFICATION_LANG STREQUAL "c")
set(NUNAVUT_VERIFICATION_ROOT "${CMAKE_SOURCE_DIR}/c")
message(STATUS "NUNAVUT_VERIFICATION_LANG is C (${NUNAVUT_VERIFICATION_LANG})")
message(STATUS "Setting NUNAVUT_VERIFICATION_ROOT = ${NUNAVUT_VERIFICATION_ROOT}")
else()
message(FATAL_ERROR "Unknown or no verification language (${NUNAVUT_VERIFICATION_LANG}). Try cmake -DNUNAVUT_VERIFICATION_LANG:string=[cpp|c]")
endif()

string(TOLOWER ${NUNAVUT_VERIFICATION_LANG} LOCAL_VERIFICATION_LANG)

if(DEFINED ENV{NUNAVUT_FLAGSET})
set(NUNAVUT_FLAGSET "$ENV{NUNAVUT_FLAGSET}")
message(STATUS "Using ${NUNAVUT_FLAGSET} from environment for NUNAVUT_FLAGSET")
Expand Down Expand Up @@ -380,7 +386,7 @@ function(runTestCpp)
target_include_directories(${NATIVE_TEST_NAME} PUBLIC "${NUNAVUT_PROJECT_ROOT}/submodules/CETL/include")
define_native_test_run(TEST_NAME ${NATIVE_TEST_NAME} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR})
define_native_test_run_with_lcov(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/\\*)
define_natve_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR})
define_native_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR})
list(APPEND ALL_TESTS "run_${NATIVE_TEST_NAME}")
list(APPEND ALL_TESTS_WITH_LCOV "run_${NATIVE_TEST_NAME}_with_lcov")
list(APPEND ALL_TEST_COVERAGE "--add-tracefile")
Expand All @@ -402,21 +408,21 @@ endif()

function(runTestC)
set(options "")
set(oneValueArgs TEST_FILE)
set(oneValueArgs TEST_FILE FRAMEWORK)
set(multiValueArgs LINK LANGUAGE_FLAVORS)
cmake_parse_arguments(runTestC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

# Skip tests not relevant to the specified language standard
list(FIND runTestC_LANGUAGE_FLAVORS "${NUNAVUT_VERIFICATION_LANG_STANDARD}" FIND_INDEX)
if (${FIND_INDEX} GREATER -1)
if (${FIND_INDEX} EQUAL -1)
message(STATUS "Skipping ${runTestC_TEST_FILE}")
return()
endif()

set(NATIVE_TEST "${NUNAVUT_VERIFICATION_ROOT}/suite/${runTestC_TEST_FILE}")
get_filename_component(NATIVE_TEST_NAME ${NATIVE_TEST} NAME_WE)

define_native_unit_test(FRAMEWORK "unity"
define_native_unit_test(FRAMEWORK ${runTestC_FRAMEWORK}
TEST_NAME ${NATIVE_TEST_NAME}
TEST_SOURCE ${NATIVE_TEST}
OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR}
Expand All @@ -425,7 +431,7 @@ function(runTestC)
)
define_native_test_run(TEST_NAME ${NATIVE_TEST_NAME} OUTDIR ${NUNAVUT_VERIFICATIONS_BINARY_DIR})
define_native_test_run_with_lcov(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/\\*)
define_natve_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR})
define_native_test_coverage(${NATIVE_TEST_NAME} ${NUNAVUT_VERIFICATIONS_BINARY_DIR})
list(APPEND ALL_TESTS "run_${NATIVE_TEST_NAME}")
list(APPEND ALL_TESTS_WITH_LCOV "run_${NATIVE_TEST_NAME}_with_lcov")
list(APPEND ALL_TEST_COVERAGE "--add-tracefile")
Expand All @@ -437,10 +443,12 @@ endfunction()

if (NUNAVUT_VERIFICATION_LANG STREQUAL "c")
runTestCpp(TEST_FILE test_canard.cpp LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11)
runTestC( TEST_FILE test_constant.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11)
runTestC( TEST_FILE test_override_variable_array_capacity.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11)
runTestC( TEST_FILE test_serialization.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11)
runTestC( TEST_FILE test_support.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11)
runTestCpp(TEST_FILE test_support_assert.cpp LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11)
runTestC( TEST_FILE test_constant.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity")
runTestC( TEST_FILE test_override_variable_array_capacity.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity")
runTestC( TEST_FILE test_serialization.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity")
runTestC( TEST_FILE test_support.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "unity")
runTestC( TEST_FILE test_simple.c LINK dsdl-regulated dsdl-test LANGUAGE_FLAVORS c11 FRAMEWORK "none")
endif()

# +---------------------------------------------------------------------------+
Expand Down
134 changes: 134 additions & 0 deletions verification/c/suite/test_simple.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright (c) 2020 OpenCyphal Development Team.
// This software is distributed under the terms of the MIT License.

#include <regulated/basics/Struct__0_1.h>
#include <regulated/basics/Union_0_1.h>
#include <regulated/basics/Primitive_0_1.h>
#include <regulated/basics/PrimitiveArrayFixed_0_1.h>
#include <regulated/basics/PrimitiveArrayVariable_0_1.h>
#include <regulated/delimited/A_1_0.h>
#include <regulated/delimited/A_1_1.h>
#include <uavcan/pnp/NodeIDAllocationData_2_0.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>

#define TEST_ASSERT_EQUAL(A, B) do {\
if ((A) != (B)) { \
abort(); \
} \
} while(0)

#define TEST_ASSERT_TRUE(A) TEST_ASSERT_EQUAL(A, true)

/// A test to run with no test framework linked in. This allows some sanity checking but mostly is useful to support
/// analysis or instrumentation of the code while debugging.
static void testStructDelimited(void)
{
regulated_delimited_A_1_0 obj;
regulated_delimited_A_1_0_initialize_(&obj);
regulated_delimited_A_1_0_select_del_(&obj);
regulated_delimited_A_1_0_select_del_(NULL); // No action.
obj.del.var.count = 2;
obj.del.var.elements[0].a.count = 2;
obj.del.var.elements[0].a.elements[0] = 1;
obj.del.var.elements[0].a.elements[1] = 2;
obj.del.var.elements[0].b = 0;
obj.del.var.elements[1].a.count = 1;
obj.del.var.elements[1].a.elements[0] = 3;
obj.del.var.elements[1].a.elements[1] = 123; // ignored
obj.del.var.elements[1].b = 4;
obj.del.fix.count = 1;
obj.del.fix.elements[0].a[0] = 5;
obj.del.fix.elements[0].a[1] = 6;

const uint8_t reference[] = {
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
0x01U, 0x17U, 0x00U, 0x00U, 0x00U, 0x02U, 0x04U, 0x00U, 0x00U, 0x00U, 0x02U, 0x01U, 0x02U, 0x00U, 0x03U, 0x00U,
0x00U, 0x00U, 0x01U, 0x03U, 0x04U, 0x01U, 0x02U, 0x00U, 0x00U, 0x00U, 0x05U, 0x06U,
// END OF SERIALIZED REPRESENTATION
0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU, 0xAAU,
0xAAU,
};
static_assert(sizeof(reference) == regulated_delimited_A_1_0_SERIALIZATION_BUFFER_SIZE_BYTES_, "");

uint8_t buf[1024] = {0};
(void) memset(&buf[0], 0xAAU, sizeof(buf)); // Fill out the canaries
size_t size = sizeof(buf);
TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_serialize_(&obj, &buf[0], &size));
TEST_ASSERT_EQUAL(28U, size);

// Deserialize back from the reference using the same type and compare the field values.
regulated_delimited_A_1_0_initialize_(&obj); // Erase prior state.
size = sizeof(reference);
TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_deserialize_(&obj, &reference[0], &size));
TEST_ASSERT_EQUAL(28U, size);
TEST_ASSERT_TRUE(regulated_delimited_A_1_0_is_del_(&obj));
TEST_ASSERT_EQUAL(2, obj.del.var.count);
TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.count);
TEST_ASSERT_EQUAL(1, obj.del.var.elements[0].a.elements[0]);
TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.elements[1]);
TEST_ASSERT_EQUAL(0, obj.del.var.elements[0].b);
TEST_ASSERT_EQUAL(1, obj.del.var.elements[1].a.count);
TEST_ASSERT_EQUAL(3, obj.del.var.elements[1].a.elements[0]);
TEST_ASSERT_EQUAL(4, obj.del.var.elements[1].b);
TEST_ASSERT_EQUAL(1, obj.del.fix.count);
TEST_ASSERT_EQUAL(5, obj.del.fix.elements[0].a[0]);
TEST_ASSERT_EQUAL(6, obj.del.fix.elements[0].a[1]);

// Deserialize using a different type to test extensibility enabled by delimited serialization.
regulated_delimited_A_1_1 dif;
size = sizeof(reference);
TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_1_deserialize_(&dif, &reference[0], &size));
TEST_ASSERT_EQUAL(28U, size);
TEST_ASSERT_TRUE(regulated_delimited_A_1_1_is_del_(&dif));
TEST_ASSERT_EQUAL(2, dif.del.var.count);
TEST_ASSERT_EQUAL(2, dif.del.var.elements[0].a.count);
TEST_ASSERT_EQUAL(1, dif.del.var.elements[0].a.elements[0]);
TEST_ASSERT_EQUAL(2, dif.del.var.elements[0].a.elements[1]);
// b implicitly truncated away
TEST_ASSERT_EQUAL(1, dif.del.var.elements[1].a.count);
TEST_ASSERT_EQUAL(3, dif.del.var.elements[1].a.elements[0]);
// b implicitly truncated away
TEST_ASSERT_EQUAL(1, dif.del.fix.count);
TEST_ASSERT_EQUAL(5, dif.del.fix.elements[0].a[0]);
TEST_ASSERT_EQUAL(6, dif.del.fix.elements[0].a[1]);
TEST_ASSERT_EQUAL(0, dif.del.fix.elements[0].a[2]); // 3rd element is implicitly zero-extended
TEST_ASSERT_EQUAL(0, dif.del.fix.elements[0].b); // b is implicitly zero-extended

// Reverse version switch -- serialize v1.1 and then deserialize back using v1.0.
dif.del.var.count = 1;
dif.del.var.elements[0].a.count = 2;
dif.del.var.elements[0].a.elements[0] = 11;
dif.del.var.elements[0].a.elements[1] = 22;
dif.del.fix.count = 2;
dif.del.fix.elements[0].a[0] = 5;
dif.del.fix.elements[0].a[1] = 6;
dif.del.fix.elements[0].a[2] = 7;
dif.del.fix.elements[0].b = 8;
dif.del.fix.elements[1].a[0] = 100;
dif.del.fix.elements[1].a[1] = 200;
dif.del.fix.elements[1].a[2] = 123;
dif.del.fix.elements[1].b = 99;
size = sizeof(buf);
TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_1_serialize_(&dif, &buf[0], &size));
TEST_ASSERT_EQUAL(30U, size); // the reference size was computed by hand
TEST_ASSERT_EQUAL(0, regulated_delimited_A_1_0_deserialize_(&obj, &buf[0], &size));
TEST_ASSERT_TRUE(regulated_delimited_A_1_0_is_del_(&obj));
TEST_ASSERT_EQUAL(1, obj.del.var.count);
TEST_ASSERT_EQUAL(2, obj.del.var.elements[0].a.count);
TEST_ASSERT_EQUAL(11, obj.del.var.elements[0].a.elements[0]);
TEST_ASSERT_EQUAL(22, obj.del.var.elements[0].a.elements[1]);
TEST_ASSERT_EQUAL(0, obj.del.var.elements[0].b); // b is implicitly zero-extended
TEST_ASSERT_EQUAL(2, obj.del.fix.count);
TEST_ASSERT_EQUAL(5, obj.del.fix.elements[0].a[0]); // 3rd is implicitly truncated, b is implicitly truncated
TEST_ASSERT_EQUAL(6, obj.del.fix.elements[0].a[1]);
TEST_ASSERT_EQUAL(100, obj.del.fix.elements[1].a[0]); // 3rd is implicitly truncated, b is implicitly truncated
TEST_ASSERT_EQUAL(200, obj.del.fix.elements[1].a[1]);
}

int main(void)
{
testStructDelimited();
return 0;
}
44 changes: 35 additions & 9 deletions verification/c/suite/test_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,30 @@ static void testNunavutCopyBits(void)
}
}

static void testNunavutCopyAdjacentBitsForward(void)
{
uintptr_t data[2];
uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul));
const size_t word_size_bytes = sizeof(uintptr_t);
const size_t word_size_bits = word_size_bytes * 8u;
memset(&data[0], 0xFF, sizeof(uintptr_t));
memset(&data[1], 0x00, sizeof(uintptr_t));
nunavutCopyBits(&data[1], word_size_bits - 1, 1, &data[0], 1);
TEST_ASSERT_EQUAL(expected, data[1]);
}

static void testNunavutCopyAdjacentBitsBackward(void)
{
uintptr_t data[2];
uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul));
const size_t word_size_bytes = sizeof(uintptr_t);
const size_t word_size_bits = word_size_bytes * 8u;
memset(&data[1], 0xFF, sizeof(uintptr_t));
memset(&data[0], 0x00, sizeof(uintptr_t));
nunavutCopyBits(&data[0], word_size_bits - 1, 1, &data[1], 1);
TEST_ASSERT_EQUAL(expected, data[0]);
}

static void testNunavutCopyBitsWithAlignedOffset(void)
{
const uint8_t src[] = { 1, 2, 3, 4, 5 };
Expand Down Expand Up @@ -502,7 +526,7 @@ static void helperPackUnpack(float source_value, uint16_t compare_mask, size_t i
for(size_t i = 0; i < iterations; ++i)
{
repacked = nunavutFloat16Pack(nunavutFloat16Unpack(repacked));
snprintf(message_buffer, 128, "source_value=%f, compare_mask=%X, i=%zu", source_value, compare_mask, i);
snprintf(message_buffer, 128, "source_value=%f, compare_mask=%X, i=%zu", (double)source_value, compare_mask, i);
TEST_ASSERT_EQUAL_HEX16_MESSAGE(packed & compare_mask, repacked & compare_mask, message_buffer);
}
}
Expand Down Expand Up @@ -727,20 +751,20 @@ static void testNunavutSetF64(void)
helperAssertSerFloat64SameAsIEEE(-3.141592653589793, buffer);

memset(buffer, 0, sizeof(buffer));
nunavutSetF64(buffer, sizeof(buffer), 0, -NAN);
helperAssertSerFloat64SameAsIEEE(-NAN, buffer);
nunavutSetF64(buffer, sizeof(buffer), 0, -(double)NAN);
helperAssertSerFloat64SameAsIEEE(-(double)NAN, buffer);

memset(buffer, 0, sizeof(buffer));
nunavutSetF64(buffer, sizeof(buffer), 0, NAN);
helperAssertSerFloat64SameAsIEEE(NAN, buffer);
nunavutSetF64(buffer, sizeof(buffer), 0, (double)NAN);
helperAssertSerFloat64SameAsIEEE((double)NAN, buffer);

memset(buffer, 0, sizeof(buffer));
nunavutSetF64(buffer, sizeof(buffer), 0, INFINITY);
helperAssertSerFloat64SameAsIEEE(INFINITY, buffer);
nunavutSetF64(buffer, sizeof(buffer), 0, (double)INFINITY);
helperAssertSerFloat64SameAsIEEE((double)INFINITY, buffer);

memset(buffer, 0, sizeof(buffer));
nunavutSetF64(buffer, sizeof(buffer), 0, -INFINITY);
helperAssertSerFloat64SameAsIEEE(-INFINITY, buffer);
nunavutSetF64(buffer, sizeof(buffer), 0, -(double)INFINITY);
helperAssertSerFloat64SameAsIEEE(-(double)INFINITY, buffer);
}

// +--------------------------------------------------------------------------+
Expand All @@ -762,6 +786,8 @@ int main(void)
UNITY_BEGIN();

RUN_TEST(testNunavutCopyBits);
RUN_TEST(testNunavutCopyAdjacentBitsForward);
RUN_TEST(testNunavutCopyAdjacentBitsBackward);
RUN_TEST(testNunavutCopyBitsWithAlignedOffset);
RUN_TEST(testNunavutCopyBitsWithUnalignedOffset);
RUN_TEST(testNunavutSaturateBufferFragmentBitLength);
Expand Down
48 changes: 48 additions & 0 deletions verification/c/suite/test_support_assert.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/// @file
/// Googletest death tests for serialization.h
///
/// @copyright
/// Copyright (C) OpenCyphal Development Team <opencyphal.org>
/// Copyright Amazon.com Inc. or its affiliates.
/// SPDX-License-Identifier: MIT
///

#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "nunavut/support/serialization.h"

// +----------------------------------------------------------------------+
// | ☠️ DEATH TESTS ☠️
// +----------------------------------------------------------------------+
#ifndef NDEBUG

// covers https://github.com/OpenCyphal/nunavut/issues/338
TEST(NunavutSupportCopyBitsDeathTest, nunavutCopyBits)
{
uintptr_t data[2];
uintptr_t expected = (1ul << ((sizeof(expected) * 8ul) - 1ul));
const size_t word_size_bytes = sizeof(uintptr_t);
const size_t word_size_bits = word_size_bytes * 8u;
memset(&data[1], 0xFF, sizeof(uintptr_t));
memset(&data[0], 0x00, sizeof(uintptr_t));

for(size_t i = 0; i < word_size_bits; ++i) {
nunavutCopyBits(&data[0], i, 1, &data[1], 1);
}

ASSERT_DEATH(
nunavutCopyBits(&data[0], word_size_bits, 1, &data[1], 1),
"(psrc > pdst)"
);

for(size_t i = 0; i < word_size_bits; ++i) {
nunavutCopyBits(&data[1], 1, i, &data[0], 1);
}

ASSERT_DEATH(
nunavutCopyBits(&data[1], 1, word_size_bits, &data[0], 1),
"(psrc < pdst)"
);
}

#endif
Loading

0 comments on commit 118e86e

Please sign in to comment.