diff --git a/doc/website/release-notes/iceoryx-unreleased.md b/doc/website/release-notes/iceoryx-unreleased.md index e295e1bae58..094e6d66f04 100644 --- a/doc/website/release-notes/iceoryx-unreleased.md +++ b/doc/website/release-notes/iceoryx-unreleased.md @@ -52,6 +52,7 @@ - Create iceoryx version header for the C-binding [#1014](https://github.com/eclipse-iceoryx/iceoryx/issues/1014) - Create macros to deprecate header and code constructs [#2057](https://github.com/eclipse-iceoryx/iceoryx/issues/2057) - Switch to C++17 on all platforms [#2066](https://github.com/eclipse-iceoryx/iceoryx/issues/2066) +- Implement `unsafe_raw_access` in `iox::string` [#2040](https://github.com/eclipse-iceoryx/iceoryx/issues/2040) **Bugfixes:** diff --git a/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp b/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp index a6b6b6bd27e..05973344e7a 100644 --- a/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp +++ b/iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp @@ -19,6 +19,7 @@ #include "iceoryx_hoofs/testing/fatal_failure.hpp" #include "iox/string.hpp" #include "test.hpp" +#include namespace { @@ -643,6 +644,46 @@ TYPED_TEST(stringTyped_test, UnsafeAssignOfNullptrFails) EXPECT_THAT(this->testSubject.unsafe_assign(nullptr), Eq(false)); } +/// @note void unsafe_raw_access(const std::function& func) noexcept +TYPED_TEST(stringTyped_test, UnsafeRawAccessOfCStringOfSize0ResultsInSize0) +{ + ::testing::Test::RecordProperty("TEST_ID", "c1fcb14a-89ce-4c2c-8c9a-abc627adfbc3"); + this->testSubject.unsafe_raw_access([this](char* str, const uint64_t size, const uint64_t capacity) { + strcpy(str, ""); + EXPECT_THAT(size, this->testSubject.size()); + using MyString = typename TestFixture::stringType; + EXPECT_THAT(capacity, MyString::capacity()); + }); + EXPECT_THAT(this->testSubject.size(), Eq(0U)); + EXPECT_THAT(this->testSubject.c_str(), StrEq("")); +} + +TYPED_TEST(stringTyped_test, UnsafeRawAccessOfCStringOfSize1ResultsInSize1) +{ + ::testing::Test::RecordProperty("TEST_ID", "30f42371-52e1-450f-8bac-b3933ef6539b"); + this->testSubject.unsafe_raw_access([this](char* str, const uint64_t size, const uint64_t capacity) { + strcpy(str, "M"); + EXPECT_THAT(size, this->testSubject.size()); + using MyString = typename TestFixture::stringType; + EXPECT_THAT(capacity, MyString::capacity()); + }); + EXPECT_THAT(this->testSubject.size(), Eq(1U)); + EXPECT_THAT(this->testSubject.c_str(), StrEq("M")); +} + +TYPED_TEST(stringTyped_test, UnsafeRawAccessCStringOfSizeCapaResultsInSizeCapa) +{ + ::testing::Test::RecordProperty("TEST_ID", "343e1e43-5500-4255-899c-31f1109340f1"); + using MyString = typename TestFixture::stringType; + constexpr auto STRINGCAP = MyString::capacity(); + std::vector testCharstring(STRINGCAP, 'M'); + testCharstring.emplace_back('\0'); + this->testSubject.unsafe_raw_access( + [&testCharstring](char* str, const uint64_t, const uint64_t) { strcpy(str, testCharstring.data()); }); + EXPECT_THAT(this->testSubject.unsafe_assign(testCharstring.data()), Eq(true)); + EXPECT_THAT(this->testSubject.size(), Eq(STRINGCAP)); +} + /// @note template /// int64_t compare(const string& other) const noexcept TYPED_TEST(stringTyped_test, CompareEqStringsResultsInZero) diff --git a/iceoryx_hoofs/vocabulary/include/iox/detail/string.inl b/iceoryx_hoofs/vocabulary/include/iox/detail/string.inl index 5726ca4c983..ed0a4509d4c 100644 --- a/iceoryx_hoofs/vocabulary/include/iox/detail/string.inl +++ b/iceoryx_hoofs/vocabulary/include/iox/detail/string.inl @@ -238,6 +238,22 @@ inline bool string::unsafe_assign(const char* const str) noexcept return true; } +template +inline void +string::unsafe_raw_access(const iox::function& func) noexcept +{ + func(m_rawstring, m_rawstringSize, Capacity); + + const uint64_t strSize{strnlen(m_rawstring, Capacity + 1U)}; + if (Capacity < strSize) + { + IOX_LOG(FATAL, "unsafe_raw_access failed. Data wrote outside the maximun string capacity of " << Capacity); + return; + } + m_rawstringSize = strSize; +} + + template template inline IsStringOrCharArray string::compare(const T& other) const noexcept diff --git a/iceoryx_hoofs/vocabulary/include/iox/string.hpp b/iceoryx_hoofs/vocabulary/include/iox/string.hpp index 16f2327cae9..3449f83a9ed 100644 --- a/iceoryx_hoofs/vocabulary/include/iox/string.hpp +++ b/iceoryx_hoofs/vocabulary/include/iox/string.hpp @@ -19,6 +19,7 @@ #include "iox/detail/string_internal.hpp" #include "iox/detail/string_type_traits.hpp" +#include "iox/function.hpp" #include "iox/log/logstream.hpp" #include "iox/optional.hpp" #include "iox/type_traits.hpp" @@ -423,6 +424,13 @@ class string final template IsStringOrCharArrayOrChar unsafe_append(const T& str) noexcept; + /// @brief direct access to the string's raw pointer. The access resizes the data correctly after the function call. + /// If the data written in the function exceeds the capacity, and the code does not segfault beforehand due to an + /// invalid access, a FATAL error occurs. + /// + /// @param [in] function composed by the raw data, current string size and the capacity + void unsafe_raw_access(const iox::function& func) noexcept; + /// @brief inserts a iox::string or char array in the range [str[0], str[count]) at position pos. The insertion /// fails if the string capacity would be exceeded or pos is greater than the string size or count is greater than /// the string to be inserted.