为什么我的程序在使用 HeapAlloc 时崩溃并且正常工作

Why does my program crash when using HeapAlloc and work normally whith malloc

本文关键字:常工作 工作 崩溃 程序 我的 HeapAlloc 为什么      更新时间:2023-10-16

我用C++编写了一个程序,带有以下字符串:

pDataArray[i]->hWritePipes = (HANDLE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE)*(MAX_THREADS - 1));

当我运行它时,我收到消息:

HEAP[MultyThreading1.exe]: HEAP: Free Heap block 4f5830 modified at 4f5850 after it was freed
MultyThreading1.exe has triggered a breakpoint.

我将此字符串替换为

pDataArray[i]->hWritePipes = (HANDLE*)malloc(sizeof(HANDLE)*(MAX_THREADS - 1));

而且该程序似乎运行正常。

你知道第一个版本有什么问题吗?

问候。

所有代码都是下面:

#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <iostream>
#include <cstdio>
#include <string.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define MAX_THREADS 3
#define BUF_SIZE 255
#define PIPE_SIZE 64
typedef struct Args
{
    char tName[56];
    HANDLE hReadPipe;
    int n;
    HANDLE* hWritePipes/*[MAX_THREADS-1]*/;
    int i;
} ARGS, *PARGS;

void ErrorHandler(LPTSTR lpszFunction);
DWORD WINAPI recieverFunction(void *arg);
DWORD WINAPI senderFunction(void *arg);
PARGS initParg(int i);

int _tmain()
{
    PARGS pDataArray[MAX_THREADS];
    DWORD   dwThreadIdArray[MAX_THREADS];
    HANDLE  hThreadArray[MAX_THREADS];
    for (int i = 0; i < MAX_THREADS; i++)
    {
        pDataArray[i] = initParg(i);
        if (i == 0){
            pDataArray[i]->hWritePipes = (HANDLE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HANDLE)*(MAX_THREADS - 1));
        }
        else {
            if (!CreatePipe(&pDataArray[i]->hReadPipe, &pDataArray[0]->hWritePipes[i - 1], NULL, NULL)){
                ErrorHandler(TEXT("CreateThread"));
                ExitProcess(3);
            }
        }

        if (pDataArray[i] == NULL)
            ExitProcess(2);
        hThreadArray[i] = CreateThread(NULL, 0, i==0 ? senderFunction : recieverFunction, pDataArray[i], 0, &dwThreadIdArray[i]);
        if (hThreadArray[i] == NULL)
        {
            ErrorHandler(TEXT("CreateThread"));
            ExitProcess(3);
        }
    }
    WaitForMultipleObjects(MAX_THREADS, hThreadArray, TRUE, INFINITE);
    for (int i = 0; i<MAX_THREADS; i++)
    {
        CloseHandle(hThreadArray[i]);
        if (pDataArray[i] != NULL)
        {
                HeapFree(GetProcessHeap(), 0, pDataArray[i]);
                pDataArray[i] = NULL;    // Ensure address is not reused.
        }
    }
    return 0;
}
PARGS initParg(int i){
    PARGS ret = (PARGS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PARGS));
    ret->i = i;
    return ret;
}
DWORD  WINAPI senderFunction(void *arg) {
    string input;
    while (true) {
    }
    return NULL;
}
DWORD WINAPI recieverFunction(void *arg) {
    while (true) {}
    return NULL;
}


void ErrorHandler(LPTSTR lpszFunction)
{
    // Retrieve the system error message for the last-error code.
    LPVOID lpMsgBuf;
    LPVOID lpDisplayBuf;
    DWORD dw = GetLastError();
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER |
        FORMAT_MESSAGE_FROM_SYSTEM |
        FORMAT_MESSAGE_IGNORE_INSERTS,
        NULL,
        dw,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0, NULL);
    // Display the error message.
    lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
        (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
    StringCchPrintf((LPTSTR)lpDisplayBuf,
        LocalSize(lpDisplayBuf) / sizeof(TCHAR),
        TEXT("%s failed with error %d: %s"),
        lpszFunction, dw, lpMsgBuf);
    MessageBox(NULL, (LPCTSTR)lpDisplayBuf, TEXT("Error"), MB_OK);
    // Free error-handling buffer allocations.
    LocalFree(lpMsgBuf);
    LocalFree(lpDisplayBuf);
}

(发布答案,以免在评论中迷失方向)

正如 Eric 所暗示的,initParg函数中的HeapAlloc调用是错误的。您正在为指针(sizeof(PARGS))分配足够的空间,但使用结果就像为整个结构分配了足够的空间一样。

PARGS initParg(int i) {
    PARGS ret = (PARGS)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PARGS));
    ret->i = i;
    return ret;
}

您已分配 4 个字节的内存,但ret->i = i行写入的偏移量 ~68 字节超过分配块的开头。越界访问正在损坏堆。

此处要采取的纠正措施是分配sizeof(ARGS)字节。

至于malloc"修复"问题:

  • 您正在使用的malloc的实现可能会在内部将分配大小舍入到更大的最小值,以便您的非法写入碰巧不会损坏任何重要内容。
  • 您正在使用的malloc的实现可能会将空间分配相距足够远,以至于您的非法写入恰好不会损坏任何重要内容。
  • 您正在使用的malloc的实现可能不会执行与HeapAlloc正在执行的相同的验证(或者可能仅在free上执行),因此尽管您的非法写入正在破坏事物,但尚未被注意到。

另请注意,如果切换到 malloc 进行分配,则必须使用 free 进行取消分配。 不能假定HeapFree兼容。