RISOLTO Seg-fault causato da non capisco bene cosa

Pubblicità
Stato
Discussione chiusa ad ulteriori risposte.

Hero467

Utente Attivo
Messaggi
695
Reazioni
405
Punteggio
75
Allora, io per divertimento e per imparare bene a programmare in C ho deciso di creare un compilatore da un linguaggio (molto basico) progettato da me a bytecode, sempre progettato da me.
In questo momento, visto che ho appena cominciato, mi trovo alla fase del lexer/tokenizer, e sono riuscito a fare un prototipo funzionante che traduce da input testuale a tokens. Giunto però al momento di stampare i tokens a schermo per verificare l'efficacia di quello che ho fatto, ricevo un seg-fault che sembra provenire da un printf("\n"); che, però, a logica non può essere. E infatti anche se sostituisco il printf con un putchar ottengo lo stesso il seg-fault.

Allego codice:
C:
int main(int argc, char *argv[]) {
    char *file = "/home/ricky/coding/c/language/compiler/prova.txt";
    char *file_content = read_file(file);

    Token *tokens = tokenize(file_content);

    int i = 0;
    Token token;
    while ((token = tokens[i]).type != TOKEN_EOF) {
        printf("%s ", token_lookup(token));
        i++;
    }
    putchar('\n');
  
    return 0;
}
La funzione tokenize() prende in input il contenuto di un file con delle istruzioni di prova per vedere se funziona tutto e ritorna un Token* con dentro tutti i tokens convertiti dalle istruzioni, più un TOKEN_EOF alla fine.
Con il while itero attraverso l'array e converto da Token (che è un enum) a stringa che posso stampare a schermo tramite token_lookup(). In teoria, quando il loop arriva a TOKEN_EOF (che ripeto, c'è sempre) si interrompe e stampa un newline per andare a capo. Quello che succede invece (almeno per il debugger) è che il loop si interrompe correttamente a TOKEN_EOF e fa un seg-fault al putchar/printf/quello che è. Ho anche provato a rimuovere completamente qualsiasi output perché magari c'era qualcosa di oscuro con stdout che non capivo e mi causava il segfault, ma niente. Quindi è evidente che il problema sia nel loop anche se non capisco dove.

Non credo serva, ma nel dubbio metto la repo di tutto il progetto perché magari il problema risiede da un'altra parte. REPO.

Vi prego di non soffermarvi troppo sulla qualità del codice, la cui sono consapevole essere molto molto bassa.
 
Ultima modifica:
Alla fine ho risolto, il problema stava nella funzione token_lookup()che utilizzava un puntatore non inizializzato per una stringa allocata dinamicamente. Il compilatore e il debugger non mi segnalavano la cosa perché sprintf()non si faceva troppi problemi a scrivere dove non doveva e questo corrompeva l'heap, che non veniva notato fino alla fine dell'esecuzione quando il programma faceva pulizia.
 
Non guardo la sezione per qualche giorno e compare qualche topic interessante...

Se il codice nel repo non è ancora aggiornato infatti questo è un problema: https://github.com/zampitek/compiler/blob/main/src/main.c#L53
Strano non ti dia alcun Warning, ma è molto probabile non guarda cosa torni il compilatore, guarda solo se tutti i casi sono coperti e torna sempre qualcosa.

BTW: giusto un'osservazione. I break dallo switch li puoi togliere tutti, tanto usi il return.

Attenzione perchè non mi sembra che gestisci (nel main) il caso in cui tokenize() torna NULL (https://github.com/zampitek/compiler/blob/main/src/lexer.c#L82 ).
 
Se il codice nel repo non è ancora aggiornato infatti questo è un problema: https://github.com/zampitek/compiler/blob/main/src/main.c#L53
Il repo non l'ho aggiornato perché sono passato a un self-host, ma aggiornerò. Però quel NULL al momento lo lascio lì perché mi ricorda di aggiungere la rappresentazione di nuovi token man mano che espando senza corrompermi la memoria


Strano non ti dia alcun Warning, ma è molto probabile non guarda cosa torni il compilatore, guarda solo se tutti i casi sono coperti e torna sempre qualcosa.
Ho anche provato a fare il debug con GDB e cercare eventuali memory corruption o leak con valgrind, ma il primo non mi è stato utile e il secondo mi ha segnalato tutto meno che quello, anche se sospetto di essere io a non essere stato in grado di leggere l'output.


BTW: giusto un'osservazione. I break dallo switch li puoi togliere tutti, tanto usi il return.
Si infatti nella versione aggiornata l'ho fatto e ho anche migliorato la gestione della memoria


Attenzione perchè non mi sembra che gestisci (nel main) il caso in cui tokenize() torna NULL (https://github.com/zampitek/compiler/blob/main/src/lexer.c#L82 ).
In effetti no, ma non l'ho neanche preso in considerazione perché, a meno che non mi sia sfuggito qualcosa mentre scrivevo il programma (probabile), se tutto va a buon fine ma il file è vuoto ritorna almeno TOKEN_EOF, mentre se qualcosa va storto il programma si ferma direttamente. Magari da qualche parte gli faccio ritornare NULL ma in caso è stato frutto di distrazione..

Edit: ecco appunto, un NULL ce lo avevo messo
 
Stato
Discussione chiusa ad ulteriori risposte.
Pubblicità
Pubblicità
Indietro
Top