0

操作系统:Windows x86、MFC、CRT、VS2010

从 Visual Studio 2005 (SP1) 升级到 VS2010-SP1 后,我遇到了运行时 CRT 堆损坏异常。

当我的应用程序使用调试编译时,CRT 只会抱怨损坏。而且我认为 VS2010 在评估内存访问时过于严格。

可疑的违规代码执行以下操作:

typedef struct _T_TEST
{
    DWORD flag;
    TCHAR str[1];
} T_TEST;

// Then the structure is used in this way
void test(TCHAR * p_str) {
    DWORD size = sizeof(DWORD) + (_tcslen(p_str) + 1) * sizeof(TCHAR);
    T_TEST * foo = (T_TEST *) calloc(size, 1);
    foo->flag = 0;
    _tcscpy_s(foo->str, size - sizeof(DWORD), p_str);
    // Do IPC with the struct
    // When finished, free it
    free(foo);
}

此代码有时会在free(foo)将分配的缓冲区转换为(T_TEST *).

以这种方式扩展结构大小是否有效?VS2010 中是否有一些不同的东西将其视为堆损坏?

任何帮助将不胜感激!

4

2 回答 2

2

to的第二个参数_tcscpy_s是元素的数量,但你给它提供了字节数。根据文档

这些函数的调试版本首先用 0xFE 填充缓冲区。

如果 sizeof(TCHAR) != 1,这将导致缓冲区溢出。

于 2013-08-21T21:14:50.770 回答
0

代码有两个问题可能导致堆损坏:将字节大小而不是字符数传递给_tcscpy_s并计算错误的缓冲区大小。

正确的实现应该大致如下所示:

void test(TCHAR * p_str) {
    // Calculate the input string length
    size_t len = _tcslen(p_str);

    // Calculate the buffer size  (1)
    size_t bufferSize = offsetof(T_TEST, str[len + 1]);

    // Allocate a buffer
    vector<char> buffer(bufferSize);

    // Map the structure onto the buffer to get a T_TEST*
    T_TEST* foo = reinterpret_cast<T_TEST*>(&buffer[0]);

    foo->flag = 0;
    // This potentially writes beyond the end  (2)
    //_tcscpy_s(foo->str, size - sizeof(DWORD), p_str);
    _tcscpy(foo->str, len + 1, p_str);

    // Do IPC with the struct
    // When finished, free it

    // buffer will be automatically cleaned up
    //free(foo);
}

(1) 结构的大小不一定等于其成员大小的总和。根据目标平台和/或编译器设置,编译器将对齐各个成员以满足对齐要求。为此,它(可能)在它们之间添加填充。Usingoffsetof是让编译器进行计算的一种便捷方式。

(2) 在原始代码中存在两个问题: 调用_tcscpy_s需要目标缓冲区的字符数大小,而不是字节大小。还有一个隐藏的陷阱:表达式foo->str指示编译器计算偏移量,同时考虑潜在的填充。然而,该表达式size - sizeof(DWORD)不考虑填充,这打开了写入超出分配缓冲区末尾的可能性。

由于您正在处理 MFC 应用程序,因此我假设使用 C++ 是可以的,即使问题未标记为C++. 如果您不能或不想使用,您可以使用和清理std::vector分配缓冲区。new char[bufferSize]delete[] buffer;

于 2013-08-24T11:00:05.277 回答