C中的内存管理(分配)

时间:2017-03-09 23:08:58

标签: c windows winapi memory out-of-memory

我用C(不是C ++)编写cmd提示符,程序已编译但是当我运行它时,我输入了几次命令,程序错误并中止 我认为这是由于内存分配: 这是源代码:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char* Execute(char*);

HANDLE readIN = NULL;
HANDLE writeIN = NULL;
HANDLE readOUT = NULL;
HANDLE writeOUT = NULL;



int
main(int argc, char** argv)
{
    SECURITY_ATTRIBUTES saAttr;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    char cmd[12];
    char* out = NULL;
    ZeroMemory(cmd,sizeof(cmd));


    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    CreatePipe(&readOUT, &writeOUT, &saAttr, 0);
    CreatePipe(&readIN, &writeIN, &saAttr, 0);

   ZeroMemory(&si, sizeof(si));
   ZeroMemory(&pi, sizeof(pi));
   GetStartupInfo(&si);

   si.cb = sizeof(STARTUPINFO);
   si.hStdError = writeOUT;
   si.hStdOutput = writeOUT;
   si.hStdInput = readIN;
   si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
   si.wShowWindow = SW_HIDE;

   CreateProcess(NULL,
                 "cmd.exe",
                  NULL,
                  NULL,
                  TRUE,
                  CREATE_NEW_CONSOLE,
                  NULL,
                  NULL,
                  &si,
                  &pi
                );

    while (TRUE)
    {
        out = Execute(cmd);
        printf("%s\n", out);
        scanf("%s", cmd);
        strcat(cmd,"\n");
    }
    free(out);
    return 0;
}


char*
Execute(char* cmd)
{
    DWORD bwritten = 0;
    DWORD buffersize = 0;
    int outputsize = 0;
    DWORD breaden = 0;
    char* output = NULL;
    char* buffer = NULL;
    DWORD n_buffersize;
    WriteFile(writeIN, cmd, strlen(cmd), &bwritten, NULL);
    while (TRUE)
    {
        Sleep(2000);
        PeekNamedPipe(readOUT, NULL, NULL, NULL,&buffersize, NULL);
        n_buffersize = buffersize;
        if (n_buffersize)
        {   
            buffer = (char*)malloc(n_buffersize + 1);
            ZeroMemory(buffer,sizeof(buffer));
            ReadFile(readOUT, buffer, n_buffersize, &breaden, NULL);
        }
        else
            break;

        if (breaden)
        {
            outputsize += n_buffersize + 1;
            output = (char*)realloc(output, outputsize);
            strcat(output, buffer);
            free(buffer);
        }
    }
    return output;
}

2 个答案:

答案 0 :(得分:4)

你在哪里:

buffer = (char*)malloc(n_buffersize + 1);
ZeroMemory(buffer,sizeof(buffer));

请注意,最初是n_buffersize = 0,因此您只分配1个字节。 但是你将sizeof(char*)个字节数归零(在32位系统上为4个字节,在64位系统上为8个字节)。

您可以将分配的字节数归零,即n_buffersize + 1。或者使用calloc()代替malloc()

答案 1 :(得分:0)

Execute()内的内存管理可以简化。使用两个缓冲区,尤其是strcat()缓冲区,效率很低。但更重要的是,main()中的循环正在泄漏Execute()输出的内存,无论它是如何分配的。

您也没有遵循MSDN上记录的有关STD(IN|OUT|ERR)重定向的所有指南:

Creating a Child Process with Redirected Input and Output

即,您继承了不应该继承的句柄,并且在cmd.exe运行时您没有关闭不使用的句柄。

尝试更像这样的东西:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

char* Execute(char*);

HANDLE readIN = NULL;
HANDLE writeIN = NULL;
HANDLE readOUT = NULL;
HANDLE writeOUT = NULL;

int
main(int argc, char** argv)
{
    SECURITY_ATTRIBUTES saAttr;
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    char cmd[256];
    char* out = NULL;
    ZeroMemory(cmd, sizeof(cmd));

    ZeroMemory(&saAttr, sizeof(saAttr));
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;

    if (!CreatePipe(&readOUT, &writeOUT, &saAttr, 0)) {
        // error handling...
    }
    if (!SetHandleInformation(readOUT, HANDLE_FLAG_INHERIT, 0)) {
        // error handling...
    }

    if (!CreatePipe(&readIN, &writeIN, &saAttr, 0)) {
        // error handling...
    }
    if (!SetHandleInformation(writeIN, HANDLE_FLAG_INHERIT, 0)) {
        // error handling...
    }

    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));

    si.cb = sizeof(STARTUPINFO);
    si.hStdError = writeOUT;
    si.hStdOutput = writeOUT;
    si.hStdInput = readIN;
    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_HIDE;

    if (!CreateProcess(NULL,
                 "cmd.exe",
                  NULL,
                  NULL,
                  TRUE,
                  CREATE_NEW_CONSOLE,
                  NULL,
                  NULL,
                  &si,
                  &pi
                ))
    {
        // error handling...

        CloseHandle(readIN);
        CloseHandle(writeIN);
        CloseHandle(readOUT);
        CloseHandle(writeOUT);
    }
    else
    {
        CloseHandle(pi.hThread);
        CloseHandle(pi.hProcess);

        CloseHandle(readOUT);
        CloseHandle(writeIN);

        do
        {
            if (scanf("%254s", cmd) != 1)
                break;    
            strcat(cmd,"\n");

            out = Execute(cmd);
            if (!out) {
                printf("ERROR!\n");
                break;
            }

            printf("%s\n", out);
            free(out);
        }
        while (TRUE);

        CloseHandle(writeOUT);
        CloseHandle(readIN);
    }

    return 0;
}    

char*
Execute(char* cmd)
{
    DWORD bwritten = 0;
    DWORD buffersize = 0;
    int outputsize = 0;
    DWORD bread = 0;
    char* buffer = NULL;
    char* output = NULL;

    buffersize = strlen(cmd);
    while (buffersize > 0)
    {
        if (!WriteFile(writeIN, cmd, buffersize, &bwritten, NULL))
            return NULL;
        cmd += bwritten;
        buffersize -= bwritten;
    }

    do
    {
        Sleep(2000);
        if (!PeekNamedPipe(readOUT, NULL, NULL, NULL, &buffersize, NULL))
            break;

        if (buffersize == 0)
            break;

        buffer = (char*) realloc(output, outputsize + buffersize + 1);
        if (!buffer) {
            free(output);
            return NULL;
        }

        output = buffer;

        if (!ReadFile(readOUT, output + outputsize, buffersize, &bread, NULL))
            bread = 0;

        outputsize += bread;
        output[outputsize] = '\0';
    }
    while (bread > 0);

    return output;
}