mirror of
https://github.com/ETLCPP/etl.git
synced 2026-04-30 19:09:10 +08:00
Hardened mem_set and mem_char parameter requirements
This commit is contained in:
parent
09acfca5a6
commit
e87e24557f
@ -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),
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user