Δημοσιεύτηκε: 10 Σεπ 2011, 09:58
Ελπίζοντας πως έχετε καταλάβει τα του προηγούμενου ποστ, πάμε να φτιάξουμε τις μέχρι τώρα συναρτήσεις μας να είναι πιο ασφαλείς !
Στην γραμμή 54 του κώδικά μας, στη main(), έχουμε προνοήσει και ελέγχουμε ώστε αν ο δείκτης table είναι NULL μετά το malloc() (επειδή π.χ. απέτυχε να δεσμευτεί μνήμη για αυτόν) να ειδοποιούμε τον χρήστη και να τερματίζουμε το πρόγραμμα).
Τι θα γινόταν όμως αν δεν κάναμε τον έλεγχο αυτόν και αφήναμε τη ροή να συνεχίσει; Για να δείτε τι θα γινόταν απενεργοποιήστε προσωρινά τη γραμμή του malloc() (για να είναι NULL ο table, λόγω της αρχικοποίησης στον ορισμό του) καθώς και τις γραμμές του ελέγχου μετά το malloc() και τρέξτε το πρόγραμμα. Για να απενεργοποιείτε στα γρήγορα συνεχόμενες γραμμές κώδικα, μπορείτε να χρησιμοποιείτε το pre-processor directive #if #endif, δηλαδή για το παραπάνω:
Αυτό που θα γίνει είναι πως η memset() θα παράξει segmentation-fault ! Απενεργοποιήστε την κι αυτή προσωρινά, καθώς και το puts() που ακολουθεί για να παέι η ροή απευθείας στη γραμμή που καλεί τη συνάρτηση:
Θα διαπιστώσετε πως και αυτή θα παράξει segmentation-fault !
Η επόμενη άσκηση λοιπόν είναι να τροποποιήσετε τον κώδικα των συναρτήσεων: tablen(), table_print_stats() και table_print_contents() ώστε να μην παράγουν segmentation-fault όταν ο πίνακας είναι NULL.
Σκεφτείτε το σαν ένα 2ο επίπεδο ασφάλειας, σε περίπτωση που μας διαφύγει να κάνουμε τον σχετικό έλεγχο στη main(). Αυτή η πρακτική πρέπει να μας γίνει συνήθεια σε ΟΛΕΣ τις συναρτήσεις που δέχονται δείκτες ως ορίσματα!
Στην γραμμή 54 του κώδικά μας, στη main(), έχουμε προνοήσει και ελέγχουμε ώστε αν ο δείκτης table είναι NULL μετά το malloc() (επειδή π.χ. απέτυχε να δεσμευτεί μνήμη για αυτόν) να ειδοποιούμε τον χρήστη και να τερματίζουμε το πρόγραμμα).
Τι θα γινόταν όμως αν δεν κάναμε τον έλεγχο αυτόν και αφήναμε τη ροή να συνεχίσει; Για να δείτε τι θα γινόταν απενεργοποιήστε προσωρινά τη γραμμή του malloc() (για να είναι NULL ο table, λόγω της αρχικοποίησης στον ορισμό του) καθώς και τις γραμμές του ελέγχου μετά το malloc() και τρέξτε το πρόγραμμα. Για να απενεργοποιείτε στα γρήγορα συνεχόμενες γραμμές κώδικα, μπορείτε να χρησιμοποιείτε το pre-processor directive #if #endif, δηλαδή για το παραπάνω:
- Κώδικας: Επιλογή όλων
...
#if 0 // αλλάξτε το σε: #if 1 ή σβήστε το, μαζί με το #endif, για να ενεργοποιηθούν ξανά οι γραμμές
table = malloc( tabsize ); /* δέσμευση μνήμης για τον πίνακα */
if ( !table ) { /* αποτυχία δέσμευσης μνήμης */
puts("*** σφάλμα: ανεπαρκής μνήμη, τερματισμός προγράμματος..." );
exit( EXIT_FAILURE ); /* ... τερματισμός προγράμματος */
}
#endif
memset( table, EMPTYELEM, tabsize ); /* αρχικοποίηση όλων των στοιχείων */
...
Αυτό που θα γίνει είναι πως η memset() θα παράξει segmentation-fault ! Απενεργοποιήστε την κι αυτή προσωρινά, καθώς και το puts() που ακολουθεί για να παέι η ροή απευθείας στη γραμμή που καλεί τη συνάρτηση:
- Κώδικας: Επιλογή όλων
table_print_stats( table, maxelems, tabsize ); /* τύπωμα στατιστικών */
Θα διαπιστώσετε πως και αυτή θα παράξει segmentation-fault !
Η επόμενη άσκηση λοιπόν είναι να τροποποιήσετε τον κώδικα των συναρτήσεων: tablen(), table_print_stats() και table_print_contents() ώστε να μην παράγουν segmentation-fault όταν ο πίνακας είναι NULL.
Σκεφτείτε το σαν ένα 2ο επίπεδο ασφάλειας, σε περίπτωση που μας διαφύγει να κάνουμε τον σχετικό έλεγχο στη main(). Αυτή η πρακτική πρέπει να μας γίνει συνήθεια σε ΟΛΕΣ τις συναρτήσεις που δέχονται δείκτες ως ορίσματα!