#c #casting #void-pointers #crypto #reinterpret-cast
#c #Кастинг #void-указатели #crypto #переинтерпретировать-приведение
Вопрос:
Я получаю странную ошибку приведения при компиляции с помощью Crypto
(исходный код Crypto напрямую #include
обрабатывается моим приложением в той же сборке.
Все *.cpp
исходные файлы Crypto добавляются в CMake и непосредственно компилируются. Обычно это работает нормально.)
/*******************************************
** Snippet of unedited Crypto source code:
** misc.h
*******************************************/
template <class T>
inline void SecureWipeArray(T *buf, size_t n)
{
if (sizeof(T) % 8 == 0 amp;amp; GetAlignmentOf<T>() % GetAlignmentOf<word64>() == 0)
SecureWipeBuffer(reinterpret_cast<word64 *>(static_cast<void *>(buf)), n * (sizeof(T)/8)); //error
else if (sizeof(T) % 4 == 0 amp;amp; GetAlignmentOf<T>() % GetAlignmentOf<word32>() == 0)
SecureWipeBuffer(reinterpret_cast<word32 *>(static_cast<void *>(buf)), n * (sizeof(T)/4)); //error
else if (sizeof(T) % 2 == 0 amp;amp; GetAlignmentOf<T>() % GetAlignmentOf<word16>() == 0)
SecureWipeBuffer(reinterpret_cast<word16 *>(static_cast<void *>(buf)), n * (sizeof(T)/2)); //error
else
SecureWipeBuffer(reinterpret_cast<byte *>(static_cast<void *>(buf)), n * sizeof(T)); //error
}
Все четыре строки выдают одну и ту же ошибку:
‘static_cast’: не удается преобразовать из ‘T *’ в ‘void *’
‘CryptoPP::SecureWipeBuffer’: не найдена соответствующая перегруженная функция
Я компилирую с C 20, но это не должно вызывать проблем со сбоями при компиляции кода до C 20, верно?
Я написал класс «SecArray», который наследует std::array
и использует SecureWipeArray
при уничтожении объекта.
(Примечание: должен ли деструктор быть виртуальным? std::array
не имеет никаких деструкторов)
namespace myNamespace
{
template<class T, size_t length>
class array : public std::array<T, length>
{
private:
using base = std::array<T, length>;
public:
inline ~array() noexcept
{
SecureWipeArray(base::data(), length);
}
constexpr inline operator T* () noexcept { return base::data(); }
constexpr inline operator T const* () const noexcept { return base::data(); }
};
}
Это единственный раз, когда мой код вызывает SecureWipeArray
напрямую.
(Я также написал несколько классов контейнеров, которые используют std
контейнеры с CryptoPP::AllocatorWithCleanup
, которые, в свою очередь, вызывают SecureWipeArray
)
Но T
все равно должен быть базовый тип, например char
, uint
, string
,
и т.д. Поэтому я не уверен, что вызывает эту ошибку.
Где мне следует искать потенциальную причину?
Комментарии:
1. Сообщение об ошибке должно продолжаться и указывать, какой тип
T
находится в расширении шаблона?2. @RichardCritten По-видимому, Microsoft Visual Studio не обеспечивает такого уровня детализации ошибки, даже при компиляции проектов CMake с использованием Ninja? Есть ли «подробная» опция, которую я должен включить, чтобы получить более подробную информацию об ошибке?
3. @rustyx Нет, это отдельная ошибка.
SecureWipeBuffer
вызывается функция, которую компилятор не может понять, не пройдя сначала мимоvoid*
проблемы.4. @n.’местоимения’м. О, ГЕНИАЛЬНО. Это потому, что я где-то объявил
array<const char>
или что-то в этом роде. Поэтому я должен использоватьconditional_t<is_const_v<...>...>
для проверки наличия const типов поT
мере необходимости иconst_cast
по мере необходимости. Давайте попробуем это и посмотрим, что произойдет. Спасибо за совет!!5. Вы смотрите на представление ошибок или представление вывода компилятора? Вывод компилятора должен показывать гораздо больше деталей, чем это.
Ответ №1:
Если у вас есть массив std, который является const , любая попытка изменить его содержимое является неопределенным поведением.
Это означает, что поведение вашей программы до и после записи не имеет ограничений, налагаемых на нее стандартом C . Да, UB может привести к перемещению во времени, и это так.
Наиболее вероятными последствиями являются то, что запись не происходит, не весь код видит запись (непоследовательным образом), и / или данные находятся на защищенной странице или ПЗУ, и ваша программа или компьютер выходят из строя.
Данные Const (в отличие от указателей const) в C на самом деле являются const .
Если вы хотите это сделать, удалите const в strange и предоставьте ему интерфейс const . Тогда то, что вы хотите сделать, является законным.
Однако не используйте объединения для ввода pun . В большинстве случаев это незаконно в C .
template<class T, size_t length>
struct array<T const, length> : private std::array<T, length>
{
using base=std::array<T, length>;
// then forward:
T const*begin()const{return base::begin();}
// etc
array(std::array<T const, length> arr):base(arr){}
};
Комментарии:
1. Использование специализации шаблона (и, возможно, наследования) для обработки оболочек const — лучший подход, чем моя сумасшедшая идея объединения. Спасибо, что указали мне правильное направление.