למזלי, לא אני הגיבור של הסיפור המטורף הזה – אחרת קשה לי להאמין שהייתי מצליח לשמור על מספיק שפיות בשביל לכתוב. הנה הפרטים על באג כל כך מוזר וחמקמק, שכל דבר שתעשו יכול לתקן אותו – או להחזיר אותו שוב – בלי שתבינו אף פעם למה!
העניין הוזכר, כבדרך אגב, באחד מהפרקים האחרונים של הפודקאסט The Amp Hour. האורח דיבר על פרויקט שלו, שהתבסס על מיקרו-בקר CC430F6137 של TI, ושבמסגרתו (אם הבנתי נכון) היה צריך לפעמים לכתוב ערך לשעון זמן-אמתי (RTC) פנימי. בגלל תקלה כלשהי בתכנון החומרה של מהדורה מסוימת של המיקרו-בקר, הכתיבה נכשלה אם פקודת אסמבלי קריטית אחת נמצאה בכתובת זיכרון שמתחלקת ב-16 ללא שארית!
זה כשלעצמו פסיכי לגמרי. איזה מין מנגנון יכול לגרום לתקלה שכזו? זה משהו שחייב לקרות עמוק בחומרה: התנגשות תזמונים של ערוצי נתונים פנימיים, חוצצים סמויים שאפילו ה-Datasheet לא מכיר, או משהו אזוטרי ותמוה אחר. מה שלא יהיה, זה רחוק מאוד מהמקומות שבהם אנחנו מחפשים ומוצאים באגים בדרך כלל.
לצורך העניין, זה גם לא משנה אם אנחנו כותבים את הקוד שלנו באסמבלי או בשפה עילית: כל עוד אנחנו לא מודעים לסיבת הבאג, יש סיכוי של 1 ל-16 שהפקודה ההיא תגיע לכתובת בעייתית. יום אחד הקוד יעבוד מצוין, יום אחרי זה נוסיף לו פיצ'ר לגמרי לא קשור (למשל, שיכתוב "Hey" במקום "Hi" במסך הפתיחה) והופ, השעון לא יתעדכן. שום כלי דיבוג לא יעזור, אפילו אם הוא יירד לרמת ה-Cycle והביטים הבודדים: אנחנו פשוט נראה שבקוד מסוים הפקודה עובדת, ובאחר לא. מי יחשוב להסתכל בכלל על הכתובת? שינוי נוסף הכי קטן בקוד, והבאג ייעלם שוב: אנחנו נחשוב שפתרנו אותו, או אולי שהוא היה פרי הדמיון בלבד, ואז הוא יחזור ויעקוץ אותנו מי יודע מתי ובאילו נסיבות.
האורח בפודקאסט לא הסביר איך הוא גילה את הבאג בסופו של דבר; בין השורות קיבלתי את הרושם שהנושא דווקא צוין ב-Errata של המיקרו-בקר והוא פשוט לא קרא את המסמך בתחילת הדרך. קשה לי גם לדמיין איזו השקעה עצומה, או מזל בלתי-רגיל, צריך כדי לגלות באג כזה לבד.
הפתרון שמוצע ב-Errata, אגב, הוא להשתמש בפונקציה מוכנה-מראש כלשהי, שכוללת כנראה הוראה מפורשת לקומפיילר "ליישר" את פקודות האסמבלי שלה למקום לא-בעייתי בזיכרון. כן, אפשר לעשות גם דברים כאלה; השיטה המדויקת תלויה כמובן במיקרו-בקר ובקומפיילר הספציפיים.
ממש סיפור אימה. ככה לקרוא על דבר כזה לפני השינה…בררר
🙂