也许资源没有发布?什么可能导致这个?

时间:2010-01-26 04:55:12

标签: c linux debugging memory-leaks

我正在开展一个项目,然后我突然出现了以下堆栈跟踪:

#0  0x0017c30c in _IO_flush_all_lockp () from /lib/libc.so.6
#1  0x0017d030 in _IO_cleanup () from /lib/libc.so.6
#2  0x0013e042 in exit () from /lib/libc.so.6
#3  0x00126bbe in __libc_start_main () from /lib/libc.so.6
#4  0x08049d11 in _start ()

(代码被移除,因为内存泄漏已经解决了。当然还有其他内容。我会更努力地跟踪它们,然后将它们发布到这里。:)最初的问题可能与内存泄漏无关。 )

首先,我是否从最初的堆栈跟踪中寻找正确的方向?我在处理内存问题之前从未见过这个。有什么想法吗?

编辑:有人说这是由于visual_mem_new0。该函数只是分配内存。它对plugin->作者一无所知。

编辑:Duh。在strdup之前的memcopy填充了内存。

编辑:好的,这摆脱了一次内存泄漏。我不相信最初的堆栈跟踪是关于内存泄漏的 - 例如,它仍然存在。它试图释放一些我相信的资源。该程序的一部分使用了大量的编译程序集(JIT编译器),它在缓冲区的文件描述符之上使用mmap'd内存。我正在关闭文件。我需要对内存映射做些什么吗?

但是,我会继续尝试清除这些内存泄漏。我最近做了一些与特定插件有关的事情。当我运行该插件时,该程序仅在关闭时挂起,该插件使用我所说的内存映射。我不确定它可能是什么。我做了一些小改动。最初我怀疑是一个共享指针,我跟踪引用。它使用整个libvisual中使用的相同系统,并且没有特定的内存泄漏出现。无论如何,我希望有人有一些关于它的线索。我想不出还有什么要补充的。

编辑:好的,在修订历史的帮助下跟踪它。以下代码有什么问题?我可以不像那样将输出复制到自己身上吗?

static inline int dump_stack(AvsCompilerContext *ctx)
{
    AvsCompilerArgument *pa;
    char output[2048];

    snprintf(output, 2047, "\ncompiler: stackdump: Stack dump\n");
    for (pa=(AvsCompilerArgument *)ctx->stack->base; pa < (AvsCompilerArgument *)ctx->stack->pointer; pa++) {
        snprintf(stderr, 2047, "%scompiler: stackdump: [%2d] = ", output, (pa - (AvsCompilerArgument *)ctx->stack->base));
        switch (pa->type) {
            case AvsCompilerArgumentInvalid:
                snprintf(output, 2047, "%sinvalid", output);
                break;

            case AvsCompilerArgumentConstant:
                snprintf(output, 2047, "%s%.2f", output, pa->value.constant);
                break;

            case AvsCompilerArgumentIdentifier:
                snprintf(output, 2047, "%s", pa->value.identifier);
                break;

            case AvsCompilerArgumentMarker: {
                char *markers[] = { "invalid", "function", "argument", NULL };
                snprintf(output, 2047, "%s--- %s marker ---", output, markers[pa->value.marker]);
                break;
            }

            case AvsCompilerArgumentPrivate:
                snprintf(output, 2047, "%sprivate", output);
                break;

        }
        snprintf(output, 2047, "\n");
    }

    avs_debug(print(output));
    return VISUAL_OK;
}

宏avs_debug什么都不做。我评论了它的内容。

3 个答案:

答案 0 :(得分:3)

visual_plugin_info_new调用正在分配内存的visual_mem_new0,你需要先释放插槽,然后再在visual_plugin_info_copy中分配它们。

答案 1 :(得分:1)

由于您正在执行strdup(),因此您应该使用free()释放值。我不确定visual_mem_free()是否会调用free()。如果您尝试free()而不是visual_mem_free(),那么valgrind错误会消失吗?

修改:您的snprintf()来电错误:

snprintf(output, 2047, "%sinvalid", output);

snprintf()是C99,标准说(7.19.6.5p2):

  

如果在重叠的对象之间进行复制,则行为未定义。

确切的陈述也适用于C89中的sprintf()

解决问题的最简单方法是:

char init[] = "\ncompiler: stackdump: Stack dump\n";
size_t init_len = sizeof init - 1;
snprintf(output, 2047, "\ncompiler: stackdump: Stack dump\n");

接下来是:

snprintf(output+init_len, sizeof output - init_len, "%.2f", pa->value.constant);

(请检查上面的一个错误。)

另外,我不确定为什么你在snprintf()中调用stderr作为其中一个调用的第一个参数。您是否在启用警告的情况下编译代码?

答案 2 :(得分:0)

您发布的最后一段代码中可能至少存在2个问题(问题的编辑会让您对目前正在尝试处理的问题感到非常困惑):

  1. 您有一行以snprintf(stderr, 2047, etc...)开头。这几乎肯定是一个复制粘贴错误,因为它不应该编译。您可能打算使用fprintf()

  2. 您无法在snprintf()来电中将目的地缓冲区用作来源。标准说,“如果在重叠的对象之间进行复制,则行为未定义”。如果你考虑一下,你可能会意识到,如果没有先在其他地方复制缓冲区,它就无法在一般情况下工作。尝试在vsnprintf()(可能名为snprintfcat())周围创建一个包装器,将包装格式化的字符串连接到目标缓冲区。这不是太难做,虽然它需要使用varargs,这可能有点棘手 - 但只是一点点。

  3. 以下是snprintfcat()功能完全未经测试的镜头 - 它会编译,但超出此用途需要您自担风险:

    int snprintfcat( char* dest, size_t siz, char const* fmt, ...)
    {
        size_t len = strnlen( dest, siz);
        size_t remainder = 0;
        int result;
    
        va_list ap;
    
        if (len < siz) {
            remainder = siz - len;
        }
    
        va_start( ap, fmt);
        result = vsnprintf( dest+siz-remainder, remainder, fmt, ap);
        va_end( ap);
    
        return result + siz - remainder;
    }