לדלג לתוכן

פתרון חיפוש והקטנת ממצא

פתרון ראשון

הקלט [0, 1] מצהיר על בית גוף אחד שאינו קיים, ולכן החיתוך במימוש הפגום חורג מהטווח. הקלט [0, 0, 7] מצהיר על גוף ריק אך כולל בית נוסף. המימוש מחזיר גוף ריק למרות שהממשק אמור לצרוך מסגרת שלמה אחת ולדחות עודפים.

פתרון שני

נחליף את הספרייה בקוד הבא. הוא בודק את הגודל לפני החיתוך ומגדיר במפורש את מדיניות הבתים העודפים.

pub fn payload(data: &[u8]) -> Result<&[u8], &'static str> {
    let header = data.get(..2).ok_or("short header")?;
    let length = u16::from_be_bytes([header[0], header[1]]) as usize;
    if length > 4096 { return Err("too large"); }
    let end = 2_usize.checked_add(length).ok_or("length overflow")?;
    if data.len() != end { return Err("frame length mismatch"); }
    data.get(2..end).ok_or("short body")
}

#[test]
fn complete_frame_contract() {
    assert_eq!(payload(&[0, 0]), Ok(&[][..]));
    assert!(payload(&[0, 1]).is_err());
    assert_eq!(payload(&[0, 1, 7]), Ok(&[7][..]));
    assert!(payload(&[0, 0, 7]).is_err());
}

הגבול הקטן של שדה האורך כבר מונע גלישת חיבור ביעדים הרגילים, אך השימוש בחיבור נבדק שומר את הכוונה מפורשת אם הפורמט יורחב. יעד החיפוש המקורי ממשיך להתאים לחוזה החדש.

פתרון שלישי

נשאיר את ההקצאה בחיים עד אחרי הקריאה או נעביר אל הפונקציה הפניה שהקומפיילר בודק. התיקון הפשוט הוא למחוק את המצביע הגולמי ואת ההשמדה המוקדמת ולהשתמש ב־&u8 כל עוד הבעלים חי. שינוי הערך המודפס או הוספת המתנה אינם תיקון.

יעד הדרגתי יקבל רצף של גדלי חלקים ושל בתים, יזין את המפענח בכמה פעולות ויקרא לסיום מפורש. נשווה את התוצאה לפענוח המסגרת השלמה ונבדוק שפיצול אינו משנה משמעות. כך אנו בודקים מצב בין קריאות, בעוד היעד הטהור בודק רק את חוזה המסגרת השלמה.