Problema ao liberar regioes

Problema ao liberar regioes

por Eron Ferreira de Castro Júnior -
Número de respostas: 32

Boa tarde, pessoal!

Ao tentar liberar a lista ligada contendo as regiões, o compilador não acusa falha de segmentação. Em vez disso, mostra o mapa de memória toda vez que tento liberar a memória alocada para cada uma das células que contém as regiões conexas. Alguém teve esse erro e/ou pode me indicar como proceder para encontrar o meu erro?

Em resposta à Eron Ferreira de Castro Júnior

Re: Problema ao liberar regioes

por Caio Braz -

Esse é o problema clássico do "Double-Free"

Acontece quando você acaba dando free num bloco que já foi liberado (ou que nunca tenha sido alocado).

Provavelmente este é o problema! 

 

Em resposta à Caio Braz

Re: Problema ao liberar regioes

por Thiago Gomes -

Isso tava acontecendo comigo no Mac. Mas aí eu consertei. Testei inúmeras vezes, inclusive com o gdb.

Aí fui testar a versão consertada no Ubuntu e deu isso. Voltei a rodar no Mac e e ele roda perfeitamente. E agora? Eu não posso deixar ele como está? está funcionando no Mac.

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por Victor Sanches Portella -

Esses problemas de rodar em um S.O. e não em outro as vezes são meio confusos,
mas normalmente é devido a inicialização de variável. Uma variável que não
foi inicializada um S.O. pode as vezes inicia-la, por segurança (se não me engano).

Seja o que for, se dá errado em algum dos S.O.'s, é porque de fato tem algo errado,
e o S.O. onde não dá o erro está fazendo algo que evita que o erro seja causado.

Em resposta à Victor Sanches Portella

Re: Problema ao liberar regioes

por Thiago Gomes -

Então... já faz 3 horas que eu tô trabalhando nas funções e continuo a receber o mesmo erro.

Primeiro acho que a lógica é liberar as linhas certo?


for(contador = 0; contador < img->height; contador++)

    free(img->pixel[i]);

Pelo o que eu pude perceber o erro ocorre no primeiro looping, ou seja, free(img->pixel[0]). Eu pus para ele imprimir o endereço da memória e é um endereço normal. Aí eu tentei criar variáveis auxiliares do tipo:

PixelRGB **matriz;

matriz = img->pixel;

for(...)

   free(matriz[i])

E ele continou a dar o mesmo erro. Aí eu passei para o segundo looping, que seria free(img->pixel[1]), que aponta para um outro endereço normal da memória, mas o erro tbm acontece aí.

 O Caio falou que o double free pode ocorrer ao tentar liberar algo que nem foi alocado. Mas esse não é o caso, pq se não tivesse sido alocado, o programa não funcionaria corretamente e ele funciona perfeitamente, exceto na hora de sair e liberar a memória que ocorre esse erro no linux.

O que pode ser isso? Eu revisei todas as funções que alocam e liberam memória mais de 3 vezes e tentei modificá-las, mas não deu certo. = /

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por Gabriel Ogawa -

Tenta mandar imprimir todos os endereços sendo liberados e vê se algum se o último mostrado antes do erro se repete anteriormente. Também seria uma boa checar o conteúdo da célula.

Eu também tive esse erro e, no meu caso, o problema foi na liberação das regiões por um erro na hora de ligar as listas que passou despercebido por causa da recursão.

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por Caio Braz -

Provavelmente foi um typo, mas se seu código está assim:

for(contador = 0; contador < img->height; contador++)
    free(img->pixel[i]);

Basta trocar o pixel[i] por pixel[contador] que resolve o problema.

Seguir a order de desalocação que o Gustavo sugeiru é o correto também!

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por José Coelho de Pina -

Oi Thiago,

Complementando o que o Victor descreveu.
O seu programa está com algum erro...
Por sorte ou por azar o erro não está se manifestando no MAC, mas ele está lá.
Vou ilustrar isto com um exemplo.
O programa a seguir pretende calcular a soma de uma sequência de números inteiros
terminada por um zero (Problema 1 de MAC0110, acho).

int main()
{
   int soma;
   int numero;

   printf("Digite um numero: ");
   scanf("%d", &numero);
   while (numero != 0)
     {
       soma += numero;
       printf("Digite um numero: ");
       scanf("%d", &numero);
     }

   printf("Soma = %d\n", soma);
   return 0;
}

Esse programa "funciona" no Ubuntu e não "funciona" no Windows.
Nas últimas distribuições linux do Ubuntu, talvez por questões de segurança, as variáveis com zero.
Este comportamento não é definido pela linguagem e portanto não podemos
contar com isso (como ocorre em outras linguagens).

Bem, voltando ao EP (e as notas de aula).
Nas notas de aula da AULA 07 o seguinte trecho de código
é apresentado para alocar uma matrz:

int **a;
int i;
a = mallocSafe(m * sizeof(int *));
for (i = 0; i < m; i++)
  a[i] = mallocSafe(n * sizeof(int);

Entretanto, nas notas de aula eu não escrevi como liberar essa área.
Acrescentarei o trecho a seguir às notas de aula.
Notem que os passos para liberar são os inversos aos da alocação.
Acho que isto é essencialmente o que o Caio e o Gustavo sugeriram.

for (i = 0; i < m; i++)
  free(a[i]); /* libera cada linha da matriz */

free(a); /* libera o vetor de ponteiros para as linhas */
Em resposta à José Coelho de Pina

Re: Problema ao liberar regioes

por Thiago Gomes -

Obrigado à todos pelas respostas. Eu refiz as funções seguindo o que todos disseram, inclusive, adaptei o modelinho do Coelho para dar free na função, mas mesmo assim não deu. Ele continua a dar o erro double free or corruption na hora de sair. = /

Aproveitando o comentário aí de cima, no meu caso, eu consigo liberar a imagem (free(img)), mas na hora de liberar as linhas da matriz de pixel (free(img->pixel[i]) ele dá o erro.

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por Caio Braz -

Achamos o erro então, a ordem dos frees

Uma regrinha bem básica pra gente não se perder é a seguinte: "os frees devem ser na ordem inversa dos mallocs"

Isso quer dizer:

No seu EP você provavelmente fez:

img = malloc(...);
img->pixel = malloc(...);
for (...) img->pixel[i] = malloc(...);

então os frees tem que ser na ordem:

for (...) free(img->pixel[i]);
free(img->pixel);
free(img);

Se não seguir esta ordem, no momento em que você libera o img, você não consegue mais acessar nada que tinha dentro dele, causando assim o erro do free

Confere ai! mostrando a língua

Em resposta à Caio Braz

Re: Problema ao liberar regioes

por Thiago Gomes -

Caio, eu conferi e é essa ordem mesmo que eu tô usando, mas mesmo assim continua a dar esse erro sem sentido. =/

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por Caio Braz -

Então confira o tipo e o tamanho de cada malloc e quanto você está percorrendo no for.

Outra coisa, pra tantar debugar, tente colocar um:

if (img->pixel[i] == NULL) antes de dar free, pra achar onde está o erro, pode parecer bobo mas as vezes o erro está em algum outro canto (isto é, não na alocação nem no free) e acabou estourando ai =/

Em resposta à Caio Braz

Re: Problema ao liberar regioes

por Thiago Gomes -

Eu baixei e rodei o programa como graphic.c novo e ele não acusou nada professor.

Talvez eu tenha esquecido de mencionar, mas a minha função freeRegioes() está funcionando. Eu testei ela individualmente. Fiz minha função quit() chamar apenas ela e deu tudo certo. Agora me resta a função freeImagemRGB que está causando todo o problema.

Caio eu tentei o que vc falou de checar if (img->pixel[i] == NULL) antes de dar free, mas não deu.

Uma observação, na minha função quit() eu chamo as funçoes free nessa ordem:

/* Libera a lista de regiões */
freeRegioes(listaRegioes)

/* Libera a imagem da tela */
freeImagemRGB(tela);

/* Libera a imgem original */
freeImagemRGB(img) 

Será possível que as linhas da matriz já tenham sido liberadas durante o programa?! Eu sei que, pelo menos no módulo imagem.c, isto é impossível pq eu só uso  free() nessas duas funções. 

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por José Coelho de Pina -

Vamos tentar o seguinte:

No início da função freeImagem coloque:

    printf("Entrei na freeImagemRGB\n");

e no final

    printf("Sai da freeImagemRGB\n");

Faça algo semelhante com a freeRegioes.

Veja em qual função o programa explode.

Em resposta à José Coelho de Pina

Re: Problema ao liberar regioes

por Thiago Gomes -

É o meu explode na freeImagemRGB.

Entrei na freeImagemRGB
*** glibc detected *** ./ep2: double free or corruption (out):0x00000000012ec1d0 ***

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por José Coelho de Pina -

boca aberta Tenho um chute!

No main vocês devem criar temos

  /* 2. carregue a imagem do arquivo*/

  /* 3 crie a tela (imagem) em que trabalharemos */

A função que carrega a imagem em 2 já faz a alocação e tudo mais.
Ela retorna o ponteiro para a imagem.
Já em 3 você precisa usar a função mallocImagemRGB para cria a tela.

É possível que tela e imagemOriginal sejam ponteiros para a mesma estrutura?
Se este for o caso a opção 'o' não deve redenhar a imagem original. Isto ocorria se, por exemplo, no main estivesse:

  /* 4 copie a imagem lida para a tela */ 
  tela = imgOriginal; /* ERRO */

P.S. O problema não pode ser na função freeImagemRGB ela é muito simples. Só se houver algum erro de digitação. Está liberando img->width linhas em vez de img->height.

Em resposta à Caio Braz

Re: Problema ao liberar regioes

por Eron Ferreira de Castro Júnior -

Então, Caio, mas eu acredito estar alocando. Eu consigo andar na lista ligada, só não consigo liberá-la. Você acha que a forma com que gero a lista ligada pode estar influenciando?

Em resposta à Eron Ferreira de Castro Júnior

Re: Problema ao liberar regioes

por Caio Braz -

Então provavelmente tem algum errinho lógico que faz com que haja um segundo free.

Por exemplo, desalocar o vetor img->pixel antes de desalocar cada componente img->pixel[i].

Em todo caso, essas coisas são bem específicas, cada EP pode estar dando o problema em um lugar diferente! No seu caso, isso pode ser o caso, pois você consegue andar pela lista.

Em resposta à Eron Ferreira de Castro Júnior

Re: Problema ao liberar regioes

por José Coelho de Pina -

Oi Eron,

Ao tentar liberar a lista ligada contendo as regiões, o compilador não acusa falha de segmentação.

 Só para eu entender o que está rolando.
Você poderia copiar e colar aqui a mensagem erro (ou pelo menos um trecho
 "relevante" da mensagem) você está recebendo.

Em resposta à José Coelho de Pina

Re: Problema ao liberar regioes

por Eron Ferreira de Castro Júnior -

Professor, eu recebo um problema do glibc, dizendo que estou tentando liberar uma região inválida.

Eu consigo liberar os pixels das regiões mas não as regiões. É estranho, porque eu aloquei a a memória para as regiões e consigo acessá-la através dos ponteiros.

Anexo Screenshot - 09062013 - 115855 AM.png
Em resposta à Eron Ferreira de Castro Júnior

Re: Problema ao liberar regioes

por José Coelho de Pina -

Oi Eron e Thiago,

Vamos ver se a gente cerca o problema.
Eu coloquei um novo arquivo graphic.c lá no diretório do esqueleto.
Por favor, copiem esse novo graphic.c compilem e executem os seu programas.

Ao testarem a opçao 'r', verifiquem no shell as mensagens que aparecem.
Esse novo graphic.c imprime, na opção 'r', uma mensagem caso detecte alguma região vazia.

Em resposta à José Coelho de Pina

Re: Problema ao liberar regioes

por Eron Ferreira de Castro Júnior -

Basicamente, o que faço é varrer a lista de pixels em listaRegioes->ini. Aí, vou dando free até que o ponteiro chegue em NULL.

Daí, percorro a lista de regiões e tento dar free até chegar ao final. Para tudo isso, uso dois ponteiros. Um, eu utilizo para guardar a proxima posicao e o outro para dar free. Sempre funcionar liberar a lista de pixels. O problema é quando chega a listaRegioes, que o ocorre o double free .

Em resposta à Eron Ferreira de Castro Júnior

Re: Problema ao liberar regioes

por Shayenne Luz Moura -

O meu dá o mesmo erro quando o programa vai fazer a segunda região.

Na primeira região funciona direitinho aloca e dá free, mas quando vai alocar uma nova celRegiao dá isso.

*** glibc detected *** ./ep2: free(): invalid next size (fast): 0x091de048 ***

 

Em resposta à Eron Ferreira de Castro Júnior

Re: Problema ao liberar regioes

por José Coelho de Pina -

Basicamente, o que faço é varrer a lista de pixels em listaRegioes->ini. Aí, vou dando free até que o ponteiro chegue em NULL.

Eron, você testou o seu programa com o novo graphic.c que coloquei na diretório do esquelto?
Se testou, qual a mensagem que aparece no shell antes do programa explodir?

Em resposta à José Coelho de Pina

Re: Problema ao liberar regioes

por Eron Ferreira de Castro Júnior -

Testei, professor! 

Aí é que está: ele não explode quando aperto r!

Em resposta à Eron Ferreira de Castro Júnior

Re: Problema ao liberar regioes

por José Coelho de Pina -

Eron,

Aí é que está: ele não explode quando aperto r!

Certo. Você colocou no código as mensagens que eu sugeri na funções freeImagemRGB e freeRegiões?


Vamos tentar o seguinte:

No início da função freeImagem coloque:

    printf("Entrei na freeImagemRGB\n");

e no final

    printf("Sai da freeImagemRGB\n");

Faça algo semelhante com a freeRegioes.

Veja em qual função o programa explode.

Em resposta à José Coelho de Pina

Re: Problema ao liberar regioes

por Eron Ferreira de Castro Júnior -

Professor, 

Meu programa só explode na freeRegioes e não consegui encontrar uma solução para o problema ainda. Acabei de te enviar meu arquivo imagem.c.

Obrigado pela atenção!

Em resposta à Eron Ferreira de Castro Júnior

Re: Problema ao liberar regioes

por Thiago Gomes -

Professor, tbm acabei de enviar o meu, apesar de não ter achado uma solução para o problema. No módulo imagem.c eu comentei em que parte do código está dando o erro. Se alguém rodar no linux acho que vai dar erro ao apertar 'q'. = /

Em resposta à Thiago Gomes

Re: Problema ao liberar regioes

por Eron Ferreira de Castro Júnior -

Ae, Thiago,  eu enviei meu programa ao professor e ele me mostrou meu erro. Veja se você não fez a mesma coisa:

Prof. José Coelho de Pina:

o seu programa não alocou o número certo de bytes para as estruturas
  dos tipos CelRegiao e CelPixel.

----------------------------------------------------------------

Para inserir uma nova região:


  CelRegiao *nova;

  /* regiao = (CelRegiao *) mallocSafe(sizeof(regiao)); ERRO */

o certo é

  regiao = (CelRegiao *) mallocSafe(sizeof(*regiao));     ou
  regiao = (CelRegiao *) mallocSafe(sizeof *regiao);      ou
  regiao = (CelRegiao *) mallocSafe(sizeof(CelRegiao)); nas aulas tenho feito assim

------------------------------

Ao inserir um pixel

  CelPixel *pixel;
  /* pixel = (CelPixel *) mallocSafe(sizeof(pixel)); ERRO */

o certo é

  pixel = (CelPixel *) mallocSafe(sizeof(*pixel));    ou
  pixel = (CelPixel *) mallocSafe(sizeof *pixel);     ou
  pixel = (CelPixel *) mallocSafe(sizeof(CelPixel)); nas aulas tenho feito assim

 

Espero que ajude!

 

Abs