Rust: ownership και ασφαλής ανάλυση εισόδου — DedSec Project
Ο borrow checker δεν αντικαθιστά τους κανόνες δεδομένων Ανέλυσε είσοδο χωρίς panic Για άγνωστο input χρησιμοποίησε Result αντί να καλείς unwrap() και να τερματίζει το πρόγραμμα. Η επιλογή…
Ο borrow checker δεν αντικαθιστά τους κανόνες δεδομένων
Ανέλυσε είσοδο χωρίς panic
Για άγνωστο input χρησιμοποίησε Result αντί να καλείς unwrap() και να τερματίζει το πρόγραμμα. Η επιλογή u16 περιορίζει το εύρος τιμών και αυτό πρέπει να ταιριάζει στον πραγματικό κανόνα. Το αποτέλεσμα parsing και η επιχειρησιακή αποδοχή μιας τιμής είναι διαφορετικά βήματα.
fn parse_port(input: &str) -> Result<u16, String> {
let value: u16 = input.parse().map_err(|_| "not a valid port".to_owned())?;
if value == 0 { return Err("port zero not allowed here".to_owned()); }
Ok(value)
}
fn main() {
assert_eq!(parse_port("8080"), Ok(8080));
assert!(parse_port("70000").is_err());
assert!(parse_port("0").is_err());
}
Τι γίνεται με το ownership;
Η συνάρτηση δανείζεται &str και δημιουργεί δικό της String μόνο για μήνυμα αποτυχίας. Δεν απαιτείται clone των αρχικών ψηφίων. Το u16 επιστρέφεται ως τιμή που αντιγράφεται, άρα δεν υπάρχει αναφορά προς προσωρινή συμβολοσειρά. Αν προσπαθούσαμε να επιστρέψουμε &str που δείχνει σε τοπικό προσωρινό String, ο compiler θα εντόπιζε πρόβλημα lifetime.
Compiler έναντι σωστής λογικής
Η Rust αποτρέπει πολλές λανθασμένες χρήσεις μνήμης, όχι όλους τους λάθος κανόνες μιας εφαρμογής. Δοκίμασε ακραίες επιτρεπτές τιμές, overflow, spaces και ειδικούς επιχειρησιακούς περιορισμούς. Κατάγραψε έκδοση toolchain και αν το cargo test εκτελέστηκε πραγματικά.
Άσκηση
Άλλαξε τον κανόνα ώστε να επιτρέπεται το μηδέν και ενημέρωσε πρώτα το αντίστοιχο test. Εξήγησε γιατί ο compiler δεχόταν ήδη τον παλιό κώδικα ενώ άλλαξε το business requirement. Τι θα γίνει με input " 8080 "; πρέπει το πρόγραμμα να το καθαρίζει ή να το απορρίπτει;
Θέσεις bytes και όρια χαρακτήρων UTF-8
Μια συμβολοσειρά Rust είναι έγκυρη UTF-8, αλλά η θέση byte δεν είναι επιλογή χαρακτήρα. Ένα εύρος μέσα στο μήκος bytes μπορεί να τελειώνει στη μέση πολυbyte χαρακτήρα. Χρησιμοποίησε get για πιθανή αποτυχία τομής ή chars όταν το συμβόλαιο αφορά Unicode scalar values. Ένα εμφανιζόμενο γράφημα μπορεί ακόμη να περιέχει πολλές τέτοιες τιμές.
Όταν μια δυαδική μορφή ορίζει θέσεις bytes, διατήρησε bytes ώσπου να επικυρωθεί και αποκωδικοποιηθεί η περιοχή. Μη μετατρέπεις πλήθος χαρακτήρων σε πλήθος bytes. Το παράδειγμα διαχωρίζει έγκυρη αποκωδικοποίηση από έγκυρη τομή συμβολοσειράς.
fn main() {
let text = "γa";
assert_eq!(text.len(), 3);
assert!(text.get(0..1).is_none());
assert_eq!(text.get(0..2), Some("γ"));
assert!(std::str::from_utf8(&[0xce]).is_err());
assert_eq!(text.chars().count(), 2);
}
Μεταγλώττισε και εκτέλεσε με το εγκατεστημένο Rust πριν θεωρήσεις το δείγμα απόδειξη εκτέλεσης. Πρόσθεσε συνδυαστικά σημεία και κενό εύρος. Η απωλεστική αντικατάσταση ταιριάζει ίσως σε προβολή, όχι σε σιωπηρή αλλαγή αναγνωριστικού για εξουσιοδότηση ή ισότητα.