【问题标题】:C malloc weird behavior on debug/releaseC malloc 在调试/发布时的奇怪行为
【发布时间】:2012-08-18 04:32:15
【问题描述】:

我正在尝试在简单程序中使用 C malloc/free 函数。

void* alloc_array( const int size )
{
    void* p;

    p = malloc( size );
    if( p )
    {
        //memset(p, 0, size);
        return( p );
    }
    else
        return NULL;
}

void free_array( void* p )
{
    if( p )
    {
        free( p );
        p = NULL;
    }       
}

void** alloc_array_ptr( const int nPointers )
{
    void** p;   
    unsigned int size = AMOUNT_TO_ALLOC(nPointers, void*);

    p = malloc( size );
    if( p )
    {
        return( p );
    }
    else
        return( NULL );
}

void free_array_ptr( void** p, const int nPointers )
{
    unsigned int i;

    if( p )
    {
        for( i = 0; i < nPointers; i++ )
            if( p[i] )
            {
                free( p[i] );
                p[i] = NULL;
            }

        free(p);
        p = NULL;
    }
}
int main(int argc, char* agv[]) {
    // builds the string with the location of the ini file
    int inifile_size = 0;
    char* inifile;
    // gets the buffer size nedeed for the buffer
    inifile_size = GetCurrentDirectory(0, NULL);
    // allocates memory for the buffer
    inifile = (char*) alloc_array( AMOUNT_TO_ALLOC(inifile_size, char) );
    // fills the buffer with the current directory
    if( GetCurrentDirectory( inifile_size, inifile ) == 0 )
    {
        printf("GetCurrentDirectory failed! (ErrorCode: %u)\n", GetLastError());
        return( !MY_ERROR_OK );
    }
    strcat(inifile, "\\");
    strcat(inifile, "test.ini");    
    printf("INI File: %s\n", inifile);

    char** sessions;
    int nSessions = 0;
    int i;

    nSessions = getNumberOfSubkeys(str);
    printf("\nOK (%d sessions found)\n", nSessions);

    // allocating memory for the sessions array of char*
    sessions = (char**) alloc_array_ptr( nSessions );

    if( sessions == NULL )
    {
        printf("ERROR_IN_MEM_ALLOC (SESSIONS)\n");      
        return( MY_ERROR_MEM_ALLOC );
    }
    else
        printf("sessions: 0x%p\n", sessions);

    // allocating memory for each one of the char* in sessions
    for( i = 0; i < nSessions; i++ )
    {
        sessions[i] = (char*) alloc_array( AMOUNT_TO_ALLOC(MAX_KEY_LENGTH, char) );

        printf("sessions[%d]: 0x%p\n", i, sessions[i]);

        if( sessions[i] == NULL )
        {
            printf("ERROR_IN_MEM_ALLOC (SESSIONS[%d])\n", i);
            return( MY_ERROR_MEM_ALLOC );                   
        }
    }

    printf("\nSessions found:\n");

    if( readSubkeys( str, sessions ) == MY_ERROR_OK )
    {
        for( i = 0; i < nSessions; i++ )
        {
            printf("\t%s: ", sessions[i]);

            if( convert2ini(inifile, sessions[i]) == MY_ERROR_OK )
                printf("OK\n");
            else
            {
                printf("ERROR\n");
                return( !MY_ERROR_OK );
            }           
        }
    }
    else
    {
        printf("ERROR\n");
        return( MY_ERROR_OPEN_REGISTRY );   
    }

    // free the inifile array
    free_array(inifile);

    // free the array of char*
    free_array_ptr( (void**)sessions, nSessions );      

    // returns to OS
    return( MY_ERROR_OK ); 
}

这是一个小工具,可以将 Windows 注册表中的一些程序设置转换为 ini 文件(Windows7,64 位,4Gb RAM)。

readSubkeys 用它从 str 中的注册表项获取的会话名称填充 char* 的预分配会话数组

getNumberOfSubkeys 返回注册表中给定子键的数量

其余代码与此无关。问题是,当我在 for 循环内为每个 char* 分配内存时,malloc 失败。我正在使用 CodeLite 编写这个程序,奇怪的是,当我逐步调试代码时 malloc 不会失败。

这里是运行此程序的图像。

有人可以给我一些建议吗?

【问题讨论】:

  • 在 for 循环中,malloc 失败 你的意思是它返回 NULL?
  • 在我的电脑上工作。 getNumberOfSubkeys(str); 可能有问题 - 太大了?运行 Microsoft C/C++ 编译器 15.00.30729.01。甚至适用于 O2(优化)。
  • @jsn:我会检查这个。谢谢。
  • @nos:我将发布正在运行的会话的屏幕。
  • printf("\nOK (%d sessions found)\n", nSessions); 出于某种原因,nSessions 以十六进制打印。尝试将 nSession 的数量硬编码为任意数量。如果这样可行,则该功能有问题。这里的其他一切看起来都很好。

标签: c debugging gcc malloc


【解决方案1】:

奇怪的是,当我逐步调试代码时,malloc 不会失败。

此语句可能意味着您的代码中的其他地方存在内存分配错误,导致此块(例如 malloc() 调用或断言)失败。如果没有更多代码,我们真的没有足够的信息来完全调试它。

【讨论】:

  • 假设 GetCurrentDirectory(0, NULL) 准确返回目录名的长度,您的 strcat() 调用可能会溢出 inifile,并导致相关内存损坏。我会为目录名称加上“\\test.ini”的长度分配 iniFile,再加上一个空终止字符。 (strcat 不会为你分配)。
  • 就此而言,即使没有 strcat() 调用,您也只能为目录名称分配足够的空间,而不是终止 null。你应该有inifile = alloc_array(inifile_size + 1 + &lt;room for strcat&gt;)
  • 是的,没错。这是真正的问题。我在开始时没有正确分配内存的事实有点搞砸了随后的分配(我无法弄清楚究竟是为什么)。我想不通的另一件事是为什么在调试模式下没有崩溃。
  • 在备用环境中运行通常会改变堆(malloc 空间所在的位置)的特性。我遇到过发布的代码可以运行但调试代码不会运行的情况!如果您能接受这个作为答案,我将不胜感激,我刚刚开始使用我的 stackoverflow 声誉积分。谢谢!
【解决方案2】:

抱歉,我必须将此作为答案发布。我仍然没有发布 cmets 的权限。 在第一个 malloc 语句中,您将 malloc 的返回类型转换为指向指针的指针。 因此,在 for 循环中,当您说 session[0] 时,它将包含第一个位置 0x00701760(在第一个 malloc 之后)的地址。 您将 for 循环增加到会话 [1]。这在技术上是不可能的。由于会话中没有下一个值。您实际上需要增加 session[0] 中包含的值。 它可能类似于 *sessions++。我想说的是您应该将 0x00701760 增加到 0x00701762 并对此执行 malloc。所以 0x00701762 现在包含了新分配内存的地址。接下来是 0x00701764,然后是 0x00701766。 增加 session[] 将导致错误或至少访问无效内存。 希望这个建议对您有所帮助。

谢谢 阿迪亚

【讨论】:

  • 谢谢。但它不应该是 0x00701760 到 0x00701764 因为指针在 IA32 中是 4 字节长吗?此外,在第一次尝试分配每个 char* 时分配失败。
  • 哦,对了!......对不起。好的,所以断言在 for 循环的第一次迭代中因 (char *)malloc 失败,因为您现在正试图将地址分配给另一个地址。我在想的是你没有正确取消引用。它就像 0x00701760 = (char *)malloc...所以地址正在改变..尝试做 **sessions 看看它是否有效。
  • 试试 (session[0]) = (char)malloc(..)
  • 感谢您的提示,但这不是问题所在。
  • 哦,好的。当您进行逐步调试时,我无法看到它是如何不失败的。您可以打印/粘贴逐步调试输出的结果吗?您是否为 nSessions 的所有值迭代了 for 循环?
【解决方案3】:

谢谢大家的建议。

问题是我在程序的早期没有正确分配内存。奇怪的是,这部分软件可以工作,但随后的内存分配失败了。我要解决的是我计算了我必须 malloc 的内存的正确大小,包括几个 strcat 调用来添加分隔符和文件名。然后,该软件运行良好。我重写了有问题的部分,它看起来像这样。

    // builds the string with the current directory

    // gets the size nedeed for the buffer
    current_path_size = GetCurrentDirectory(0, NULL);

    // allocates memory for the buffer
    current_path = (char*) alloc_array( AMOUNT_TO_ALLOC(current_path_size, char) );

    // gets the current directory
    if( GetCurrentDirectory( current_path_size, current_path ) == 0 )
    {
        printf("GetCurrentDirectory failed! (ErrorCode: %u)\n", GetLastError());
        return( !MY_ERROR_OK );
    }

    // builds the string with the location of the ini file

    // calculates the total amount of memory to alloc
    total_size = current_path_size + strlen(CHAR_SEPARATOR) + strlen(PUTTY_FILENAME) + 1;

    // allocates memory for the full path + filename of the ini file
    ini_file = (char*) alloc_array(AMOUNT_TO_ALLOC(total_size, char));

    // fills the buffer with the path + separator + filename + leading '\0'
    strcat(ini_file, current_path);
    strcat(ini_file, CHAR_SEPARATOR);
    strcat(ini_file, PUTTY_FILENAME);
    ini_file[total_size - 1] = '\0';

没有响应的一件事是为什么调试器没有使代码崩溃。我还需要对此做进一步的研究。

【讨论】:

    猜你喜欢
    • 2018-10-22
    • 1970-01-01
    • 2015-06-05
    • 2011-01-21
    • 1970-01-01
    • 2018-04-10
    • 1970-01-01
    相关资源
    最近更新 更多