从函数返回结构导致内存损坏

Returning struct from function causes memory corruption

我正在尝试 return 从一个函数到另一个函数的 FFmpeg AVDictionary 结构。我写了下面两个函数:

int get_p_metadata(State **ps, AVDictionary *metadata) {
    printf("get_p_metadata\n");

    State *state = *ps;

    if (!state || !state->pFormatCtx) {
        return FAILURE;
    }

    metadata = NULL;
    av_dict_copy(&metadata, state->pFormatCtx->metadata, 0);

    printf("count in get_p_metadata %d\n", metadata->count);

    return SUCCESS;
}

int get_metadata(State **ps) {
    printf("get_metadata\n");

    AVDictionary m;
    get_p_metadata(ps, &m);
    printf("count in get_metadata %d\n", (&m)->count);

    return SUCCESS;
}

代码编译并运行,但是当我调用 get_metadata 函数时,生成的输出是:

count in get_p_metadata 12
count in get_metadata 2073109240

谁能解释为什么每次运行此代码时 count 的值都会从 12 变为随机值?为什么在 get_p_metadata 函数 return 之后不保留 12 的值?我该如何解决这个问题?

更新:

这个解决方案有效(感谢 Cornstalks 实际阅读了 FFmpeg 文档和 linkdd 的答案):

int get_p_metadata (State **ps, AVDictionary **metadata) {
    printf("get_p_metadata\n");

    State *state = *ps;

    if (!state || !state->pFormatCtx) {
        return FAILURE;
    }

    av_dict_copy(metadata, state->pFormatCtx->metadata, 0);

    return SUCCESS;
}

int get_metadata(State **ps, AVDictionary *metadata) {
    printf("get_metadata\n");

    AVDictionary *m = NULL;
    get_p_metadata (ps, &m);
    printf("count in get_metadata %d\n", m->count);

    return SUCCESS;
}

这些说法有何重大意义?!

metadata = NULL;
av_dict_copy(&metadata, state->pFormatCtx->metadata, 0);

如果您将指向对象 m 的指针作为参数传递给第二个函数

AVDictionary m;
get_p_metadata(ps, &m);

那么你似乎要使用它的值或对象本身。否则传递指针是没有意义的。

此代码毫无意义

  metadata = NULL;
    av_dict_copy(&metadata, state->pFormatCtx->metadata, 0);

您传入了一个我认为要更新的元数据对象的指针。现在您将该指针设置为空,调用更新该指针的函数。由于我们看不到您的其他功能,因此很难知道您的意图,因此我无法提出修复建议

你从这两个语句中得到不同的答案,因为它们打印的是不同对象的字段。虽然 get_metadata()&m 传递给 get_p_metadata(),但该函数完全忽略传递的值,并将参数值重新分配给 NULL。坦率地说,我很惊讶你没有遇到段错误。

我想你在设置 metadata = NULL 中的 objective 是为了创建一个新的元数据对象,但是接收指向该新元数据对象的指针的局部变量与传递的参数之间没有联系到函数。

也许你想要

int get_p_metadata(State **ps, AVDictionary **metadata) {
    ...
}

int get_metadata(State **ps) {
    printf("get_metadata\n");

    AVDictionary *m;
    get_p_metadata(ps, &m);
    printf("count in get_metadata %d\n", m->count);

    // NOTE: *m was dynamically allocated and needs to be cleaned up or returned

    return SUCCESS;
}

您在调用 av_dict_copy 之前将 metadata 设置为空指针。我想知道为什么这甚至有效,并假设 av_dict_copy 做了一些与您预期不同的事情(即为 AVDictionary* 设置一个值,其地址作为第一个参数传递)。无论哪种方式,您都失去了与本地 AVDictionary m 的连接,而 2073109240 只是内存中的一些随机值。

根据av_dict_copy的声明:第一个参数"dst"是一个指向AVDictionary结构的指针。如果*dst为NULL,这个函数会为你分配一个struct,放在*dst

对于您的代码,您不应该将 "metadata" 分配给 NULL,因为它已经指向一个 AVDictionary 结构,那么它应该没问题。

如果元数据为 NULL,则意味着 av_dict_copy 创建一个新的 AVDictionary 结构并更改其中的值,而 get_metadata(State **ps) 中定义的结构保持不变,所以你得到任意值。

实际上,在您的 get_p_metadata() 中,您有一个参数 AVDictionary *metadata

你可以认为它是get_p_metadata()中的局部变量。 因此,&metadata 将引用局部变量,而不是 get_metadata().

中的 m 变量

get_p_metadata()的开头,metadata设置为m的地址,然后你重新设置为NULL。

您应该尝试以下方法:

int get_metadata (State **ps)
{
    AVDictionary *m = NULL;
    get_p_metadata (ps, &m);
    av_dict_free (&m);
    return SUCCESS;
}

int get_p_metadata (State **ps, AVDictionary **metadata)
{
    /* ... */

    av_dict_copy (metadata, state->pFormatCtx->metadata, 0);

    /* ... */
}

这样,如果 *metadataNULLav_dict_copy() 将为您的 AVDictionary 分配内存,这是它现在的初始值。

最后av_dict_free()会释放字典占用的内存。