geomagas Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 Πολύ πιθανόν να έχω κολλήσει σε κάτι προφανές, αλλά μου έχει σπάσει τα νεύρα! Έστω το παρακάτω: char *getlexeme(lexer *dfa,char **srcpos) { char *token_start=*srcpos; // ... // do stuff // ... // *srcpos is guaranteed >=token_start char *str=malloc(*srcpos-token_start+1); strncpy(str,token_start,*srcpos-token_start); return str; } token *gettoken(lexer *dfa,char **srcpos) { char *l; symbol *s; while((l=getlexeme(dfa,srcpos))[0]) // l>"" { s=dfa->current->symbol; if(s&&(/*some other conds*/)) { printf("i[%s]",l); free(l); } else { printf("r[%s]\n",l); return tokenize(s,l,NULL); } } printf("EOS!\n"); return tokenize(dfa->eos,"<EOS>",NULL); } char *txt="\n"; token *t=gettoken(somedfa,&t); Έτσι όπως είναι, δεν εκτυπώνει ποτέ "EOS!\n". Αν βγάλω την free(l); δουλεύει κανονικά, αλλά προφανώς δεν ελευθερώνεται η μνήμη, όπως θα ήθελα... Τι χάνω;
imitheos Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 Το μήνυμά μου δεν θα βοηθήσει πολύ (έως καθόλου) αλλά θέλω να ρωτήσω αν ο κώδικας που δεν δουλεύει είναι ακριβώς έτσι ? Το ρωτάω γιατί μερικές εκφράσεις είναι παράξενες. π.χ Στο printf γιατί έχεις δύο l ορίσματα ενώ έχεις ορίσει μόνο ένα %s Στην getlexeme, εφόσον το token_start δείχνει στο *srcpos, η έκφραση "*srcpos-token_start" δεν είναι μηδενική οπότε η malloc δεσμεύει 1 θέση και η strncpy δεν αντιγράφει τίποτα ? Άκυρο. Ό,τι να ναι διαβάζω. Στα σχόλια λες ότι υπάρχει και άλλος κώδικας που αυξάνει το srcpos. Μες τη χαζομάρα είμαι.
geomagas Δημοσ. 14 Ιουνίου 2014 Μέλος Δημοσ. 14 Ιουνίου 2014 π.χ Στο printf γιατί έχεις δύο l ορίσματα ενώ έχεις ορίσει μόνο ένα %s Διότι είχε ξεμείνει έτσι... Το διόρθωσα. Στη συγκεκριμένη συνάρτηση, αυτός είναι ο κώδικας αυτούσιος*. Δεν ξέρω αν θα βοηθήσει ή θα μπερδέψει περισσότερο, αλλά ολόκληρη η getlexeme() είναι αυτή: char *getlexeme(lexer *dfa,char **srcpos) { char *token_start=*srcpos,*t=*srcpos,c; dfa->current=dfa->start; int i,nedges; printf("%c(%d)",**srcpos,**srcpos); while(c=**srcpos) { nedges=dfa->current->nedges; for(i=0;i<nedges;i++) if(strchr(dfa->current->edge[i].charset,c)) { dfa->current=dfa->current->edge[i].target; (*srcpos)++; break; } if(i==nedges) break; // no shift, dead end! } char *str=malloc(*srcpos-token_start+1); strncpy(str,token_start,*srcpos-token_start); return str; } * EDIT: Εχμ... εκτός από το if, που είνα αυτό: if(s&&((s->kind==2)||(s->kind==4)||(s->kind==5)||(s->kind==6)))
imitheos Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 Στη περίπτωση που δεν εμφανίζει το EOS παίρνεις κάποιο μήνυμα λάθους ή το while παίζει επ αόριστον ?
migf1 Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 Έτσι όπως είναι, δεν εκτυπώνει ποτέ "EOS!\n". Αν βγάλω την free(l); δουλεύει κανονικά, αλλά προφανώς δεν ελευθερώνεται η μνήμη, όπως θα ήθελα... Τι χάνω; Δεν δίνεις πολλά info για να το δω πιο διεξοδικά, αλλά από ότι δείχνεις φαίνεται πως η συνθήκη: if ( s && /* someother stuff */ ) είναι πάντα TRUE; ΥΓ. Άσχετο, μετά το char *str=malloc(*srcpos-token_start+1); βάλε check για NULL πριν πας στην strncpy() EDIT: Α, έβαλες νέο κώδικα; Κάτσε να το δω μήπως μπορέσω να βοηθήσω.
geomagas Δημοσ. 14 Ιουνίου 2014 Μέλος Δημοσ. 14 Ιουνίου 2014 Στη περίπτωση που δεν εμφανίζει το EOS παίρνεις κάποιο μήνυμα λάθους ή το while παίζει επ αόριστον ? Όχι, τερματίζει κανονικά. Και μάλιστα από το 2ο return, γιατί το επόμενο l=getlexeme(...) θα δώσει "\0".
geomagas Δημοσ. 14 Ιουνίου 2014 Μέλος Δημοσ. 14 Ιουνίου 2014 ΥΓ. Άσχετο, μετά το char *str=malloc(*srcpos-token_start+1); βάλε check για NULL πριν πας στην strncpy() Έχεις δίκιο, το έκανα. Στη περίπτωση που δεν εμφανίζει το EOS παίρνεις κάποιο μήνυμα λάθους ή το while παίζει επ αόριστον ? Όχι, τερματίζει κανονικά. Και μάλιστα από το 2ο return, γιατί το επόμενο l=getlexeme(...) θα δώσει "\0". Τώρα πρόσθεσα στο τέλος: printf("%s\n",t->value); και μου βγάζει segfault στη μέση της printf("i[%s]",l): (10)i[ Segmentation fault (core dumped) Βαλε ενα breakpoint να δεις τι παιζει... Όντως, βάλτο στον debugger. Στην τελική θα το κάνω κι έτσι, αλλά δεν είναι πολύ κουλό;
migf1 Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 Κάτι βρήκα νομίζω... char *l; symbol *s; while ( (l = getlexeme(dfa,srcpos))[0] ) // l>"" { μάλλον ήθελες... while ( (l = getlexeme(dfa,srcpos)) ) // l>"" { μιας και η getlexme() επιστρέφει char * (και άρα το [0] δίνει char, ενώ το l το έχεις ορίσει ως char *) EDIT: Μπα όχι, άκυρο! Σωστά τις έχεις τις παρενθέσεις. Debugger, debugger!
defacer Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 Αφού αν βγάλεις τη free τερματίζει αυτό σημαίνει ότι η συμπεριφορά του προγράμματος εξαρτάται από τον τυχαίο παράγοντα του τι υπάρχει στη μνήμη που σου γυρνάει η malloc() -- βγαίνοντας η free ο allocator σου γυρνάει άλλα πράγματα που τυχαίνει να έχουν άλλες τιμές οπότε αλλάζει η συμπεριφορά του. Μέχρι εδώ ήδη ξέρεις ότι έχεις bug γιατί το να εξαρτάσαι από το τι σκουπίδια έχει η μνήμη που σου γυρνάει η malloc δεν είναι βέβαια σωστό. Η malloc γίνεται στην getlexeme οπότε εκεί κοιτάς για το bug (ενδεχομένως όχι μέσα στον κώδικα αλλά ίσως στο contract που υπόσχεται στον caller της και τι απαιτήσεις τελικά έχει αυτός). Βλέπεις λοιπόν στη getlexeme ότι κάνεις αυτό: strncpy(str,token_start,*srcpos-token_start); Η τρίτη παράμετρος είναι η λεγόμενη "num". Τι λέει το man γι' αυτή; No null-character is implicitly appended at the end of destination if source is longer than num. Thus, in this case,destination shall not be considered a null terminated C string (reading it as such would overflow). Άρα αν ισχύει ότι *srcpos == token_start τότε η strncpy δε θα κάνει τίποτα απολύτως οπότε μένει το junk από τη malloc αναλλοίωτο να επηρρεάζει το τι γίνεται μέσα στο if εκεί που καλείς τη getlexeme. Οπότε ξέρεις πού είναι το bug, φτιάξτο (δεν έκατσα να δω ποιά είναι ακριβώς η λογική στη getlexeme). 1
geomagas Δημοσ. 14 Ιουνίου 2014 Μέλος Δημοσ. 14 Ιουνίου 2014 Debugger, debugger! Χεχε! ΟΚ! Πάω να φάω κάτι, και μετά. Στο μεταξύ, αν έχει κάποιος καμιά ιδέα, είμαι όλος αυτιά.
migf1 Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 Με αφορμή αυτό που λέει ο defacer (που είναι σωστό, και πιθανόν να είναι και το πρόβλημά σου) να προσθέσω πως εγώ σχεδόν την έχω καταργήσει την malloc() (εκτός από πολύ ειδικές περιπτώσεις) και την έχω αντικαταστήσει με την calloc(). Δηλαδή στο παράδειγμά σου θα το έκανα κάπως έτσι: ... size_t len = *srcpos - tokstart; char *str = calloc( 1, 1+len ); if ( str ) { strncpy(str, tokstart, len); } return str; } Αλλά έχει trade-off. Αν βασίζεσαι στο "immediate crash is good" μάλλον δεν θα σε βολέψει. Αν και στην προκειμένη περίπτωση που συζητάμε (και στις περισσότερες) με την malloc() δεν έχεις εγγυημένα immediate crash.
παπι Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 Στην τελική θα το κάνω κι έτσι, αλλά δεν είναι πολύ κουλό; What the fuck?
migf1 Δημοσ. 14 Ιουνίου 2014 Δημοσ. 14 Ιουνίου 2014 A, ξέχασα... αν το θυμάμαι καλά, τόσο η malloc() όσο και η calloc() δεν κάνουν fail αν τους ζητήσεις 0 bytes μνήμη, οπότε έχετε το κι αυτό υπόψη σου (ή ψάξτο αν όντως ισχύει ακόμα, γιατί εγώ πάω να δω μπαλίτσα τώρα )
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα