代码之家  ›  专栏  ›  技术社区  ›  luke

在malloc之后修改字符串时,“释放后修改的空闲堆块”

  •  1
  • luke  · 技术社区  · 10 年前

    我目前正在处理一个包含一些文件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 在里面 join_paths .

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

    1 回复  |  直到 10 年前
        1
  •  4
  •   AnT stands with Russia    10 年前

    你的 memcpy 没有零终止目标缓冲区。同时 strncat 需要有效字符串作为目标。如果没有适当的零终止 斯特恩卡特 调用开始在缓冲区下游某个不可预测的位置串联,最终在缓冲区的末端运行。

    你很有可能通过做

    memcpy(path, a, a_len + 1);
    

    以确保终止零也被复制。

    但你为什么要混合 mem... 功能和 str... 功能?正确地执行是可能的,但在使用任何命令之前,您必须不断注意诸如正确的零终止之类的事情 字符串。。。 作用

    可以认为,当弦的长度已知时, 内存。。。 功能比 str.. 功能。在这种情况下,只要坚持 内存。。。 功能。例如,在您的情况下,这应该正常工作

    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);
    
    推荐文章