代码之家  ›  专栏  ›  技术社区  ›  Adam Naylor

为什么这段代码会损坏内存?

  •  3
  • Adam Naylor  · 技术社区  · 17 年前

    在……里面 参数

    #define MAX_PRINT_OUTPUT 4096
    
    void Echo(char *args[MAX_COMMAND_ARGUMENTS], int argCount)
    {
        for (int i = 1; i < argCount; ++i)
        {
            Printf("%s ", args[i]);
            Printf("\n");
        }
    };
    
    void Printf(const char *output, ...)
    {
        va_list args;
        char formattedOutput[MAX_PRINT_OUTPUT];
    
        va_start(args, output);
        vsnprintf(formattedOutput, sizeof(formattedOutput), output, args);
        va_end(args);
    
        g_PlatformDevice->Print(formattedOutput);
    };
    
    void RiseWindows::Print(const char *output)
    {
        //Corruption appears to occur as soon as this function is entered
        #define CONSOLE_OUTPUT_SIZE 32767
    
        char buffer[CONSOLE_OUTPUT_SIZE];
        char *pBuffer = buffer;
        const char *pOutput = output;
        int i = 0;
    
        while (pOutput[i] && ((pBuffer - buffer) < sizeof(buffer) - 1))
        {
            if (pOutput[i] == '\n' && pOutput[i+1] == '\r' )
            {
                pBuffer[0] = '\r';
                pBuffer[1] = '\n';
                pBuffer += 2;
                ++i;
            }
            else if (pOutput[i] == '\r')
            {
                pBuffer[0] = '\r';
                pBuffer[1] = '\n';
                pBuffer += 2;
            }
            else if (pOutput[i] == '\n')
            {
                pBuffer[0] = '\r';
                pBuffer[1] = '\n';
                pBuffer += 2;
            }
            else
            {
                *pBuffer = pOutput[i];
                ++pBuffer;
            }
            ++i;
        }
        *pBuffer = 0;
    
        SendMessage(this->ConsoleWindow.hwndBuffer, EM_LINESCROLL, 0, 0xffff);
        SendMessage(this->ConsoleWindow.hwndBuffer, EM_SCROLLCARET, 0, 0);
        SendMessage(this->ConsoleWindow.hwndBuffer, EM_REPLACESEL, 0, (LPARAM)buffer);
    
    };
    


    编辑
    编辑

    更新 对于任何感兴趣的人来说,问题似乎是溢出的调用堆栈,在堆栈的更底层,然后定义了另一个大数组。重构此操作消除了内存损坏。所以,这被归结为殴打!

    10 回复  |  直到 17 年前
        1
  •  3
  •   Brian Neal    17 年前

    您还没有提到这段代码在什么环境下运行。可能是你在吹牛。您正在RiseWindows::Print中的堆栈上声明一个32767字节的数组。在我熟悉的一些嵌入式系统环境中,这将是个坏消息。你能增加堆栈大小和/或在堆上分配缓冲区来测试这个理论吗?您可能希望将该缓冲区设置为std::vector,或者可能设置为私有成员向量,以避免每次调用Print时都对其进行分配和重新分配。

    按照这些思路,MAX_PRINT_OUTPUT有多大?

        2
  •  2
  •   Ryann Graham    17 年前

    可能不是你问的bug,但在循环中,在某些情况下,你会加倍递增pBuffer,这可能会把你推到缓冲区的末尾,因为你只检查长度-1(用于空终止)。

        3
  •  2
  •   Stephen Friederichs    17 年前

    随机猜测:我觉得问题是由Printf中的这一行引起的:

    char formattedOutput[MAX_PRINT_OUTPUT];
    

    我认为这是因为你有一些明显声明的指针和一些明显未声明的指针。字符数组是一个指针——这是不可能的,但并不明显。在函数定义中,Echo args被定义为二维数组,因为它是

    *args[MAX_COMMAND_ARGS]
    

    此外,据我所知,指向char的const指针只保留指针的值,而不是指针处内容的值。

        4
  •  2
  •   Ismael Philip Pryde    17 年前

    你尝试过分而治之的策略吗?

    • 开始注释行,直到它工作。
    • 一旦它正常工作,取消注释行,直到你找到错误所在。

    在进行逐步操作时,在单独的窗口中查看args[]指向的内存也会有所帮助。

        5
  •  1
  •   Jon W    17 年前

        6
  •  1
  •   banno    17 年前

    而(pOutput[i]&&(pBuffer-缓冲区)<size(缓冲区)-1))

    更改为:

    而(pOutput[i]&&(pBuffer-缓冲区)<size(缓冲区)-2))

    你一次写两个字符,所以你需要确保有足够的空间容纳两个字符。

        7
  •  0
  •   John Boker    17 年前

    不确定它是否应该工作,但Echo不会打印出args的第一个元素

    // Changed i=1 to i=0;
    for (int i = 0; i < argCount; ++i)
    {
        Printf("%s ", args[i]);
        Printf("\n");
    }
    
        9
  •  0
  •   i_am_jorf    17 年前

    工作原理是,我们用以下方法来吹烟囱:

    char缓冲区[CONSOLE_OUTPUT_SIZE];

    请尝试:

        10
  •  0
  •   Arafangion    17 年前

    我还没有真正调查过这件事,但你把自己的类型搞混了。..这非常迂腐,但在C中确实有所不同。

    char formattedOutput[MAX_PRINT_OUTPUT];
    

    void RiseWindows::Print(const char *output)
    

    尝试:

    void RiseWindows::Print(const char output[])
    

    此外,我注意到你正在修改这些缓冲区中的内存——你确定你能做到吗?至少,我确信你不能随意使用更多而不分配更多内存。(提示!)

    然后,我将使用字符串函数替换换行符(如适用)。