על קוצו של ביט

בעקבות הפוסט הקודם שלי (מתחלקים לקבוצות) קיבלתי כמה הערות מחברי פייסבוק שלי שהם גם חברים בעולם האמיתי (היי איציק!) שהם לא הצליחו לקרוא אותו עד הסוף כי הוא היה טכני מידי ולא מובן, ובאופן כללי – התחיל טוב אבל התדרדר. “אתה לא יכול לכתוב משהו שקשור למחשבים וגם יהיה מעניין?” שאלו אותי. האמת שחשבתי שמחשבים זה מעניין באופן עקרוני, אבל אני נענה לאתגר והנה נסיון כזה –

בבוקר חמים ונעים של יוני, 1996, עמדה גולת הכותרת של סוכנות החלל האירופאית על כן השיגור בגינאה הצרפתית. הטיל אריאן 5 (Ariane5) היה פסגת היצירה דאז, סיכום של עשר שנות מחקר ופיתוח ויותר מ-7 מיליארד דולר שהושקעו בבניית הטיל המתקדם ביותר עד אז, שהיה מסוגל לשאת על גבו טונות של משקל לחלל.

הטיל שוגר, וכ-36 שניות אחרי שיגורו הוא החל לסטות ממסלולו. ארבע שניות אחרי זה, 40 שניות לאחר הצתת המנוע ובעודו בגובה של כארבעה קילומטר, סטיית המסלול הגיעה לנקודת האל-חזור, ומנגנון ההשמדה העצמית האוטומטי הופעל, הטיל התפוצץ והמטיר גשם של אלפי חלקיקים ושברים שעלו מיליארדים והכילו מאמצים אנושיים אדירים (יחד עם הטיל התפוצצו גם שלושה לווינים שהיו על גבו ולא היו מבוטחים).

מה קרה שם? מסתבר שאחד מהחיישנים – האקסלומטר (מד התאוצה) שמדד את המהירות האופקית של הטיל, נתקל בשגיאה וכיבה את עצמו. מיד נכנסה במקומו מערכת הגיבוי, אבל חצי שניה אחרי זה גם מערכת זו כיבתה את עצמה כי היא נתקלה באותה שגיאה. מחשב הטיסה (כן, היו מחשבים בתקופה הפרהיסטורית ההיא) קיבל בטעות נתון שדיווח על סטיה מהמסלול, ולכן הוא ביצע תיקון מסלול. אבל התיקון בעצם גרם לסטיה, שרק הלכה וגברה עד שעברה את גבול הבטיחות וגרמה לפיצוץ הטיל.

לפני שנבין מה קרה שם שגרם למערכות לקבל קריאות שגויות, נחזור רגע לקרקע המציאות ולדרך שבה מחשבים שומרים מספרים. מחשבים מתעסקים רק במספרים ושומרים רק מספרים. גם כשהם שומרים אותיות, מילים, תמונות וקולות הם מייצגים אותם במספרים. יותר מזה, כיוון שמחשבים עובדים על חשמל ומגנטיות, הדרך של מחשב לייצג ספרות היא באמצעות מתח חשמלי ומגנוט, ולכן ישנן רק שני מצבים שהמחשב מכיר – 0 או 1. זה לא סיפור גדול, סה”כ ניתן לספור באיזו מערכת ספרות שאנחנו רוצים (אנחנו רגילים לספור במערכת הדצימלית, שמכילה עשר ספרות) ואולי זה לא ממש אנושי לספור רק עם שתי ספרות (מערכת שנקראת בינארית) אבל זה גם לא לגמרי מוזר.

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

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

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

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

מעולם לא חבו רבים כל כך הרבה כל כך למעט(ים) כל כך (: