C 也许是一个资源没有被释放?这是什么原因造成的?

C 也许是一个资源没有被释放?这是什么原因造成的?,c,linux,debugging,memory-leaks,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

我正在做一个项目,我到达了一个点,出现了以下堆栈跟踪:

#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 ()
(代码已删除,因为内存泄漏问题已解决。当然还有其他问题。不过,在将它们发布到此处之前,我会更努力地查找它们。:)最初的问题可能与内存泄漏无关。)

首先,我是否从初始堆栈跟踪看向了正确的方向?在处理内存问题时,我以前从未见过这个。有什么想法吗

编辑:有人说这是因为视觉记忆。该函数只是分配内存。它对插件->作者一无所知

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

编辑:好的,这样就消除了一个内存泄漏。我不相信最初的堆栈跟踪是关于内存泄漏的——例如,它仍然存在。我相信这是在释放一些资源。这个程序的一部分使用了大量已编译的程序集(JIT编译器),它在文件描述符上使用mmap内存作为缓冲区。我正在关闭文件。我需要处理内存映射吗

不过,我会继续努力清除这些内存泄漏。我最近做了一件与某个插件相关的事情。这个程序只有在我运行插件时才会挂起,插件使用了我提到的内存映射。我不确定会是什么。我做了一些小改动。起初,我怀疑有一个共享指针,我会跟踪它的引用。它使用了整个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;
}
static inline int dump_堆栈(AvsCompilerContext*ctx)
{
AvsCompilerArgument*pa;
字符输出[2048];
snprintf(输出,2047,“\n编译器:堆栈转储:堆栈转储\n”);
对于(pa=(AvsCompilerArgument*)ctx->stack->base;pa<(AvsCompilerArgument*)ctx->stack->pointer;pa++){
snprintf(stderr,2047,“%s编译器:堆栈转储:[%2d]=”,输出,(pa-(AvsCompilerArgument*)ctx->stack->base));
开关(pa->类型){
案例AvsCompilerArgumentInvalid:
snprintf(输出,2047,“%sinvalid”,输出);
打破
案例AvsCompilerArgumentConstant:
snprintf(输出,2047,“%s%.2f”,输出,pa->value.constant);
打破
案例AvsCompilerArgumentIdentifier:
snprintf(输出,2047,“%s”,pa->value.identifier);
打破
案例AvsCompilerArgumentMarker:{
字符*标记[]={“无效”,“函数”,“参数”,NULL};
snprintf(输出,2047,“%s---%s标记---”,输出,标记[pa->value.marker]);
打破
}
案例AvsCompilerArgumentPrivate:
snprintf(输出,2047,“%sprivate”,输出);
打破
}
snprintf(输出,2047,“\n”);
}
avs_调试(打印(输出));
返回视觉_OK;
}

宏avs_调试不执行任何操作。我把它的内容注释掉了。

visual\u plugin\u info\u new调用visual\u mem\u new0分配内存,在visual\u plugin\u info\u copy中分配插槽之前,您需要释放插槽。

既然您正在执行
strdup()
,您应该使用
free()
释放这些值。我不确定
visual\u mem\u free()
是否调用
free()
。如果您尝试
free()
而不是
visual\u mem\u 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
。您是否在编译代码时启用了警告?

在您发布的最后一段代码中,可能至少有两个问题(编辑该问题会让您对您现在要处理的问题感到非常困惑):

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

  • snprintf()
    调用中,不能将目标缓冲区也用作源。该标准说,“如果复制发生在重叠的对象之间,则行为未定义”。如果您想一想,您可能会意识到,在一般情况下,如果不先将缓冲区复制到其他地方,它是无法工作的。尝试在
    vsnprintf()
    (可能名为
    snprintfcat()
    )周围创建一个包装器,将格式化字符串连接到目标缓冲区。这不是很难做到,尽管它需要使用varargs,这可能有点棘手,但只需要一点

  • 以下是对
    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;
    }
    
    int snprintfcat(字符*dest,大小大小,字符常量*fmt,…)
    {
    尺寸长度=标准长度(目的地、尺寸);
    大小\u t余数=0;
    int结果;
    va_列表ap;
    如果(长度<尺寸){
    余数=尺寸-长度;
    }
    va_启动(ap、fmt);
    结果=vsnprintf(目的地+大小剩余、剩余、fmt、ap);
    va_端(ap);
    返回结果+大小-余数;
    }
    
    具体来说,如valgrind输出所示,您需要