"释放后释放的免费堆块"在malloc之后修改字符串时

时间:2014-08-06 21:29:51

标签: gdb malloc memcpy c89 string.h

我目前正在开发一个包含一些文件I / O的项目。

由于它是跨平台的,我需要考虑不同的路径分隔符,因此决定创建以下函数来简化加入路径的过程:

/**
 * @brief Joins two paths together.
 * 
 * path = a + seperator + b + '\0'
 * 
 * @param a First path.
 * @param b Second path.
 * 
 * @return A pointer to the two paths combined.
 */
char * join_paths(const char * a, const char * b)
{
    const char separator[] =
    #ifdef _WIN32
        "\\";
    #else
        "/";
    #endif


    /* Get the sizes of all the strings
       to join.                         */
    size_t a_len = strlen(a);
    size_t b_len = strlen(b);
    size_t s_len = strlen(separator);
    size_t total_len = a_len + b_len + s_len + 1; /* +1 for \0 */

    /* path will contain a, b, the separator and \0
       hence the total length is total_len.
    */
    char * path = malloc(total_len);
    check( path != NULL,
           "Error allocating memory for path. " );

    memcpy(path, a, a_len);          /* path will begin with a */

    strncat(path, separator, s_len); /* copy separator */
    strncat(path, b, b_len);         /* copy b         */

error:

    return path;
}

(其中check是来自此处的宏:http://pastebin.com/2mZxSX3S

到目前为止,当我不得不使用GDB来调试与文件I / O无关的东西并且意识到我的所有文件路径似乎都已损坏时(例如“║½½½½½½½½■■■■■■■■■■■■■■■■■■■■■■■■■■■■ ¯■“)。

我也收到了错误消息:

  

“释放后释放的自由堆块”

经过进一步调查后,我意识到这一切都发生在memcpy的{​​{1}}之后。

然而,这一切似乎只有在从GDB运行时才会发生。这里出了什么问题?

1 个答案:

答案 0 :(得分:4)

您的memcpy未将目标缓冲区置零。同时,strncat需要一个有效的字符串作为目标。如果没有正确的终止,你的strncat调用会在缓冲区的某个不可预测的位置开始连接,最终会在缓冲区的末尾运行。

很可能只需要做

即可解决问题
memcpy(path, a, a_len + 1);

确保也复制终止零。

但为什么要混合使用mem...函数和str...函数?可以正确地执行此操作,但在使用任何str...函数之前,必须始终注意诸如正确的零终止之类的事情。

有人可能会争辩说,当字符串的长度已知时,mem...函数比str..函数更合适和有效。在这种情况下,只需坚持mem...函数。例如,在您的情况下,这应该正常工作

memcpy(path, a, a_len);
memcpy(path + a_len, separator, s_len);
memcpy(path + a_len + s_len, b, b_len + 1);

或者(甚至可能更好),您可以使用sprintf(或snprintf)在一行中执行此操作

size_t n_written = sprintf(path, "%s%s%s", a, separator, b);
assert(n_written + 1 == total_len);