Возможно, ресурс не выпущен? Что может вызвать это? - PullRequest
2 голосов
/ 26 января 2010

Я работаю над проектом и дошел до того, что всплыла следующая трассировка стека:

#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. Эта функция просто выделяет память. Он ничего не знает о плагине-> авторе.

Редактировать: Дух. Memcopy прямо перед тем, как strdup заполняет память.

Редактировать: Хорошо, это избавляет от одной утечки памяти. Я не уверен, что начальная трассировка стека связана с утечкой памяти - она ​​все еще там, например. Я пытаюсь выпустить какой-то ресурс, которому я верю. Часть этой программы использует много скомпилированных сборок (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 ]

3 голосов
/ 26 января 2010

visual_plugin_info_new вызывает visual_mem_new0, который выделяет память, вам нужно освободить слоты перед их назначением в visual_plugin_info_copy.

1 голос
/ 26 января 2010

Поскольку вы делаете strdup(), вы должны освободить значения, используя free().Я не уверен, что visual_mem_free() звонит free().Если вы попробуете free() вместо visual_mem_free(), ошибка valgrind исчезнет?

Редактировать : Ваши snprintf() вызовы неверны:

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

snprintf() - это C99, и стандарт гласит (7.19.6.5p2):

Если копирование происходит между перекрывающимися объектами, поведение не определено.

Точное утверждение также относится к sprintf() в C89.

Самый простой способ решить вашу проблему - это что-то вроде:

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 в качестве первого аргумента в одном из вызовов.Вы компилируете свой код с включенными предупреждениями?

0 голосов
/ 26 января 2010

Вероятно, в последнем фрагменте кода, который вы опубликовали, есть по крайней мере 2 проблемы (редактирование вопроса оставляет очень запутанным представление о том, с какой проблемой вы пытаетесь сейчас столкнуться):

  1. У вас есть строка, которая начинается snprintf(stderr, 2047, etc...).Это почти наверняка ошибка копирования-вставки, так как она не должна компилироваться.Вы, вероятно, намеревались использовать fprintf().

  2. Вы не можете использовать целевой буфер также в качестве источника в вашем 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;
}
...