محتويات الدورة

C / المتوسط: الذاكرة والمكونات الموثوقة / الدرس 12

الاختبار والتشخيص والتنقيح

اجمع الفحوص التنفيذية مع تحليل العقود وابحث عن أول موضع يخرق فيه البرنامج ثابته.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • اختيار اختبارات الحدود والفشل من العقود.
  • استخدام التأكيدات دون إخفاء عمل مطلوب.
  • تفسير أدلة المنقح والكواشف ضمن حدودها.

اشتقاق الاختبارات من الوعود

يقارن الاختبار السلوك الملحوظ بتوقع محدد. اشتق الحالات من مجالات الإدخال والحدود والثوابت وسياسة الخطأ، لا من الأسطر الموجودة عرضا في التنفيذ. في البحث اختبر المتتالية الفارغة والموضعين الأول والأخير والهدف الغائب والتكرار وفق قاعدة أول تطابق المختارة.

اجعل الاختبارات حتمية وصغيرة بما يكفي ليشرح التوقع الفاشل خاصية. تأخذ المجموعة الناجحة عينات من التنفيذات؛ ولا تثبت غياب السلوك غير المعرّف أو كل عيب ممكن. اجمع الاختبارات بمراجعات تثبت المجالات الصالحة والتهيئة والملكية والتنظيف الكامل.

جعل اختبار صغير يتحقق من نفسه

يفحص المثال الأول عدة خصائص لدالة القيمة الكبرى ويعيد الفشل فورا عند خرق خاصية. مرجع الاختبار مستقل وبسيط: لأزواج معروفة قيم عظمى معروفة. تختبر المقارنة بصفر والمعاملات المتساوية حد القرار دون إطار اختبار.

قد يستخدم مشروع إنتاجي إطارا للتقارير والتجهيزات، لكن الفكرة المفيدة تبقى السلوك المتوقع الصريح. لا تكرر تعبير التنفيذ نفسه في كل نتيجة متوقعة، فقد تكرر النسختان سوء الفهم نفسه. وفي المساعدات الحسابية أضف القيم القصوى بعد أن يثبت العقد سلامة العمليات.

c مشغل اختبارات حتمي صغير
#include <stdio.h>

static int maximum(int a, int b)
{
    return a >= b ? a : b;
}

int main(void)
{
    if (maximum(2, 5) != 5) return 1;
    if (maximum(-3, 0) != 0) return 1;
    if (maximum(4, 4) != 4) return 1;
    puts("3 checks passed");
    return 0;
}
الناتج المتوقع
3 checks passed

كل نتيجة متوقعة قيمة معروفة؛ ولا يطبع النجاح إلا بعد اجتياز كل الفحوص.

التأكيدات توثق الحقائق الداخلية

تعبر assert عن شرط داخلي يتوقع البرنامج تحققه. عند تعريف NDEBUG لا يُقيّم تعبير التأكيد، لذلك لا يجوز أن يؤدي عملا مطلوبا. لا تضع تخصيصا أو إدخالا أو زيادة أو تحديثا أساسيا داخل التأكيد. استخدم معالجة أخطاء عادية للمدخلات الخارجية غير الصالحة وفشل الموارد.

يحسب المثال الثاني النتيجة أولا ثم يؤكد خاصية رياضية. وتظل مقارنة صريحة مستقلة تمنح العرض حالة فشل ذات معنى عند تعطيل التأكيدات. في البرمجيات الأكبر قد تكشف التأكيدات خرق الثوابت الداخلية مبكرا، بينما تنفذ الواجهة العامة أخطاءها القابلة للاسترداد الموثقة.

c تأكيد دون عمل مخفي
#include <assert.h>
#include <stdio.h>

int main(void)
{
    int a = 7;
    int b = 4;
    int result = a >= b ? a : b;
    assert(result >= a && result >= b);
    if (result != 7) return 1;
    puts("invariant holds");
    return 0;
}
الناتج المتوقع
invariant holds

لا يعتمد حساب result على تفعيل assert.

التوقف قرب الثابت المكسور

ابن بمعلومات التنقيح وأعد إنتاج الفشل بمدخل اصطناعي مسجل، واستخدم منقحا للتوقف قبل العملية المشكوك فيها. يظهر تتبع المكدس مسار الاستدعاءات؛ وقد يكشف فحص القيم المحلية والحدود سبب فشل افتراض. وتساعد نقطة المراقبة على العثور على الكتابة التي تغير كائنا دون توقع.

قد يكون موضع الانهيار بعيدا عن الكتابة غير الصالحة الأصلية. ابحث عن أول حالة خاطئة بدلا من إضافة فحص صفري حيث يقع الانهيار. قد يعيد البناء المحسن ترتيب كائنات المصدر أو يحذفها، فقارن بناء تنقيح مناسبا مع حفظ اختبار تراجع لإعداد الإصدار النهائي.

استخدام الأدوات كشهود إضافيين

تضيف AddressSanitizer فحوصا إلى البناء المدعوم لتشخيص كثير من أخطاء الحدود والعمر. وتفحص UndefinedBehaviorSanitizer عمليات مختارة غير معرّفة، مثل بعض الإزاحات غير الصالحة وتجاوز الإشارة. تستخدم الأوامر المتوافقة مع GCC غالبا -g -O1 -fsanitize=address,undefined مع خيارات الكواشف نفسها عند الربط. هذه خيارات أدوات وتتطلب بيئة تشغيل متوافقة.

يغطي التشغيل السليم المزود بالفحوص المسارات المنفذة والفحوص المدعومة فقط. تحتاج بعض العيوب أدوات أخرى، ويستخدم تحليل التزامن عادة بناء ThreadSanitizer مستقلا بدل جمعه مع AddressSanitizer. احتفظ بالمدخل المصغر المسبب لكل عيب، وأصلح العقد المخرق، ثم أعد اختبار التراجع والحدود القريبة المناسبة.

الأخطاء الشائعة وإصلاحها

يتخطى بناء الإصدار استدعاء أساسيا.

لماذا يحدث؟
يوجد الاستدعاء داخل assert فقط وتعطله NDEBUG.
كيف تصلحه؟
نفذ العمل خارج assert وافحص نتيجته صراحة.
كيف تتجنب تكراره؟
راجع كل تأكيد بحثا عن آثار جانبية.

يخفي الإصلاح الانهيار لكنه يفسد النتائج.

لماذا يحدث؟
عولج العرض دون استعادة الثابت.
كيف تصلحه؟
تتبع أول حالة غير صالحة وأصلح سببها.
كيف تتجنب تكراره؟
أضف اختبار تراجع يفحص النتيجة الصحيحة والبقاء حيا معا.

يُعد التشغيل النظيف بالكاشف برهانا.

لماذا يحدث؟
أُهملت المسارات غير المنفذة والفحوص غير المدعومة.
كيف تصلحه؟
اجمع الأدوات مع مراجعة العقود والحالات الموجهة.
كيف تتجنب تكراره؟
سجل تغطية كل أداة وحدودها.

اختبر فهمك

1. اختر اختبارات لإلحاق مفحوص بمخزن يبقى دون تغيير عند امتلائه، وحدد غرض كل اختبار.

اعرض الحل المشروح

اختبر مخزنا فارغا بسعة إضافية وموضعا قبل الامتلاء والامتلاء التام والمدخل غير الصالح وفق العقد. افحص حالة الإرجاع والطول والمحتوى بعد كل استدعاء. وعند الامتلاء احتفظ بنسخة من العناصر السابقة ذات المعنى وقارنها بعد الاستدعاء. يفحص ذلك وعد عدم التغيير عند الفشل لا علم النجاح وحده.

2. ينهار برنامج أثناء free. قدم خطة لا تفترض عيبا في free نفسها.

اعرض الحل المشروح

تحقق من أن المؤشر المالك الحالي المعاد من التخصيص، لا عنوان داخلي ولا كتلة محررة سابقا. افحص الكتابات السابقة بحثا عن تجاوز الحدود ونسخ الملكية بحثا عن التحرير المزدوج. أعد الإنتاج بمعلومات تنقيح وكاشف عناوين في بناء معزول. أصلح أول عملية غير صالحة واحتفظ بالمدخل الاصطناعي المسبب كتراجع.

أهم ما تعلمته

  • تحتاج الاختبارات توقعا مستقلا مشتقا من عقد.
  • لا تحمل التأكيدات آثارا جانبية مطلوبة.
  • توفر المنقحات والكواشف أدلة؛ وتفسر الثوابت الإصلاح.

المراجع الرسمية