Jump to content
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

Sign in to follow this  
pwseo

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

Recommended Posts

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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other sites
pwseo

Além disso, passei agora isto pelo valgrind e dá montes de avisos... algum conselho? :s

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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);
}

Share this post


Link to post
Share on other 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

Share this post


Link to post
Share on other 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)

Share this post


Link to post
Share on other 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!

Share this post


Link to post
Share on other 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 :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.