1

背景

考虑以下代码:

    template <typename T>
    void WriteData(const size_t &offset, const T &data)
    {
        if(sizeof(data) <= 8) //if size is 64bits or less, memcpy is not as efficient as a direct write
            *reinterpret_cast<T*>(reinterpret_cast<char*>(_memView) + offset) = data;
       else
        {
            errno_t result = memcpy_s(reinterpret_cast<char*>(_memView) + offset, SHARED_BUFFER_SIZE - offset, &data, sizeof(data));
            if(result != 0)
                throw exception("Error writing data");
        }
    }

假设 _memView 被声明为 void 指针。memcpy_s 尚未在任何地方重新定义。

该函数仅使用以下类型实例化:char、int、HANDLE、unsigned int、long 和 unsigned long。不要陷入这个片段的其他问题,这是关于 klocwork 的。

这个模板化的代码是一个类的一部分,所以它位于一个头文件中。

如果我缺少其他相关信息,请询问。

问题

在使用 Klocwork 进行分析后,我收到了 SV.BANNED.COPY 警告:“不要使用不安全的缓冲区复制功能——考虑使用安全的变体,例如 strcpy_s”

所以我在这里用我调用 memcpy_s 的方式做一些脑死的事情,Klocwork 是否认为 memcpy_s 不安全?Klocwork 是否对转换为 char* 感到困惑,并认为我正在操作 C 风格的字符串?

我想了解 Klocwork 试图告诉我什么,即使它只是告诉我这是误报。

4

1 回答 1

2

根据标准 C++,这个函数是各种损坏的。

  • if分支执行未对齐的写入并违反严格的别名。

两个分支都会很高兴地注销缓冲区的末尾。

  • if分支根本不检查大小。
  • 在缓冲区大小参数的else计算中,分支受无符号进位的影响。

memcpy_s不是万灵药。使用memcpy参数验证并对其进行一些思考将击败memcpy_s每次的盲目调用。

修正版:

template <typename T>
void WriteData(const size_t &offset, const T &data)
{
    if (sizeof data > SHARED_BUFFER_SIZE)
        throw exception("Type cannot fit in shared buffer");
    if (offset > SHARED_BUFFER_SIZE - sizeof data)
        throw exception("Copy would overrun end of shared buffer");
    memcpy(reinterpret_cast<char*>(_memView) + offset, &data, sizeof data);
}

为了有效地处理小副本,请确保您的编译器将其memcpy视为内在函数已启用。

于 2014-08-21T13:57:00.913 回答