C / دليل حلول تحريري
تشخيص خطأ التجزئة وعمر المؤشر
تتبع أول وصول غير صالح واستعد ضمانات العمر والحدود والملكية قبل اعتبار الانهيار مُصلحا.
قاعدة معرفة للقراءة فقط · بلا تعليقات عامة
تعرّف على الأعراض
يبلغ برنامج مختبر محلي "Segmentation fault"، أو يفشل داخل دالة مكتبة، أو يتغير سلوكه مع التحسين. لا تحدد الأعراض سببا وحيدا. وقد تبدو شيفرة C غير الصالحة عاملة؛ لذلك لا يثبت غياب الانهيار صلاحية المؤشر ولا مخرجا متوقعا.
افهم الأسباب المحتملة
- تشمل الأسباب فك مؤشر صفري وفهارس خارج الحدود واستخدام تخصيص بعد free أو realloc وإعادة عنوان محلي تلقائي والكتابة فوق بيانات إدارية سابقا. تهم المحاذاة وأنواع الوصول غير المتوافقة أيضا. يعالج فحص عدم الصفر شرطا واحدا ولا يتحقق من عناوين قديمة أو فاسدة عشوائية.
1. حفظ إعادة إنتاج محدودة
انسخ أصغر مصدر ذي صلة إلى مجلد تطوير معزول واستخدم بيانات اصطناعية تسلك المسار نفسه. سجل إصدار المترجم ووضع اللغة والخيارات والمدخلات. لا تعِد الإنتاج على ملفات أو خدمات إنتاجية. لا تفترض أن سطر الانهيار أول عملية خاطئة؛ فقد يظهر فساد الذاكرة السابق متأخرا جدا.
2. إثبات التزامات الوصول
حدد للمؤشر المتسبب الكائن المالك وتخصيصه أو تصريحه وعمره الحالي وعدد العناصر المتاحة ومحاذاته ونوع الوصول المسموح. تتبع كل إسناد وتحرير يؤثر فيه. إذا أعادت دالة مؤشر متغيرها المحلي العادي ففك إشارته لاحقا غير صالح مهما كان العنوان المرئي بالمنقح. لا تنسب مخرجا متوقعا لهذا المسار غير الصالح.
3. جمع أدلة تشخيص موجهة
في سلسلة مختبر مدعومة متوافقة مع GCC ابن بمعلومات التنقيح وفحوص العناوين والسلوك غير المعرّف. الأمر توضيحي ويتطلب lab.c اصطناعيا موجودا. شغل البرنامج المزود بالفحوص في سياق الاختبار المعزول فقط. افحص التتبع والقيم المثبتة لخرق الحد أو العمر في المنقح؛ واستخدم أول تقرير مفيد لتوجيه التحقيق.
cc -std=c17 -g -O1 -Wall -Wextra -Wpedantic -fsanitize=address,undefined lab.c -o lab_checked
يلزم دعم المترجم وبيئة الكواشف المتوافقة؛ وهذه ليست صياغة ISO C.
4. إعادة قيمة أو استخدام تخزين يملكه المستدعي
يكتب المثال المصحح في int حي يملكه المستدعي ويبلغ النجاح منفصلا. يفيد فحص الصفري، مع استمرار ضمان المستدعي لهدف صالح قابل للكتابة. لا يهرب مؤشر لتخزين المساعد المحلي. وإذا استُخدم تخصيص ديناميكي فحدد من يحرره ومتى تبطل كل الاستعارات؛ ولا يصلح تصفير مالك واحد الأسماء البديلة.
#include <stdbool.h>
#include <stdio.h>
static bool answer(int *out)
{
if (out == NULL) return false;
*out = 42;
return true;
}
int main(void)
{
int value = 0;
if (!answer(&value)) return 1;
printf("value=%d\n", value);
return 0;
}
value=42
يبقى value حيا طوال الاستدعاء وprintf التالية.
5. إصلاح انتقال الملكية الأصلي
لعيب تغيير الحجم احتفظ بنتيجة realloc مؤقتا واعتمدها بعد النجاح فقط وأعد إنشاء كل مؤشر عنصر مستعار بعدها. ولعيب الحدود افحص الفهرس مقابل الطول المنطقي قبل الوصول. وللتحرير المزدوج عين مالكا واحدا بدلا من إضافة free تخمينية. يجب أن يفسر الإصلاح خرق الثابت الأصلي لا أن ينقل الانهيار.
تحقق من نجاح الإصلاح
يجب أن يطبع المثال المصحح value=42 وينهي بنجاح. أعد تشغيل اختبار التراجع المصغر وحالات الفراغ والحدود والفشل المناسبة في بناء الفحوص الملائم. اشترط صحة النتائج وغياب التقارير معا. يغطي صمت الكاشف فحوصه المدعومة المنفذة فقط؛ واحتفظ بحجة العمر والحدود حتى دون تشخيص.
امنع تكرار المشكلة
- وثق المالكين ومدة الاستعارة والأعداد المتاحة وإبطال المؤشرات. هيئ الحالة قبل العمل القابل للفشل واختبر التنظيف بعد كل فشل. احتفظ بفحوص التنقيح والإصدار مستقلة؛ فتغيير التحسين جمع أدلة مفيد لكنه لا يصحح السلوك غير المعرّف.