Hardened mem_set and mem_char parameter requirements

This commit is contained in:
John Wellbelove 2025-05-29 20:14:37 +01:00
parent 09acfca5a6
commit e87e24557f
2 changed files with 111 additions and 68 deletions

View File

@ -2286,12 +2286,15 @@ namespace etl
/// \return A pointer to the destination.
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<T*>::value_type>::value, T*>::type
mem_copy(const T* sb, const T* se, T* db) ETL_NOEXCEPT
T* mem_copy(const T* sb, const T* se, T* db) ETL_NOEXCEPT
{
return reinterpret_cast<T*>(memcpy(reinterpret_cast<void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * static_cast<size_t>(se - sb)));
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "Cannot mem_copy a non trivially copyable type");
memcpy(reinterpret_cast<void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * static_cast<size_t>(se - sb));
return db;
}
//***************************************************************************
@ -2302,12 +2305,15 @@ namespace etl
/// \param destination begin
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<T*>::value_type>::value, T*>::type
mem_copy(const T* sb, size_t n, T* db) ETL_NOEXCEPT
T* mem_copy(const T* sb, size_t n, T* db) ETL_NOEXCEPT
{
return reinterpret_cast<T*>(memcpy(reinterpret_cast<void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * n));
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "Cannot mem_copy a non trivially copyable type");
memcpy(reinterpret_cast<void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * n);
return db;
}
//***************************************************************************
@ -2318,12 +2324,15 @@ namespace etl
/// \param destination begin
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<T*>::value_type>::value, T*>::type
mem_move(const T* sb, const T* se, T* db) ETL_NOEXCEPT
T* mem_move(const T* sb, const T* se, T* db) ETL_NOEXCEPT
{
return reinterpret_cast<T*>(memmove(reinterpret_cast<void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * static_cast<size_t>(se - sb)));
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "Cannot mem_move a non trivially copyable type");
memmove(reinterpret_cast<void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(T) * static_cast<size_t>(se - sb));
return db;
}
//***************************************************************************
@ -2334,12 +2343,15 @@ namespace etl
/// \param destination begin
//***************************************************************************
template <typename T>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<T*>::value_type>::value, T*>::type
mem_move(const T* sb, size_t n, T* db) ETL_NOEXCEPT
T* mem_move(const T* sb, size_t n, T* db) ETL_NOEXCEPT
{
return reinterpret_cast<T*>(memmove(reinterpret_cast<void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * n));
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "Cannot mem_move a non trivially copyable type");
memmove(reinterpret_cast<void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * n);
return db;
}
//***************************************************************************
@ -2348,17 +2360,18 @@ namespace etl
/// \param se Source end
/// \param db Destination begin
/// \return < 0 The first byte that does not match in both memory blocks has a lower value in 'sb' than in 'db' when evaluated as unsigned char values.
/// 0 The contents of both memory blocks are equal
/// > 0 The first byte that does not match in both memory blocks has a greater value in 'sb' than in 'db' when evaluated as unsigned char values.
/// 0 The contents of both memory blocks are equal
/// > 0 The first byte that does not match in both memory blocks has a greater value in 'sb' than in 'db' when evaluated as unsigned char values.
//***************************************************************************
template <typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<T*>::value_type>::value, int>::type
mem_compare(const T* sb, const T* se, const T* db) ETL_NOEXCEPT
int mem_compare(const T* sb, const T* se, const T* db) ETL_NOEXCEPT
{
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "Cannot mem_compare a non trivially copyable type");
return memcmp(reinterpret_cast<const void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * static_cast<size_t>(se - sb));
sizeof(T) * static_cast<size_t>(se - sb));
}
//***************************************************************************
@ -2367,49 +2380,64 @@ namespace etl
/// \param n Source length
/// \param db Destination begin
/// \return < 0 The first byte that does not match in both memory blocks has a lower value in 'sb' than in 'db' when evaluated as unsigned char values.
/// 0 The contents of both memory blocks are equal
/// > 0 The first byte that does not match in both memory blocks has a greater value in 'sb' than in 'db' when evaluated as unsigned char values.
/// 0 The contents of both memory blocks are equal
/// > 0 The first byte that does not match in both memory blocks has a greater value in 'sb' than in 'db' when evaluated as unsigned char values.
//***************************************************************************
template <typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<T*>::value_type>::value, int>::type
mem_compare(const T* sb, size_t n, const T* db) ETL_NOEXCEPT
int mem_compare(const T* sb, size_t n, const T* db) ETL_NOEXCEPT
{
ETL_STATIC_ASSERT(etl::is_trivially_copyable<T>::value, "Cannot mem_compare a non trivially copyable type");
return memcmp(reinterpret_cast<const void*>(db),
reinterpret_cast<const void*>(sb),
sizeof(typename etl::iterator_traits<T*>::value_type) * n);
sizeof(T) * n);
}
//***************************************************************************
/// Template wrapper for memset.
/// \param db Destination begin.
/// \param de Destination end.
/// \param value The value to set each character of the memory region.
/// \param value The value to set each byte of the memory region.
/// \return The destination
//***************************************************************************
template <typename TPointer, typename T>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, TPointer>::type
typename etl::enable_if<etl::is_pointer<TPointer>::value &&
!etl::is_const<TPointer>::value &&
etl::is_integral<T>::value &&
sizeof(T) == 1, TPointer>::type
mem_set(TPointer db, const TPointer de, T value) ETL_NOEXCEPT
{
return reinterpret_cast<TPointer>(memset(reinterpret_cast<void*>(db),
static_cast<char>(value),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * static_cast<size_t>(de - db)));
ETL_STATIC_ASSERT(etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, "Cannot mem_set a non trivially copyable type");
memset(reinterpret_cast<void*>(db),
static_cast<char>(value),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * static_cast<size_t>(de - db));
return db;
}
//***************************************************************************
/// Template wrapper for memset.
/// \param db Destination begin.
/// \param n Destination length.
/// \param value The value to set each character of the memory region.
/// \param value The value to set each byte of the memory region.
/// \return The destination
//***************************************************************************
template <typename TPointer, typename T>
typename etl::enable_if<etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, TPointer>::type
typename etl::enable_if<etl::is_pointer<TPointer>::value &&
!etl::is_const<TPointer>::value &&
etl::is_integral<T>::value &&
sizeof(T) == 1, TPointer>::type
mem_set(TPointer db, size_t n, T value) ETL_NOEXCEPT
{
return reinterpret_cast<TPointer>(memset(reinterpret_cast<void*>(db),
static_cast<char>(value),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * n));
ETL_STATIC_ASSERT(etl::is_trivially_copyable<typename etl::iterator_traits<TPointer>::value_type>::value, "Cannot mem_set a non trivially copyable type");
memset(reinterpret_cast<void*>(db),
static_cast<char>(value),
sizeof(typename etl::iterator_traits<TPointer>::value_type) * n);
return db;
}
//***************************************************************************
@ -2421,7 +2449,10 @@ namespace etl
//***************************************************************************
template <typename TPointer, typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_pointer<TPointer>::value && !etl::is_const<typename etl::remove_pointer<TPointer>::type>::value, char*>::type
typename etl::enable_if<etl::is_pointer<TPointer>::value &&
!etl::is_const<typename etl::remove_pointer<TPointer>::type>::value &&
etl::is_integral<T>::value &&
sizeof(T) == 1, char*>::type
mem_char(TPointer sb, TPointer se, T value) ETL_NOEXCEPT
{
void* result = memchr(reinterpret_cast<void*>(sb),
@ -2440,7 +2471,10 @@ namespace etl
//***************************************************************************
template <typename TPointer, typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_pointer<TPointer>::value && etl::is_const<typename etl::remove_pointer<TPointer>::type>::value, const char*>::type
typename etl::enable_if<etl::is_pointer<TPointer>::value &&
etl::is_const<typename etl::remove_pointer<TPointer>::type>::value &&
etl::is_integral<T>::value &&
sizeof(T) == 1, const char*>::type
mem_char(TPointer sb, TPointer se, T value) ETL_NOEXCEPT
{
const void* result = memchr(reinterpret_cast<const void*>(sb),
@ -2459,7 +2493,10 @@ namespace etl
//***************************************************************************
template <typename TPointer, typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_pointer<TPointer>::value && !etl::is_const<typename etl::remove_pointer<TPointer>::type>::value, char*>::type
typename etl::enable_if<etl::is_pointer<TPointer>::value &&
!etl::is_const<typename etl::remove_pointer<TPointer>::type>::value &&
etl::is_integral<T>::value &&
sizeof(T) == 1, char*>::type
mem_char(TPointer sb, size_t n, T value) ETL_NOEXCEPT
{
void* result = memchr(reinterpret_cast<void*>(sb),
@ -2478,7 +2515,10 @@ namespace etl
//***************************************************************************
template <typename TPointer, typename T>
ETL_NODISCARD
typename etl::enable_if<etl::is_pointer<TPointer>::value && etl::is_const<typename etl::remove_pointer<TPointer>::type>::value, const char*>::type
typename etl::enable_if<etl::is_pointer<TPointer>::value &&
etl::is_const<typename etl::remove_pointer<TPointer>::type>::value &&
etl::is_integral<T>::value &&
sizeof(T) == 1, const char*>::type
mem_char(TPointer sb, size_t n, T value) ETL_NOEXCEPT
{
const void* result = memchr(reinterpret_cast<const void*>(sb),

View File

@ -1176,9 +1176,9 @@ namespace
uint32_t src[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t dst[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
etl::mem_copy(src, src + 8, dst);
uint32_t* result = etl::mem_copy(src, src + 8, dst);
CHECK(std::equal(src, src + 8, dst));
CHECK(result == dst);
}
//*************************************************************************
@ -1187,9 +1187,9 @@ namespace
const uint32_t src[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t dst[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
etl::mem_copy(src, src + 8, dst);
uint32_t* result = etl::mem_copy(src, src + 8, dst);
CHECK(std::equal(src, src + 8, dst));
CHECK(result == dst);
}
//*************************************************************************
@ -1198,8 +1198,9 @@ namespace
uint32_t src[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t dst[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
etl::mem_copy(src, 8, dst);
uint32_t* result = etl::mem_copy(src, 8, dst);
CHECK(std::equal(src, src + 8, dst));
CHECK(result == dst);
}
//*************************************************************************
@ -1208,8 +1209,9 @@ namespace
const uint32_t src[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t dst[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
etl::mem_copy(src, 8, dst);
uint32_t* result = etl::mem_copy(src, 8, dst);
CHECK(std::equal(src, src + 8, dst));
CHECK(result == dst);
}
//*************************************************************************
@ -1218,9 +1220,9 @@ namespace
uint32_t expected[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t data[12] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201, 0, 0, 0, 0 };
etl::mem_move(data, data + 8, data + 4);
uint32_t* result = etl::mem_move(data, data + 8, data + 4);
CHECK(std::equal(expected, expected + 8, data + 4));
CHECK(result == data + 4);
}
//*************************************************************************
@ -1231,9 +1233,9 @@ namespace
const uint32_t* data_begin = &data[0];
const uint32_t* data_end = &data[8];
etl::mem_move(data_begin, data_end, data + 4);
uint32_t* result = etl::mem_move(data_begin, data_end, data + 4);
CHECK(std::equal(expected, expected + 8, data + 4));
CHECK(result == data + 4);
}
//*************************************************************************
@ -1242,9 +1244,9 @@ namespace
uint32_t expected[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t data[12] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201, 0, 0, 0, 0 };
etl::mem_move(data, 8, data + 4);
uint32_t* result = etl::mem_move(data, 8, data + 4);
CHECK(std::equal(expected, expected + 8, data + 4));
CHECK(result == data + 4);
}
//*************************************************************************
@ -1253,9 +1255,10 @@ namespace
uint32_t expected[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 };
uint32_t data[12] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201, 0, 0, 0, 0 };
const uint32_t* data_begin = &data[0];
etl::mem_move(data_begin, 8, data + 4);
uint32_t* result = etl::mem_move(data_begin, 8, data + 4);
CHECK(std::equal(expected, expected + 8, data + 4));
CHECK(result == data + 4);
}
//*************************************************************************
@ -1342,7 +1345,7 @@ namespace
uint32_t data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint32_t expected[8] = { 0, 0x5A5A5A5A, 0x5A5A5A5A, 0x5A5A5A5A, 0x5A5A5A5A, 0, 0, 0 };
etl::mem_set(data + 1, data + 5, 0x5A);
etl::mem_set(data + 1, data + 5, (char)0x5A);
CHECK(std::equal(expected, expected + 8, data));
}
@ -1353,7 +1356,7 @@ namespace
uint32_t data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
uint32_t expected[8] = { 0, 0x5A5A5A5A, 0x5A5A5A5A, 0x5A5A5A5A, 0x5A5A5A5A, 0, 0, 0 };
etl::mem_set(data + 1, 4, 0x5A);
etl::mem_set(data + 1, 4, (char)0x5A);
CHECK(std::equal(expected, expected + 8, data));
}
@ -1363,8 +1366,8 @@ namespace
{
uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67294501, 0x45016723, 0x01324576, 0x76453201 };
char *p1 = etl::mem_char(data, data + 8, 0x29);
char* p2 = etl::mem_char(data, data + 8, 0x99);
char *p1 = etl::mem_char(data, data + 8, (char)0x29);
char* p2 = etl::mem_char(data, data + 8, (char)0x99);
CHECK_EQUAL(uint32_t(0x29), uint32_t(*p1));
CHECK((reinterpret_cast<char*>(data) + 18) == p1);
@ -1376,8 +1379,8 @@ namespace
{
const uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67294501, 0x45016723, 0x01324576, 0x76453201 };
const char* p1 = etl::mem_char(data, data + 8, 0x29);
const char* p2 = etl::mem_char(data, data + 8, 0x99);
const char* p1 = etl::mem_char(data, data + 8, (char)0x29);
const char* p2 = etl::mem_char(data, data + 8, (char)0x99);
CHECK_EQUAL(uint32_t(0x29), uint32_t(*p1));
CHECK((reinterpret_cast<const char*>(data) + 18) == p1);
@ -1389,8 +1392,8 @@ namespace
{
uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67294501, 0x45016723, 0x01324576, 0x76453201 };
char* p1 = etl::mem_char(data, 8, 0x29);
char* p2 = etl::mem_char(data, 8, 0x99);
char* p1 = etl::mem_char(data, 8, (char)0x29);
char* p2 = etl::mem_char(data, 8, (char)0x99);
CHECK_EQUAL(uint32_t(0x29), uint32_t(*p1));
CHECK((reinterpret_cast<char*>(data) + 18) == p1);
@ -1402,8 +1405,8 @@ namespace
{
const uint32_t data[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67294501, 0x45016723, 0x01324576, 0x76453201 };
const char* p1 = etl::mem_char(data, 8, 0x29);
const char* p2 = etl::mem_char(data, 8, 0x99);
const char* p1 = etl::mem_char(data, 8, (char)0x29);
const char* p2 = etl::mem_char(data, 8, (char)0x99);
CHECK_EQUAL(uint32_t(0x29), uint32_t(*p1));
CHECK((reinterpret_cast<const char*>(data) + 18) == p1);