تقرير في مستودع Rust: كود آمن بالكامل يقرأ ذاكرة محرَّرة بسبب ثغرة في الـ borrow checker موجودة منذ الإصدار 1.4
المغزى: ضمان الأمان في Rust وعد عن مترجم كتبه بشر، لا نظرية معصومة، والفرق بين الآمن والذي لم يصطدم به أحد بعد ظل قائمًا قرابة 11 عامًا.
فتح المستخدم jsnell في 13 أكتوبر 2026 تقريرًا في المستودع الرسمي للغة Rust بعنوان “struct’s lifetime requirements can be bypassed via covariant field assignment”. ويعرض التقرير كودًا لا يحتوي على كلمة unsafe إطلاقًا، ومع ذلك يطبع ذاكرة محرَّرة ويتسبب في segfault. وتكشف أداة AddressSanitizer الخطأ بوصفه stack-use-after-scope.
ووعد Rust الأساسي أن الكود الآمن لا يمكن أن يصل إلى undefined behaviour. والآلية هنا بسيطة: يُعرَّف struct عليه قيد T: ’static، أي أن ما بداخله يعيش طوال عمر البرنامج، ويُكتب له تطبيق Drop يعتمد على هذا القيد عند التنظيف. والمفترض أن يمنع الـ borrow checker وضع قيمة أقصر عمرًا في الحقل، لكنه لا يمنعها حين يتم ذلك بالإسناد إلى الحقل. فيُسند إليه مرجع لمتغير محلي، ويقبل المترجم، وحين يحين وقت Drop يجد مرجعًا لشيء انتهى عمره.
ويرجّح maxdexh، أحد أعضاء المشروع، أن عملية الـ unification لا تتحقق من قيود الـ lifetime للنوع عمومًا، أي أن المشكلة فراغ في الفحص نفسه لا حالة شاذة. وقدّم lcnr، المساهم في الفريق، نسخة لا تحتاج إلى ’static أصلًا.
وبحسب التعليقات، كتب lcnr أن الخلل قائم منذ الإصدار 1.4، وكتب maxdexh أن نسخته تنهار أو تطبع ذاكرة محرَّرة منذ 1.4. وصدر Rust 1.4 عام 2015، فعمر الخلل نحو 11 عامًا بحساب التاريخين، لا برقم مكتوب في التقرير. ويؤثر على nightly وعلى النسخة المستقرة حتى 1.85.0 على الأقل. والتقرير مصنف P-high وI-unsound، ولا يوجد حتى الآن مكلَّف بإصلاحه ولا pull request.
ولا يعني ذلك أن كودًا قائمًا سينهار فجأة. فبقاء الخلل 11 عامًا دليل على أن الوقوع فيه بالخطأ نادر. لكن الواقعة تغيّر معنى كلمة “آمن” عند كثيرين، من “مثبت” إلى “وعد عن برنامج كتبه بشر”. ومن وجد الخلل أفراد من مجتمع اللغة نفسه، فتحوا تقريرًا علنيًا مع الكود، ويبقى الخلاف قائمًا حول ما إذا كان عمر الثغرة الطويل علامة ضعف في الضمان أم علامة على قوته.