Salve a tutti, ho da poco terminato di realizzare un semplice clone di space invaders in C ed SDL.
Ho riscontrato varie volte che il gioco va segfault all'avvio di una particolare funzione, sia sulla mia debian 32bit che su sistemi win32, e su hardware diversi.
Mi sono affidato a gdb per provare a scovare l'arcano ma non riesco a capire cosa vada storto, questo e' l'output del debugger:
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb7cf4b30 (LWP 4992)]
0x0804adf9 in moveInvaders () at retroinvaders.c:1061
1061 if(rectCollision(Enemy[i].x, Enemy[i].y, Enemy[i].width, STD_H,
Il programma va in crash non appena inizia il movimento degli invaders nel gioco, ma non sempre, avviene in maniera del tutto casuale.
A riguardare il codice scritto, non trovo nulla di anomalo, vorrei sapere il vostro parere al riguardo, cosa potrebbe scatenare questa anomalia nel gioco?
Trovate il codice del gioco
qui.
Grazie a tutti per eventuali risposte e soluzioni :]
Ho provato a compilarlo e ad eseguirlo ma non è riuscito ad andare in SIGSEGV

E' completamente random?
Il codice, a prima occhiata, mi pare corretto!
(22-12-2011 17:04)hjeldin ha scritto: [ -> ]Ho provato a compilarlo e ad eseguirlo ma non è riuscito ad andare in SIGSEGV 
E' completamente random?
Il codice, a prima occhiata, mi pare corretto!
Si, e' casuale la cosa, per fortuna non capita sempre ma 4 volte su 6 si.
Basta semplicemente avviare il gioco e premere il tasto 1, non appena gli invaders stanno per effettuare un passo il gioco si blocca o va direttamente in segfault.
Quando si blocca senza andare in segfault, ottengo questo risultato in gdb:
Program received signal SIGINT, Interrupt.
[Switching to Thread 0xb7bebb30 (LWP 3070)]
rectCollision (x1=151566241, y1=176, w1=16, h1=16, x2=64, y2=368, w2=10, h2=8)
at retroinvaders.c:177
177 {
Si puo' notare che il primo valore passato alla funzione rectCollision da moveInvaders e' completamente sbagliato, ma non riesco a capire da cosa dipenda.
Non sono l'unico comunque ad aver riscontrato questo problema, anche altre persone che hanno provato il gioco mi hanno parlato di questa noia, ti ringrazio comunque per la risposta :]
L'unica cosa che mi viene in mente è qualche libreria "sballata", perchè l'ho chiuso e riaperto una ventina di volte senza problemi.
Così a pelle sembra che su certi gcc non apprezzi gli array di struct dichiarati globalmente nel data segment dell'applicazione. Come se andasse a recuperare male gli indirizzi quando li converte per l'accesso dei valori. Ovviamente non ha senso così di per sé però hai provato ad allocare tutto dinamicamente?
Per intendersi:
Enemy *enemies = calloc(MAX_ALIENS,sizeof(struct _Enemy));
Hai inizializzato tutte le variabili nella struct Enemy?
Comunque SDL ha le sue turbe ogni tanto... A me da windows ad esempio non riesce a caricare le immagini PNG, carica solo le bitmap. Ora... stesso codice stesso ambiente di sviluppo (codeblocks, ma da visual studio mi dà lo stesso problema).
Le dll le trova, perché le stesse funzioni le bmp le caricano... L'unica cosa che mi viene in mente è che per qualche ragione non gli piace libpng però boh...
Grazie a tutti per le risposte, comunque si, le variabili di tutte le struct vengono inizializzate in apposite funzioni all'avvio dell'applicazione.
Penso che non gli vada molto a genio il ciclo annidato nella funzione, anche se mi sembra un po' assurdo pensarlo perche' in tutto il programma avro' fatto la stessa cosa piu' di una volta senza nessun problema.
Comincio a pensare che possa essere un problema di gcc che compila male il codice, anche se compilato da windows (con mingw), alcuni mi hanno riferito che da gli stessi problemi...
Provero' a testare l'opzione di jack dell'allocazione dinamica, anche se sono molto scettico che possa risolvere il problema ._.
Codice:
[encelo@photon retroinvaders]$ cppcheck .
Checking retroinvaders.c...
[retroinvaders.c:227]: (error) Buffer access out-of-bounds
Codice:
sprintf(filename, "snd/fastinvader%d.wav", sound_index);
I venti caratteri della variabile
filename non bastano per contenere il terminatore di stringa aggiunto automaticamente al termine della stampa formattata.
Non vorrei che la scrittura di questo byte corrompesse qualche dato del gioco...
(22-12-2011 23:51)Pix3l ha scritto: [ -> ]Comincio a pensare che possa essere un problema di gcc che compila male il codice
Prima di arrivare a dubitare del compilatore ce ne vuole!
P.S.
Ti prego, aggiungi un semplice Makefile.

Direi che il problema è sicuramente quello. Sia la stringa che le struct statiche finiscono nel data segment, quindi l'ultimo carattere della stringa andrà a sovrascriversi al primo byte del primo enemy.
Ovviamente ogni compilatore si organizza lo spazio statico come vuole, motivo per cui non spunta fuori sempre l'errore. Però in ogni caso potrebbe generare segfault di vario genere (e su parti diversi di dati).. in realtà la mia soluzione avrebbe funzionato ma avrebbe solo nascosto il problema

(22-12-2011 23:58)encelo ha scritto: [ -> ] (22-12-2011 23:51)Pix3l ha scritto: [ -> ]Comincio a pensare che possa essere un problema di gcc che compila male il codice
Prima di arrivare a dubitare del compilatore ce ne vuole! 
Lezione numero 1 !
Lezione numero 2: usare una cifra di asserts(), specie se si usano array piani in C.
..poi usare snprintf() (occhio alla strncpy() invece, che non zero-termina in caso di lunghezza massima raggiunta, quindi da solo non basta)
Mi era proprio sfuggita la lunghezza della stringa filename...
Probabilmente a generare tutti quegli errori era proprio quella.
A testarlo ora, il problema sembra essere svanito del tutto, e lo spero
La cosa curiosa e' che spostando il controllo della collisione tra bunker e invaders in una funzione a parte, il problema non si presentava, misteri... o.o
@encelo: Dubitavo del compilatore perche' piu' di una volta mi sono trovato di fronte a problemi di compilazione o errata compilazione per delle stupidaggini, non tutte le versioni di gcc compilano allo stesso modo.
Una volta per compilare zsnes 1.5.1 con un gcc4, dovetti patchare il codice per renderlo "compilabile" con una versione superiore al 3, come lui anche altri programmi mi hanno fatto questo scherzetto, ormai per me e' un chiodo fisso :]
@TheCrib: Grazie per i consigli :]
Ho corretto il codice aumentando la dimensione della stringa di filename, aggiunto un make file e realizzato una versione modulare, trovate tutto
qui.
Grazie a tutti per il supporto e buon natale

(23-12-2011 11:50)Pix3l ha scritto: [ -> ]@encelo: Dubitavo del compilatore perche' piu' di una volta mi sono trovato di fronte a problemi di compilazione o errata compilazione per delle stupidaggini, non tutte le versioni di gcc compilano allo stesso modo.
Il compilatore progredisce e possono cambiare alcune cose che necessitano di modifiche nei sorgenti o nelle flag delle opzioni.
(23-12-2011 11:50)Pix3l ha scritto: [ -> ]Una volta per compilare zsnes 1.5.1 con un gcc4, dovetti patchare il codice per renderlo "compilabile" con una versione superiore al 3, come lui anche altri programmi mi hanno fatto questo scherzetto, ormai per me e' un chiodo fisso :]
Nella
mia carriera di packager per ArchLinux ne ho viste di patch per ripristinare la compilazione sulle ultime versioni di GCC, ma non si tratta di bug.

Tutto questo mi ricorda la convinzione di poter ottimizzare il codice manualmente quando poi si va a compilare -Os
