הבאג שהתחבא 4 שנים: איך מצאתי באג בכרומיום שמקריס את הטאב.
כשנתקלים בבאג, אפשר להתעצבן ואפשר לדבג. או: ככה שחזרתי באג שהתחבא בכרום יותר מ-4 שנים.
להתרגז או לדבג
הכל התחיל כשגלשתי באתר של חילן (מערכת ניהול משאבי אנוש), וניסיתי לעדכן את ימי המילואים שלי. על המסך קפצה הודעה על המסמכים הדרושים. אני, כמו מתכנת טוב, משתמש במקלדת - לוחץ Enter כדי לסגור את ההודעה.
ופתאום...
1💥 Aw, Snap!
2Something went wrong while displaying this webpage.
3די מרגיז, אבל ניסיתי שוב.
אבל אז זה קורה שוב. ושוב. כל פעם שאני לוחץ Enter על ההודעה - הטאב קורס.
כשמתכנת נתקל בבאג, הוא יכול להתעצבן או לדבג. החלטתי לדבג:
- לחיצה עם העכבר? ✅ עובד מצוין.
- לחיצה עם Enter? 💥 CRASH.
- לחיצה עם Space? 💥 CRASH.
משהו בקוד של הדף גורם לכרום לקרוס כשמשתמשים במקלדת. אבל מה?
ניסיתי לדבג את הקוד, וראיתי שההודעה נמצאת בתוך IFrame, והטאב קורס כשמסירים את ה-Iframe.
כדי לראות אם צדקתי, החלטתי לנסות לחזר.
נסיונות שחזור
החלטתי לנסות לשחזר עם Cursor:
1I think there is a bug in chrome when script inside IFrame remove the iframe from dom.
2Can you create a minimal reproduce?
3For example: Iframe with a button, when you clicked on the button, script in the iframe run and remove the IFrame.
4The Iframe can be in the same domain.
5ה-cursor יצר גרסה פשוטה. הרצתי אותה, אבל הבאג לא השתחזר.
ניסינו כל מיני וריאציות:
- ליצור את ה-iframe דינמית.
- לשים את הכפתור בתוך from.
- לשים חלקים שונים בקוד בתוך ה-iframe ומחוץ ל-iframe.
- ועוד...
שום דבר לא עבד.
הייתי בטוח שאפשר לשחזר את הבאג, אבל קשה מאוד להבין מה הקומבינציה שגרמה לבאג. הקוד הוא די גדול ויכולים להיות הרבה חלקים שגורמים לבאג.
פריצת הדרך
בסוף החלטתי לתת ל-cursor את כל הקוד של ה-iframe.
סוף סוף הוא יצר דוגמה שמשחזרת את הבאג, עברתי עליה והורדתי עוד כמה דברים מיותרים, עד שהגענו לדוגמה המינימלית שמשחזרת את הבאג:
הדף הראשי (index.html)
1<!DOCTYPE html>
2<html>
3<head>
4 <title>Chrome IFrame Bug</title>
5</head>
6<body>
7 <h1>Parent Page</h1>
8 <iframe id="iframe" src="iframe.html" width="400" height="300"></iframe>
9 <script>
10 const iframe = document.getElementById('iframe');
11
12 function hide() {
13 iframe.remove();
14 }
15 </script>
16</body>
17</html>
18תוכן ה-iframe (iframe.html)
1<!DOCTYPE html>
2<html>
3<head>
4 <title>IFrame Content</title>
5</head>
6<body>
7 <h2>IFrame Content</h2>
8 <button id="btn">OK</button>
9 <script>
10 const btn = document.getElementById('btn');
11
12 // זה המפתח! שימוש ב-onkeypress ולא ב-addEventListener
13 btn.onkeypress = function (e) {
14 if (e.keyCode == 13 || e.charCode == 32) {
15 window.parent.hide(); // קריאה לפונקציה בחלון האב
16 return e.preventDefault(); // הפונקציה הזו מנסה לרוץ כשה-iframe כבר לא קיים ומקריסה את הטאב
17 }
18 };
19 </script>
20</body>
21</html>
22זהו. 11 שורות קוד javascript והטאב קורס. 💥
מה בדיוק קורה?
הבאג קורה בגלל שרשרת אירועים מאוד ספציפית:
- משתמש לוחץ Enter על הכפתור בתוך ה-iframe.
btn.onkeypresshandler (בתוך ה-iframe) מופעל.- ה-handler קורא ל-
window.parent.hide()- פונקציה בדף האב. - הפונקציה בדף האב קוראת ל-
iframe.remove()- מוחקת את ה-iframe. - ה-iframe נמחק בזמן שה-event handler עדיין פועל.
- הפונקציה
event.preventDefault()מנסה לעצור את התנהגות ברירת המחדל של הכפתור. - ה-iframe כבר לא קיים 💥 CRASH!
בעצם, כרום מנסה לחזור ל-execution context שכבר לא קיים, וזה גורם לקריסה מלאה של הטאב.
איך באג כזה נשאר 4 שנים בכרום?
הבאג הזה קיים בכרומיום מאז גרסה 91 (שיצאה במאי 2021), אבל כמעט אף אחד לא נתקל בו. למה?
כי צריך כל התנאים האלה ביחד:
1. רק ב-macOS
הבאג מתרחש רק במק. בלינוקס ו-Windows הכל עובד תקין.
2. 🔗 iframe באותו domain
צריך iframe שיכול לגשת ישירות לחלון האב:
same-origin- iframe באותו domain כמו הדף- בקוד מודרני כמעט ולא משתמשים ב-iframe. ואם משתמשים בו, מתקשרים איתו באמצעות משתמשים ב-
postMessageולא בגישה ישירה
1// זה גורם לבאג ⚠️
2window.parent.hide();
3
4// זה לא ✅
5window.parent.postMessage({ action: 'hide' }, '*');
63. קוד legacy
צריך להשתמש בדרך הישנה והלא מומלצת:
1// הדרך הישנה שגורמת לבאג ⚠️
2btn.onkeypress = function(e) { ... }
3
4// הדרך המודרנית שלא גורמת לבאג ✅
5btn.addEventListener('keypress', function(e) { ... })
6נדיר מאוד למצוא קוד מודרני שעובד בצורה כזו, ולכן הבאג הזה חי בשקט כבר 4 שנים.
הדיווח ל-Chromium
כדי לוודא שהבאג לא קורה רק אצלי, השתמשתי ב-Browsers Stack כדי לבדוק גרסאות כרום בסביבות שונות.
מסתבר שהבאג התחיל בגרסה 91 ומשתחזר רק במחשבי Mac, אבל גם בגרסת Chrome Canary הוא עדיין קיים.
יצרתי דוגמה חיה שמשחזרת את הבאג ב-100% מהמקרים.
דיווחתי ל-Chromium ומישהו שם כבר שחזר את הבאג. מן הסתם יקחו כמה חודשים עד שייכנס תיקון ועד שהתיקון יגיע למשתמשים.
ומה למדתי?
- AI יכול לעזור - Cursor עזר לי לתמצת את הבעיה מתוך מאות שורות קוד.
- כשנתקלים בבאג, אפשר להתעצבן ואפשר לתקן.
- אם באמת רוצים להשפיע, כדאי ליצור minimal reproduction שיעשה כמה שיותר מהעבודה, ככה יש יותר סיכוי שיטפלו בבאג.
נסו בעצמכם
הקוד המלא זמין ב-GitHub.
אם אתם עובדים על Mac עם Chrome, אתם מוזמנים לנסות את הדוגמה החיה.