Compilação

Compilação

por Kaonan Micadei -
Número de respostas: 15
Professor,

A respeito do problema com o Windows e Linux, olhando agora vi que o Code::Blocks 8.02 usa o gcc 3.4.5. Não sei se isso responderia ao problema do programa rodar normalmente no windows e dar segmentation fault no linux.
Em resposta à Kaonan Micadei

Re: Compilação

por Kaonan Micadei -
Resolvido.

A otimização (-O2) gerou problemas no programa. Sem essa opção o programa funcionou normalmente no linux também. Também fucionou com a opção -O3, ainda não descobri se é realmente uma falha do programa ou se é só o problema dessa opção. Mesmo porque essa opção no windows não compromete o programa.

Posso deixar um comentário para que não seja utilizado essa opção na compilação ou seja utilizada a opção -O3?

Obrigado.
Em resposta à Kaonan Micadei

Re: Compilação

por Natan Costa Lima -
Segmentation fault no linux dificilmente é causado pelo compilador ou algo parecido, se apareceu com a opção O2 mas não com O3 ou outros pode ser porque você acessou um lugar inválido de memória, como a opção O2 é uma opção de otimização os lugares na memória são rearranjados pelo compilador fazendo com que você não acesse "lugares proibidos" de uma versão do executável para outra (tanto em windows quanto em linux com O3).
Em resposta à Natan Costa Lima

Re: Compilação

por Kaonan Micadei -
Natan,

Acho que entendi seu comentário. Eu não deixei muito claro o que aconteceu. O segmentation fault apareceu durante um fprintf() no arquivo de saída (tanto no stdout quanto no arquivo de texto). Considerando que não tenho controle sobre o acesso de memória que o sistema faz nesse ponto, achei realmente estranho isso ter acontecido. Por isso da pergunta.
Em resposta à Kaonan Micadei

Re: Compilação

por Francisco Reverbel -
Kaonan,

Se o programa dá segfault se compilado com alguma das opções de otimização, então muito provavelmente ele tem algum erro. Aqui o significado de "muito provavelmente" é este: há um erro em algum lugar. Ou o erro está no programa ou ele é um bug do compilador.

Se o erro estiver no programa, então ele deve ser bem sutil, pois só se manifesta com a opção -O2.

É fácil fazer o segfault aparecer? Se for, mande me o fonte do seu programa via email. Estou correndo com outras coisas e não sei se conseguirei olhar o programa antes de você entregar a versão final, mas fiquei curioso...
Em resposta à Kaonan Micadei

Re: Compilação

por Kaonan Micadei -
Só pra ter uma idéia do problema, segui a sugestão do Natan no outro

post http://paca.ime.usp.br/mod/forum/discuss.php?d=11390

e rodei o programa no gdb.

Aqui estão algumas imagens do resultado







As imagens são do meu programa rodando no Debian da pro-aluno da Física.
Em resposta à Kaonan Micadei

Re: Compilação

por Natan Costa Lima -
Compilou com -g antes de usar o gdb ?


Só para lembrar, erros que as pessoas não conseguem entender geralmente são estouros de memória.
Diferente do Java, o C deixa vc escrever em qualquer lugar, quando o lugar é proibido toma o sgmentation fault, mas quando não é pode ser qualquer coisa,
como outra variável do programa, o endereço do vetor, causando segfault em lugares estranhos do código.
Em resposta à Natan Costa Lima

Re: Compilação

por Kaonan Micadei -
Natan,

Usei -g sim, eu tinha esquecido fazer dar print screen nessa parte mas já gerei outra imagem.

Em resposta à Kaonan Micadei

Re: Compilação

por Erich Leistenschneider -
Seguindo a conversa, acontece algo muito parecido comigo. Sugiro que a otimização não seja utilizada na correção. Vejam:


-> Sem uso da opção -O :

erich@coquiles:~/USP/Algoritmos$ gcc -Wall -ansi -pedantic -U_FORTIFY_SOURCE ep1-5898752.c -o ep1

erich@coquiles:~/USP/Algoritmos$ ./ep1
Digite o nome do arquivo de entrada:
Digite o nome do arquivo de saida:

23456/234
1) 23456 / 234 = 100

23456%234
2) 23456 % 234 = 56



-> Usando -O1 :

erich@coquiles:~/USP/Algoritmos$ gcc -Wall -ansi -pedantic -O1 -U_FORTIFY_SOURCE ep1-5898752.c -o ep1

erich@coquiles:~/USP/Algoritmos$ ./ep1
Digite o nome do arquivo de entrada:
Digite o nome do arquivo de saida:

23456/234
Falha de segmentação



-> Usando -O2 :

erich@coquiles:~/USP/Algoritmos$ gcc -Wall -ansi -pedantic -O2 -U_FORTIFY_SOURCE ep1-5898752.c -o ep1

erich@coquiles:~/USP/Algoritmos$ ./ep1
Digite o nome do arquivo de entrada:
Digite o nome do arquivo de saida:

23456/234
Falha de segmentação



-> Usando -O3:

erich@coquiles:~/USP/Algoritmos$ gcc -Wall -ansi -pedantic -O3 -U_FORTIFY_SOURCE ep1-5898752.c -o ep1

erich@coquiles:~/USP/Algoritmos$ ./ep1
Digite o nome do arquivo de entrada:
Digite o nome do arquivo de saida:

23456/234
1) 23456 / 234 = 1

23456%234
2) 23456 % 234 = 23222




Em resposta à Erich Leistenschneider

Re: Compilação

por Erich Leistenschneider -
Segui a dica e também usei o gdb. Ele está encasquetando com esta linha:

i=abs(num1[0]);

Linhas como essa eu uso diversas vezes em todo o programa. Mas justamente nesta atribuição nesta função que dá problema. Isso não me faz o menor sentido!

Já fiz o teste de tirar o abs() e continua o mesmo problema... até usei i=*num1; ...mesma coisa...

Esta atribuição está logo no início do código da função:

int compara_modulo(int num1[], int num2[])
{
int m=0, i;
i=abs(num1[0]);
...
}

Embora esteja dando um resultado bizarro mas não segfault, o -O3 também está dando problema exatamente neste ponto, de acordo com alguns testes que fiz...

Estou upando o meu código aqui no paca, vocês podem dar uma olhada? Aí vai a saída do gdb:

erich@coquiles:~/USP/Algoritmos$ gcc -g -Wall -ansi -pedantic -O2 -U_FORTIFY_SOURCE ep1-5898752.c -o ep1

erich@coquiles:~/USP/Algoritmos$ gdb ep1
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) run
Starting program: /home/erich/USP/Algoritmos/ep1
Digite o nome do arquivo de entrada:
Digite o nome do arquivo de saida:

23456/234

Program received signal SIGSEGV, Segmentation fault.
compara_modulo (num1=0x0, num2=0xbfde0428) at ep1-5898752.c:407
407 i=abs(num1[0]);
(gdb)

Em resposta à Erich Leistenschneider

Re: Compilação

por Francisco Reverbel -
Depois que o gdb parar na linha 407, digite where. Esse comando faz o gdb mostrar a piha de chamadas, isto é, que função foi chamando qual até chegar ao segmentation fault. Aí você descobre quem passou alguma besteira à função compara_modulo, no parâmetro num1.

O único jeito de dar um segfault numa linha como

407 i=abs(num1[0]);

é o parâmetro num1 conter algo errado. Lembre-se que o vetor é passado à função como um endereço (ponteiro). Ou esse ponteiro não foi inicializado ou ele foi inicializado com um vetor de tamanho insuficiente. Não pode ser outra coisa...



Em resposta à Francisco Reverbel

Re: Compilação

por Erich Leistenschneider -
Deu isso:

Program received signal SIGSEGV, Segmentation fault.
compara_modulo (num1=0x0, num2=0xbfea94f8) at ep1-5898752.c:407
407 i=abs(num1[0]);
(gdb) where
#0 compara_modulo (num1=0x0, num2=0xbfea94f8) at ep1-5898752.c:407
#1 0x08048f25 in divide (num1=0xbfea95c4, num2=0xbfea94f8, quoc=0xbfea942c,
resto=0xbfea9360) at ep1-5898752.c:337
#2 0x08049846 in main () at ep1-5898752.c:114
(gdb)


Aparentemente está chamando num1 como 0x0, não é um endereço válido de vetor...

a linha que chama ele é essa:
}while(compara_modulo(aux,num2)!=-1);

vem de um do while, não vejo nada de errado nisso... o vetor aux é uma cópia ou de num1 ou de resto, dependendo da ocasião, e minha função de copia funciona bem em todos os casos.

O que não me faz sentido é funcionar normalmente sem a otimização. Já ouvi falar várias vezes que a otimização do gcc faz besteiras algumas vezes. Não pode ser este o caso?


Em resposta à Erich Leistenschneider

Re: Compilação

por Francisco Reverbel -
Abri o arquivo fonte do seu programa e olhei a função que contém a linha 337. Nessa função o vetor aux está declarado com comprimento MAX_DIGITOS. Devia ser MAX_DIGITOS+1! Logo antes da linha 337 há uma chamada copia(aux,resto). Essa chamada escreve numa posição inexistente do vetor aux, pois a sua função copia está copiando sempre MAX_DIGITOS+1 elementos, sem olhar para o comprimento real do vetor. Taí a causa desse segmentation fault.

Vi que você tem algum outros vetores declarados com comprimento MAX_DIGITOS. Não pensei muito (teria que analisar cada caso), mas provavelmente isso está errado. Sugestão: Substitua todas as ocorrências de [MAX_DIGITOS] por [MAX_DIGITOS+1].

Vi também que você aparentemente supõe que todas as posições de um "inteiro grande" (as posições do vetor de ints) estão preenchidas. A sua função digitos parece precisar dessa hipótese. Os problemas dessa hipótese são:
  1. Em vários laços a quantidade de voltas fica sendo MAX_DIGITOS, quando poderia ser menor. (A função copia deveria copiar só a parte útil do vetor. A função zera deveria zerar só a posição 0 do vetor.)
  2. O pressuposto de que os "inteiros grandes" têm tamanho fixo aparece em várias partes do programa. Isso não deixa o código ser facilmente alterável para lidar com "inteiros grandes" alocados dinamicamente (com malloc), sem nenhum limite no número de dígitos.

Em resposta à Francisco Reverbel

Re: Compilação

por Erich Leistenschneider -
Nossa, obrigado, funcionou. Típico erro bobo que agente sempre passa batido. Quanto ao utilizar todas as posições do vetor, precisei disso por causa de uma das funções que não consegui pensar em uma alternativa melhor, mas acho que já sei como melhorar, vou tentar implementar até amanhã.
Em resposta à Kaonan Micadei

Re: Compilação

por Kaonan Micadei -
Procurando como usar o gdb direito, consegui achar o problema mas agora sim estou mais confuso ainda.

Coloquei um breakpoint na função que acusava problema. Rodei até atingir o calculo que acusa o primeiro overflow. Até ai tudo bem, porém... quando ele volta para o while para verificar se acabaram as entradas ele misteriosamente zera o ponteiro de saida (saida = 0x0). O que não tem nenhum sentido.

Tentei chamar o ponteiro nas funções com o tipo "const" (const FILE*), mas a função fprintf não aceita essa chamada.

O que poderia estar zerando o endereço de saida se os únicos lugares onde ele é usado são nas funções fprintf()? E por que ele estaria acontecendo só com as otimizações -O, -O1 e -O2, mas funciona normalmente com -O3?



Obrigado.
Em resposta à Kaonan Micadei

Re: Compilação

por Francisco Reverbel -

A variável saida deve estar sendo zerada por alguma escrita na posição apontada por um ponteiro "perdido" ou por alguma escrita numa posição inexistente de algum vetor. Seria melhor se essas coisas sempre dessem segfault, mas isso nem sempre acontece. O segfault só ocorre se a posição acessada erroneamente estiver fora da área de memória do programa. Quando esses acessos errôneos à memória não dão segfault, eles causam alterações misteriosas em outras variáveis do programa.

Procure por alguma dessas coisas no caminho que o programa percorre entre a linha 470 (quando a variável saida tem um valor correto) e a linha 45 (quando essa variável já está estragada).