在 std::vector<unsigned char> 中将 std::wstring 编码为 UTF-16 的正确方法是什么?

What is the proper way to encode a std::wstring to UTF-16 in a std::vector<unsigned char>?

我正在尝试将 std::wstring 编码为 UTF-16,并将其传递给采用一对向量迭代器的函数。为此,我尝试了以下方法。

std::vector<unsigned char> HashAlgorithm::ComputeHash(std::wstring value)
{
    std::wstring_convert<std::codecvt_utf16<wchar_t>> converter;

    std::string encodedString = converter.to_bytes(value);

    std::vector<unsigned char> encodedBytes(
        reinterpret_cast<unsigned char const *>(encodedString.c_str()),
        reinterpret_cast<unsigned char const *>(encodedString.c_str() + encodedString.size()));

    std::vector<unsigned char> hashedBytes = this->ComputeHash(encodedBytes.begin(), encodedBytes.end());
    return hashedBytes;
}

它在大多数情况下工作正常,除了我知道出了点问题,因为在调试模式下我在 hashedBytes 的 return 上看到以下断言,它闻起来像某种堆栈腐败。

是什么导致了这个错误,我该如何预防?

编辑 #1

下面是我正在使用的支持功能的内容。我一直试图将其分解以找出断言的来源和原因,但我还无法获得最小的复制品。

std::vector<unsigned char> HashAlgorithm::ComputeHash(std::vector<unsigned char>::const_iterator begin, std::vector<unsigned char>::const_iterator end)
{
    this->Process(begin, end);
    std::vector<unsigned char> hashedBytes = this->Complete();

    return hashedBytes;
}

void HashAlgorithm::Process(std::vector<unsigned char>::const_iterator begin, std::vector<unsigned char>::const_iterator end)
{
    NTSTATUS status = BCryptHashData(this->hash, const_cast<unsigned char *>(&(*begin)), std::distance(begin, end), 0);
}

std::vector<unsigned char> HashAlgorithm::Complete()
{
    std::vector<unsigned char> result(this->outputSize);

    NTSTATUS status = BCryptFinishHash(this->hash, result.data(), (ULONG)result.size(), 0);
    return result;
}

为确保您不会丢失任何数据,您应该直接对字节进行哈希处理:

std::vector<unsigned char> myClass::ComputeHash(std::wstring value)
{
    auto size_of_data = value.size()*sizeof(value[0]);
    auto pointer_to_data = reinterpret_cast<unsigned char const *>(value.data());
    std::vector<unsigned char> encodedBytes(pointer_to_data,pointer_to_data+size_of_data);
    std::vector<unsigned char> hashedBytes = this->ComputeHash(encodedBytes.begin(),encodedBytes.end());
    return hashedBytes;
}

尝试添加一个香蕉 (\U0001F34C) 以查看您的数据在逐步执行时发生了什么。例如std::wstring my_unicode_string{L"Test string \n"};std::wstring wstr = L"z\u00df\u6c34\U0001F34C"; // L"zß水"。如果您的 .cpp 文件未保存为 unicode 文本,第二个示例可能会更好。

您可能会遇到 to_bytes 抛出的异常,因为只有基本多语言平面中的代码点才能编码为单个 wchar。如果它确实为您进行转换,它可能会将不同的更高代码点映射到相似的字节,这将导致不同字符串的相同散列。

Microsoft VC++ 2010 和 2015 之间的

std::wstring 向后兼容。

问题是库代码 (VS 2010) 和客户端代码 (VS 2015) 中的 std::wstring 大小相差 4 个字节。 std::wstring 的较新版本更大,有 32 个字节,而旧版本有 28 个字节。当按值传递这些变量时,堆栈损坏发生在较小 std::wstring 的前 4 个字节中,并触发用于防止基于堆栈的漏洞利用的堆栈金丝雀。