背景

考虑以下代码:

    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被声明为空指针。
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试图告诉我什么,即使只是告诉我这是一个误报。

最佳答案

根据标准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视为内部函数。

    07-24 14:24