Ir para o conteúdo
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

pwseo

[resolvido] Erro na libertação de memória

Mensagens Recomendadas

pwseo

Olá, tenho o seguinte problema:

Tenho uma struct com dois *char (name, description) que são definidos durante o runtime e cuja memória é alocada com o realloc (para poder ter strings "dinâmicas" com um tamanho não-fixo lol).

Ao fazer free à struct que contém os *chars, pensei que devia primeiro fazer free aos *char (afinal de contas, eles foram alocados separadamente)... mas ao tentar fazer free, o prog crasha e dá-me um backtrace...

Algum palpite sobre o que poderá estar errado? Tenho a pequena impressão de que isto será mais uma vez fruto da minha inexperiência lool

typedef struct place_t {
    struct place_t *north, *east, *west, *south, *up, *down;
    char *name, *description;
} place_t;

place_t*
place_set_name(place_t *place, char *name)
{
    place->name = (char *)realloc(place->name, BLOCKS(name));
    if (place->name == NULL) {
        fprintf(stderr, "Could not allocate string for place's name.\n");
        exit(1);
    }

    strncpy(place->name, name, (BLOCKS(name) * BLOCKSIZE - 1));

    return place;
}

void
place_free(place_t *place)
{
    if (place == NULL) {
        fprintf(stderr, "Invalid place address.\n");
        exit(1);
    }
    else {
        if (place->name != NULL) {
#ifdef DEBUG
            fprintf(stdout, "place->name: 0x%08X\n", place->name);
#endif
            free(place->name);
        }
        if (place->description != NULL) {
#ifdef DEBUG
            fprintf(stdout, "place->description: 0x%08X\n", place->description);
#endif
            free(place->description);
        }
        free(place);
    }
}

e o backtrace:

laptop% ./main
|North West House|
|This is a very very very very very long loooooooooooong description spanning more and more characteres than you could possibly imagine..... YES  it is BIG :DDDDDDDDDDDDDDDDDDDDDDDDDDDDDd|
place->name: 0x095A7030
place->description: 0x095A7040
*** glibc detected *** ./main: free(): invalid next size (fast): 0x095a7040 ***
======= Backtrace: =========
/lib/libc.so.6(+0x6bb61)[0xb7791b61]
/lib/libc.so.6(+0x6d3b8)[0xb77933b8]
/lib/libc.so.6(cfree+0x6d)[0xb77964ad]
./main[0x804886b]
./main[0x8048602]
/lib/libc.so.6(__libc_start_main+0xe6)[0xb773cb86]
./main[0x8048501]
======= Memory map: ========
08048000-08049000 r-xp 00000000 08:07 10830      /home/pedro/work/game/main
08049000-0804a000 rw-p 00000000 08:07 10830      /home/pedro/work/game/main
095a7000-095c8000 rw-p 00000000 00:00 0          [heap]
b75b6000-b75d2000 r-xp 00000000 08:05 6934       /usr/lib/libgcc_s.so.1
b75d2000-b75d3000 rw-p 0001c000 08:05 6934       /usr/lib/libgcc_s.so.1
b7600000-b7621000 rw-p 00000000 00:00 0 
b7621000-b7700000 ---p 00000000 00:00 0 
b7725000-b7726000 rw-p 00000000 00:00 0 
b7726000-b7867000 r-xp 00000000 08:05 783        /lib/libc-2.11.1.so
b7867000-b7869000 r--p 00140000 08:05 783        /lib/libc-2.11.1.so
b7869000-b786a000 rw-p 00142000 08:05 783        /lib/libc-2.11.1.so
b786a000-b786d000 rw-p 00000000 00:00 0 
b7899000-b789b000 rw-p 00000000 00:00 0 
b789b000-b789c000 r-xp 00000000 00:00 0          [vdso]
b789c000-b78b8000 r-xp 00000000 08:05 761        /lib/ld-2.11.1.so
b78b8000-b78b9000 r--p 0001b000 08:05 761        /lib/ld-2.11.1.so
b78b9000-b78ba000 rw-p 0001c000 08:05 761        /lib/ld-2.11.1.so
bfead000-bfec2000 rw-p 00000000 00:00 0          [stack]
zsh: abort      ./main

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Localhost

Alocaste a struct?  ::P

Podes até nem ter alocado e não ter atribuído logo ao ponteiro NULL e ele vai acabar por libertar algo indefinido.


here since 2009

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Localhost

Dei uma olhada por alto e parece-me que o ponteiro *a não está a ser actualizado quando chamas as funções.


here since 2009

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pwseo

Dei uma olhada por alto e parece-me que o ponteiro *a não está a ser actualizado quando chamas as funções.

A que te referes? As funções recebem o a como parâmetro, operam em a->name e a->description e depois até imprimo as strings que foram lá armazenadas... O que queres dizer com "não está a ser actualizado"? :P

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Localhost

Desculpa. Foi um return que me confundiu.

O erro está a acontecer porque tu alocaste uma struct. Essa struct contém strings, ou seja, tu não podes libertar as strings mas sim a struct apenas. Ao libertares a struct libertas tudo o que está "dentro" dela.


here since 2009

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pwseo

Desculpa. Foi um return que me confundiu.

O erro está a acontecer porque tu alocaste uma struct. Essa struct contém strings, ou seja, tu não podes libertar as strings mas sim a struct apenas. Ao libertares a struct libertas tudo o que está "dentro" dela.

Então para poder libertar a struct E as strings separadamente, a struct teria de conter apontadores para strings, ou seja, apontadores para apontadores de char. (**char?). É que ainda me custa um pouco a ideia de que reservei o espaço para as strings independentemente da struct e o free da struct liberta tudo :S

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Localhost

Tinhas de seguir isso mas tens de ter em atenção de que se libertares a struct que está alocada dinamicamente lá se foram os teus ponteiros todos e as strings ficam "à deriva".

Será algo como isto:

#define SIZE 10

typedef struct {
  char *heapStr;
}blah

blah *pt = (blah *)malloc(sizeof(blah));
pt->heapStr = (char *)malloc(SIZE);
free(pt->heapStr);

A ideia é esta.


here since 2009

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pwseo

Mas foi precisamente isso que eu fiz, e que dava erro:

typedef struct place_t {
    char *name, *description;
} place_t;

place_new(void)
{
    place_t *place;

    place = (place_t *)malloc(sizeof(place_t));
    //...
    return place;
}

place_t*
place_set_name(place_t *place, char *name)
{
    place->name = (char *)realloc(place->name, BLOCKS(name));
    // ...
    return place;
}

place_free(place_t *place)
{
    if (place == NULL) {
        fprintf(stderr, "Invalid place address.\n");
        exit(1);
    }
    if (place->name != NULL) {
        free(place->name);
    }
    //...
    free(place);
}

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
Localhost

Eu experimentei, não me deu crash nenhum.

Deixo aqui até o código:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char *str;
}blah;

int main(void) {
    blah *pt = malloc(sizeof(blah));
    pt->str = malloc(10);
    strcpy(pt->str,"Localhost ");
    printf("%s\n", pt->str);
    free(pt->str);
    free(pt);
    return 0;
}


here since 2009

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pwseo

Pois, vou ter que ver bem aquela utilização da strncpy, provavelmente o valgrind queixa-se de algo que se passa por lá :) Porque de resto o teu código está basicamente como o meu (apenas mais simples lol)

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pwseo

O problema estava aqui:

place_t*
place_set_name(place_t *place, char *name)
{
    place->name = (char *)realloc(place->name, BLOCKS(name));
    // ...
    return place;
}

Onde diz BLOCKS(name) deveria dizer BLOCKS(name) * BLOCKSIZE. Que erro parvo :s

Obgd pela ajuda, Localhost!

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites
pwseo

BLOCKS é uma macro para alocarmos memória para a string em blocos de tamanho BLOCKSIZE (que era 50). Uma string de 40 caracteres teria um bloco de 50, uma de 70 caracteres precisaria de 2 blocos (100).

Eu basicamente estava a alocar o número de blocos e não o número de bytes necessários porque não estava a multiplicar o número de blocos pelo número de bytes por bloco :)

Partilhar esta mensagem


Ligação para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!

Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.

Entrar Agora

×

Aviso Sobre Cookies

Ao usar este site você aceita os nossos Termos de Uso e Política de Privacidade. Este site usa cookies para disponibilizar funcionalidades personalizadas. Para mais informações visite esta página.