Skip to content

Commit

Permalink
iox-#2040: add unsafe_raw_access to iox::string
Browse files Browse the repository at this point in the history
Introduce a function to directly access the string pointer. This
function enables checking the string's size and capacity after each
call, minimizing the risk of encountering invalid strings.

Signed-off-by: Luca Bartoli <[email protected]>
  • Loading branch information
lucabart97 committed Nov 18, 2023
1 parent 51a018a commit f9e3b0a
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 0 deletions.
1 change: 1 addition & 0 deletions doc/website/release-notes/iceoryx-unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:**

Expand Down
41 changes: 41 additions & 0 deletions iceoryx_hoofs/test/moduletests/test_vocabulary_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "iceoryx_hoofs/testing/fatal_failure.hpp"
#include "iox/string.hpp"
#include "test.hpp"
#include <cstring>

namespace
{
Expand Down Expand Up @@ -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<void(char*, const uint64_t, const uint64_t)>& 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<char> 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 <uint64_t N>
/// int64_t compare(const string<N>& other) const noexcept
TYPED_TEST(stringTyped_test, CompareEqStringsResultsInZero)
Expand Down
16 changes: 16 additions & 0 deletions iceoryx_hoofs/vocabulary/include/iox/detail/string.inl
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,22 @@ inline bool string<Capacity>::unsafe_assign(const char* const str) noexcept
return true;
}

template <uint64_t Capacity>
inline void
string<Capacity>::unsafe_raw_access(const iox::function<void(char*, const uint64_t, const uint64_t)>& 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 <uint64_t Capacity>
template <typename T>
inline IsStringOrCharArray<T, int64_t> string<Capacity>::compare(const T& other) const noexcept
Expand Down
8 changes: 8 additions & 0 deletions iceoryx_hoofs/vocabulary/include/iox/string.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -423,6 +424,13 @@ class string final
template <typename T>
IsStringOrCharArrayOrChar<T, bool> 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<void(char*, const uint64_t, const uint64_t)>& 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.
Expand Down

0 comments on commit f9e3b0a

Please sign in to comment.