【问题标题】:Weird error in existing Crypto++ code, casting pointers to void*现有 Crypto++ 代码中的奇怪错误,将指针转换为 void*
【发布时间】:2021-05-07 01:12:20
【问题描述】:

使用 Crypto++ 编译时出现奇怪的转换错误
(Crypto++ 源代码直接由我的应用程序#include'd,在同一个程序集中。
所有 Crypto++ *.cpp 源文件都添加到 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 && GetAlignmentOf<T>() % GetAlignmentOf<word64>() == 0)
        SecureWipeBuffer(reinterpret_cast<word64 *>(static_cast<void *>(buf)), n * (sizeof(T)/8)); //error
    else if (sizeof(T) % 4 == 0 && GetAlignmentOf<T>() % GetAlignmentOf<word32>() == 0)
        SecureWipeBuffer(reinterpret_cast<word32 *>(static_cast<void *>(buf)), n * (sizeof(T)/4)); //error
    else if (sizeof(T) % 2 == 0 && 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应该还是基本类型,比如charuintstring
所以我不确定是什么导致了这个错误。
我应该从哪里寻找潜在原因?

【问题讨论】:

  • 错误信息应该继续,并说明模板扩展中T是什么类型?
  • @RichardCritten 显然,即使使用 Ninja 编译 CMake 项目,Microsoft Visual Studio 也没有在错误中提供该级别的详细信息?我应该启用“详细”选项以获得更多错误详细信息吗?
  • @rustyx 不,这是一个单独的错误。 SecureWipeBuffer 是一个被调用的函数,如果不先解决 void* 问题,编译器将无法理解该函数。
  • @n.'pronouns'm。哦,天才。这是因为我在某处声明了array&lt;const char&gt; 或其他东西。所以我应该使用conditional_t&lt;is_const_v&lt;...&gt;...&gt; 来检查常量类型为T,并根据需要使用const_cast。让我试试这个,看看会发生什么。感谢您的提示!
  • 您查看的是错误视图还是编译器输出视图?编译器输出应该显示比这更多的细节。

标签: c++ casting void-pointers crypto++ reinterpret-cast


【解决方案1】:

如果您有一个 const 的 std 数组,则任何修改其内容的尝试都是未定义的行为。

这意味着您的程序在写入之前和之后的行为不受 C++ 标准的限制。是的,UB 会导致时间旅行,而且确实如此。

最可能的影响是未发生写入,并非所有代码都能看到写入(以不一致的方式),和/或数据位于受保护的页面或 ROM 上并且您的程序或计算机崩溃。

C++ 中的 const 数据(相对于 const 指针)实际上是 const。

如果你想这样做,去掉奇怪的 const 并为其提供一个 const 接口。那么你想做的就是合法的。

但是,不要使用联合来键入双关语。在大多数情况下,这在 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){}
};

【讨论】:

  • 使用模板特化(也可能是继承)来处理 const 包装器,是一种比我疯狂的联合想法更好的方法。感谢您为我指明正确的方向。
猜你喜欢
  • 1970-01-01
  • 2014-08-13
  • 2012-11-02
  • 2017-07-27
  • 2016-01-12
  • 2021-07-22
  • 2017-01-08
  • 2012-02-07
  • 1970-01-01
相关资源
最近更新 更多