بنية اختبار مسارات الفشل في Windows بـ Application Verifier

· آخر تحديث: · · تطوير Windows, التحقيق في الأعطال, الكاميرا الصناعيّة, Application Verifier, اختبار المسارات الشاذّة, handle leak

سجل التعديلات (3 تحديثات، آخر تحديث 3 Sep، 2026)

سجل بالتغييرات التي أُجريت على هذا المقال. وحيثما حُفظت نسخة سابقة، تبقى متاحة للقراءة عبر رابط دائم يحمل معرّف DOI.

أُضيفت روابط الاستشارة الموجودة في الأصل الياباني (consultation_services). ولم يتغيّر نصّ المقالة نفسه. قراءة النسخة السابقة لهذا التحديث (DOI: 10.5281/zenodo.22240811)
أُعيدَت الترجمة العربية كترجمة كاملة عن النص الياباني الأصلي، وأُضيفَت خريطة المعرفة.
أعيدت الترجمة كترجمة كاملة عن النص الياباني الأصلي. كانت النسخة العربية السابقة مختصراً يسقط أبواباً وجداول ورسوم Mermaid وتعليقات الأشكال وFAQ. أُعيدت هذه العناصر وفق الأصل الياباني، والادّعاءات التقنية مطابقة للنسخة اليابانية.
النشر الأول
الاستشهاد بهذا المقال(DOI: 10.5281/zenodo.21621333)

هذا المقال محفوظ على Zenodo. يرد أدناه معرّف DOI الذي يشير دائمًا إلى أحدث نسخة، ومعرّف DOI المثبَّت على النسخة التي تقرؤها.

小村 豪 (2026). بنية اختبار مسارات الفشل في Windows بـ Application Verifier. شركة كومورا سوفت ذ.م.م.. https://doi.org/10.5281/zenodo.21621333 https://comcomponent.com/ar/blog/2026/03/11/003-application-verifier-abnormal-test-foundation-part2/

DOI (أحدث نسخة)
10.5281/zenodo.21621333
DOI (هذه النسخة)
10.5281/zenodo.22279723

Application Verifier أداة قويّة عندما يُراد إظهار الشذوذ الذي يحدث حول الشيفرة الأصليّة في Windows أو حدود Win32 في وقت أبكر. تنفع خصوصاً في مواضع اختبار شذوذ المقابض وتلف الكومة ومسار الفشل عند انخفاض الموارد، فتُخرج مشكلات لا يراها اختبار المسار العاديّ وحده بسرعة كبيرة.

في الجزء الأوّل تحقيق تعطّل الكاميرا الصناعيّة بعد تشغيل طويل: فصل handle leak رتّبنا حالة تبيّن فيها بعد التحقيق في تطبيق تحكّم يسقط بعد تشغيل طويل أنّ السبب handle leak. لكن تعزيز السجلّات وحده ما زال نصفاً. ما يُراد حقّاً هو التمكّن مسبقاً من تجربة هل، إذا حدث لاحقاً خطأ برمجيّ غير متوقّع يسبّب تسريب ذاكرة أو handle leak أو فشلاً في الوسط أو نسيان تحرير، تبقى الحالة «يمكن معرفة ما حدث».

هنا استُخدم Application Verifier. أداة يمكن إدخال فحوصات وقت التشغيل وfault injection على معالجة تعمل حول الشيفرة الأصليّة في Windows أو حدود Win32. ما ينفع خصوصاً في العمل أنّه يمكن إحداث شكل انكسار يشبه نقص الذاكرة أو نقص الموارد في وقت أبكر، دون استنزاف ذاكرة الجهاز فعلاً.

في الجزء الثاني نرتّب ما هو Application Verifier، وما يمكنه فعله، وكيف يُدمَج في بنية اختبار مسارات الفشل، في سياق تطبيق تحكّم بكاميرا صناعيّة.

المحتويات

  1. الخلاصة أوّلاً (في جملة)
  2. ما هو Application Verifier
    • 2.1. ماذا يعني في جملة
    • 2.2. في أيّ مواضع ينفع
    • 2.3. ما الذي يسرّ في العمل
    • 2.4. من الحصول إلى التفعيل محليّاً
  3. ماذا يمكن لـ Application Verifier أن يفعل
    • 3.1. Basics: Handles / Heaps / Locks / Memory / TLS وغيرها
    • 3.2. Low Resource Simulation: تقديم نقص الذاكرة ونقص الموارد
    • 3.3. Page Heap والمصحّح
    • 3.4. !avrf / !htrace / السجلّات
  4. لماذا أُدخل في هذه الحالة
    • 4.1. الغرض ليس «إيجاد خطأ» فقط
    • 4.2. إحداث ظاهرة تشبه نقص الذاكرة
    • 4.3. التحقّق من إمكان التتبّع عند شذوذ المقابض
  5. كيف تُحدَث ظاهرة تشبه نقص الذاكرة أو نقص الموارد
    • 5.1. فكرة Low Resource Simulation
    • 5.2. ما يمكن إفشاله
    • 5.3. طريقة التطبيق في العمل
  6. كيف يُنظَر إلى شذوذ المقابض
    • 6.1. فحص Handles
    • 6.2. النظر إلى مكدّس open / close بـ !htrace
    • 6.3. كيف يُجمع مع السجلّ الذاتيّ
  7. طريقة بناء بنية اختبار المسارات الشاذّة
    • 7.1. إمالة وحدة التنفيذ إلى harness
    • 7.2. تقسيم قائمة الاختبار
    • 7.3. ما يُجمَع
    • 7.4. شروط القبول
    • 7.5. تنبيهات
  8. دليل اختيار تقريبيّ
  9. الخلاصة
  10. روابط مرجعيّة

في المخطّط، يشير الخطّ المتّصل إلى علاقة قائمة دائماً، ويشير الخطّ المتقطّع إلى علاقة مشروطة (شروط قيامها مذكورة في شرح كلّ علاقة في الصفحة التفصيليّة). القائمة الكاملة للعلاقات (المجموع 17، مع الأدلّة ودرجة اليقين) وتعريفات المفاهيم الرئيسة مجمّعة في صفحة تفاصيل خريطة المعرفة (باليابانية). البيانات: JSON-LD / Turtle

1. الخلاصة أوّلاً (في جملة)

  • Application Verifier أداة تسهّل إيجاد إساءة الاستخدام وقت التشغيل عند حدود unmanaged / native في Windows
  • ما ينفع ليس «إيجاد خطأ» فقط، بل إحداث المسارات الشاذّة التي يصعب ظهورها عادة في وقت أبكر
  • Handles لكشف invalid handle، وHeaps لإبراز تلف الكومة، وLow Resource Simulation لـ fault injection لوضع يشبه نقص الذاكرة أو نقص الموارد
  • إلقاء تحقيق تسريب EXE مقيم طويل الأمد على Application Verifier وحده مسار سيّئ، والجمع مع سجلّ ذاتيّ لـ Handle Count ودورة حياة المورد واقعيّ
  • في بنية اختبار المسارات الشاذّة، فصل verifier run للمسار العاديّ عن fault injection run أوضح للقراءة
  • حتّى عند تجربة DLL، هدف تفعيل Application Verifier هو EXE الاختبار الذي يشغّل ذلك DLL فعليّاً

باختصار، Application Verifier أداة تسحب إلى السطح «الأخطاء الكريهة» حول native / Win32 في Windows. تنسجم كثيراً خصوصاً في عالم تطبيقات التحكّم بالأجهزة حيث يختلط native SDK وP/Invoke وWin32 API بسهولة.

عملان لـ Application Verifierيبيّن أنّ Application Verifier له عملان: كشف إساءة الاستخدام عند الحدود الأصليّة، وتقديم المسارات الشاذّة التي يصعب ظهورها عادة، ويمكن كشف invalid handle وتلف الكومة وحقن وضع يشبه نقص الذاكرة.Application Verifierكشف إساءة الاستخدام عند الحدود الأصليّةتقديم المسارات الشاذّة الصعبة الظهورinvalid handle وتلف الكومةحقن وضع يشبه نقص الذاكرة

الشكل 1: عمل Application Verifier عمودان: «كشف إساءة الاستخدام» و«تقديم المسارات الشاذّة».

2. ما هو Application Verifier

2.1. ماذا يعني في جملة

Application Verifier أداة تحقّق وقت التشغيل لتطبيقات user-mode في Windows. تراقب استخدام التطبيق الجاري لـ OS API وطريقة تعامله مع الموارد، فتكشف استخداماً مشبوهاً أو تحقن فشلاً عمداً.

بخلاف «التحليل الساكن» أو «اختبار الوحدة»، هي أداة تنظر كيف ينكسر الأمر عند المرور فعليّاً بمسار الشيفرة ذلك. لذا تناسب إبراز مسار الفشل الذي لا يظهر في اختبار الوظائف العاديّ.

harness الاختبارتطبيق التحكّم / غلاف SDKApplication VerifierWin32 API / native DLL / موارد نظام التشغيلverifier stopخرج المصحّحAppVerifier logsسجلّ منظَّم ذاتيّ

الشكل 2: Application Verifier يراقب تطبيق التحكّم الذي يُشغَّل من harness الاختبار، ويُبقي نتائج الرصد كـ verifier stop وخرج المصحّح وسجلّات.

2.2. في أيّ مواضع ينفع

ما ينفع خصوصاً مواضع كهذه.

  • استدعاء native DLL أو SDK كاميرا
  • العبور عبر P/Invoke أو COM
  • استخدام كثير مباشر أو غير مباشر لـ handle وheap وlock والذاكرة الافتراضيّة
  • لا يسقط عادة في المسار السليم، لكن إدارة العمر توشك على الانهيار في المسار الشاذّ فقط
  • «فشل غريب أحياناً» يظهر قبل «السقوط»

بالمقابل، ليست أداة لتتبّع object graph في عالم managed خالص. لذلك تنفع كثيراً حتّى في تطبيق C# إذا كانت حدود native SDK أو Win32 سميكة، لكنّها ليست قصّة رؤية تسريب الكومة managed الخالص بهذه الأداة وحدها كلّه.

تمييز المواضع التي ينفع فيها Application Verifierيبيّن التضييق: ينفع في تطبيق سميك الحدود بـ native DLL أو P/Invoke أو Win32، لكنّه ليس أداة لتتبّع object graph في عالم managed خالص.حدود native SDK أو Win32object graph managed خالصأيّ طبقة المشكلة؟Application Verifier ينفعخارج النطاق (يُنظَر بأداة أخرى)

الشكل 3: الحدّ الفاصل للنفع سماكة حدود native / Win32، وليست أداة ترى عالم managed خالصاً فقط.

2.3. ما الذي يسرّ في العمل

ما يسرّ في العمل تقريباً ثلاثة.

  1. إيقاف إساءة الاستخدام عند الحدود الأصليّة مبكّراً
    • invalid handle
    • heap corruption
    • lock misuse
    • virtual memory API misuse وغيرها
  2. تقديم شكل انكسار لا يظهر إلا عند انخفاض الموارد
    • ما يعادل malloc يفشل أحياناً
    • CreateEvent أو CreateFile يفشل أحياناً
    • VirtualAlloc يفشل
  3. سهولة التتبّع بالجمع مع المصحّح
    • !avrf
    • !htrace
    • !heap -p -a
    • سجلّ verifier stop

ما يزعج في تطبيقات التحكّم بالأجهزة «عدم معرفة ما حدث في المسار الشاذّ». Application Verifier ينفع كثيراً في تقليل «عدم المعرفة» ذلك.

ثلاث نقاط تسرّ في العمليبيّن ثلاث فوائد: إيقاف إساءة الاستخدام عند الحدود الأصليّة مبكّراً، وتقديم شكل انكسار لا يظهر إلا عند انخفاض الموارد، وسهولة التتبّع بالجمع مع المصحّح.Application Verifierإيقاف إساءة الاستخدام مبكّراًتقديم شكل الانكسارسهولة التتبّع بالمصحّحامتدادات مثل avrf وhtrace

الشكل 4: السرور في العمل يتجمّع في ثلاث: الكشف المبكّر، وتقديم المسارات الشاذّة، والربط بالمصحّح.

2.4. من الحصول إلى التفعيل محليّاً

نفرغ أوّلاً تجهيز الأداة. إذا سقط هذا، يصير الحديث بعده كلّه نظريّاً.

Application Verifier مرفق مع Windows SDK. لا يدخل مع Windows وحده، لذا يُشغَّل مثبّت SDK ويُؤشَّر «Application Verifier» في شاشة اختيار الميزات. اسم الملفّ التنفيذيّ appverif.exe.

للاستخدام ثلاثة افتراضات.

  • أن يكون المستخدم المنفِّذ عضواً في مجموعة Administrators على ذلك الجهاز
  • أن ARM64EC خارج نطاق الدعم
  • أن هدف التحقّق شيفرة unmanaged (أصليّة)

علاقة الواجهة الرسوميّة وسطر الأوامر تُفهم هكذا فلا تحدث حيرة.

  ماذا يفعل
الواجهة الرسوميّة (appverif.exe) كتابة اسم EXE المستهدف وتركيب الاختبارات المفعَّلة في السجلّ
سطر الأوامر (appverif -enable ...) كتابة إعداد السجلّ نفسه تماماً بأمر
وقت التشغيل عند تشغيل EXE المستهدف يُنظَر إلى ذلك الإعداد فتُحمَّل DLL الخاصّة بـ verifier وتدخل خطّافات Win32 API

أي أنّ ما يُفعَل واحد أيّاً استُخدم. الاستخدام: الواجهة الرسوميّة لليدويّ أوّل مرّة، وسطر الأوامر لـ CI أو النصوص.

علاقة الواجهة الرسوميّة وسطر الأوامريبيّن أنّ الواجهة الرسوميّة وسطر الأوامر يكتبان إعداد السجلّ نفسه فقط، وأنّ EXE المستهدف عند التشغيل ينظر إلى ذلك الإعداد فتُحمَّل DLL الخاصّة بـ verifier وتدخل خطّافات Win32 API.الواجهة الرسوميّة (appverif.exe)كتابة الإعداد في السجلّسطر الأوامرالمرجع عند تشغيل EXE المستهدفتحميل DLL الخاصّة بـ verifier والخطّافات

الشكل 5: الواجهة الرسوميّة وسطر الأوامر يكتبان إعداد السجلّ نفسه فقط، والخطّافات تدخل عند تشغيل EXE المستهدف.

عمليّة الواجهة الرسوميّة: نقر أيمن في عمود Applications يساراً ثمّ «Add Application» لإضافة EXE المستهدف، وتأشير Basics وغيرها في عمود Tests يميناً ثمّ «Save». الإلغاء: نقر أيمن في عمود Applications نفسه ثمّ «Delete Application» ثمّ «Save».

من هنا يأتي قيدان مهمّان.

  • لا يمكن التفعيل لاحقاً على عمليّة جارية. الخطّافات تدخل عند تحميل DLL، لذا الترتيب تعيين ثمّ تشغيل.
  • الإعداد يبقى حتّى يُحذف صراحة. إذا تُرك بنيّة «جرّبناه مرّة واحدة»، يستمرّ ذلك EXE على ذلك الجهاز في التشغيل دائماً تحت verifier.

لاحظ أنّ سجلّات الكشف تُحفَظ افتراضيّاً بشكل ثنائيّ في %USERPROFILE%\AppVerifierLogs، ويمكن تحويلها إلى XML بالواجهة الرسوميّة أو سطر الأوامر للتجميع.

ترتيب التفعيل وبقاء الإعداديبيّن أنّ الخطّافات تدخل عند تحميل DLL فلا يمكن الإضافة لاحقاً إلى عمليّة جارية، وأنّ الترتيب تعيين ثمّ تشغيل، وأنّ الإعداد يبقى حتّى يُحذف صراحة.كتابة الإعدادتشغيل EXE المستهدفالعمل تحت verifierالإعداد يبقى حتّى الحذفالترك يجعل التشغيل دائماً تحت verifierعمليّة جاريةالتفعيل اللاحق غير ممكن

الشكل 6: ترتيب «تعيين ثمّ تشغيل» لا يُكسَر، والإعداد يبقى على ذلك الجهاز حتّى يُحذف صراحة.

3. ماذا يمكن لـ Application Verifier أن يفعل

3.1. Basics: Handles / Heaps / Locks / Memory / TLS وغيرها

المجموعة الأساسيّة في Application Verifier هي Basics. هنا تتجمّع الفحوصات الشائعة في العمل.

الطبقة ماذا ينظر إليه موضع الاستخدام في سياق هذه الحالة
Handles استخدام invalid handle هل وُطئ مقبض أُغلق / تالف
Heaps heap corruption إبراز تلف مخزن أو use-after-free عند حدود native SDK
Leak موارد لم تُحرَّر عند تفريغ DLL تأكيد اختبار harness قصير العمر أو حالات تشمل التفريغ
Locks / SRWLock إساءة استخدام lock تأكيد تسابق reconnect وshutdown
Memory إساءة استخدام VirtualAlloc / MapViewOfFile وغيرها تأكيد شذوذ حول مخزن كبير أو ذاكرة مشتركة
TLS إساءة استخدام Thread Local Storage API تأمين لشيفرة أصليّة معقّدة الحدود بين الخيوط
Threadpool اتّساق threadpool API أو حالة العامل مساعد عند كثرة callback أو المعالجة اللاتزامنيّة

النقطة ليست «يمكن الفهم بالقراءة بعد السقوط» بل «إيقاف الاستخدام المشبوه في مكانه». في أعطال نمط التشغيل الطويل ينفع هذا التقديم كثيراً.

فكرة الكشف المبكّر في Basicsيبيّن إبراز أعطال نمط التشغيل الطويل في وقت أبكر بإيقاف الاستخدام المشبوه في مكانه، لا بالتخمين من قراءة السجلّ بعد السقوط.استخدام API مشبوهمجموعة فحوصات Basicsالإيقاف في مكانهإبراز المشكلة في وقت أبكرسابقاً القراءة بعد السقوط فقط

الشكل 7: قيمة Basics تحويل «القراءة بعد السقوط» إلى «الإيقاف في مكانه».

3.2. Low Resource Simulation: تقديم نقص الذاكرة ونقص الموارد

ما ينفع كثيراً في العمل هنا. لأنّه يمكن إحداث ظاهرة قريبة من نقص الذاكرة أو نقص الموارد دون استنزاف RAM فعلاً.

الفكرة بسيطة.

  • استدعاء API معيّن
  • باحتمال ثابت
  • يُفشَل عمداً

بهذا يمكن المرور بمسار خطأ لا يُمَرّ به عادة.

عمليّاً يسهل إحداث ظواهر كهذه عمداً.

  • فشل HeapAlloc أو VirtualAlloc
  • فشل CreateFile
  • فشل CreateEvent
  • فشل MapViewOfFile
  • فشل تخصيص عائلة OLE/COM مثل SysAllocString

أسهل كثيراً من تعذيب الجهاز كلّه بمحاولة نقص ذاكرة حقيقيّ. وفوق ذلك يمكن إدخال fault injection موجَّهاً إلى DLL معيَّن. في تكوين يختلط فيه غلاف ذاتيّ مع SDK البائع مثل تطبيقات التحكّم بالأجهزة، هذا أنسب للعمل كثيراً.

آليّة Low Resource Simulationيبيّن أنّ إفشال نوع معيّن من استدعاءات API عمداً باحتمال ثابت يمكّن من المرور عمداً بمسار خطأ لا يُمَرّ به عادة، ويمكن أيضاً التضييق إلى DLL معيَّن.نعملااستدعاء APIهل أصاب الاحتمال الثابت؟إرجاع فشل عمداًالمعالجة كالعادةإلى مسار خطأ لا يُمَرّ به عادةيمكن التضييق إلى DLL معيَّن

الشكل 8: هويّة Low Resource Simulation هي fault injection يفشل استدعاء API باحتمال ثابت.

3.3. Page Heap والمصحّح

للنظر إلى تلف الكومة، جمع Heaps مع page heap قويّ. خصوصاً full page heap ميزته سهولة الإيقاف في لحظة التلف باستخدام guard page.

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

لذلك كتشغيل، تقسيم كهذا واقعيّ.

  • أوّلاً التطبيق الواسع بـ Basics
  • إذا صارت الكومة مشبوهة يُستخدَم full page heap
  • إذا ثقل أكثر يُنزَل إلى light page heap
  • اختبار طويل يعادل الإنتاج يُنظَر إليه أساساً بالسجلّ الذاتيّ

أي أنّ AppVerifier ليس عصا سحريّة كليّة، بل أداة تُبدَّل شفرتها حسب المشهد.

تدفّق اختيار page heapيبيّن التطبيق الواسع بـ Basics أوّلاً، والإيقاف بـ full page heap في لحظة التلف إذا صارت الكومة مشبوهة، والنزول إلى light page heap إذا ثقل أكثر، والنظر أساساً بالسجلّ الذاتيّ في اختبار طويل يعادل الإنتاج.نعملانعملاالتطبيق الواسع بـ Basicsهل الكومة مشبوهة؟الإيقاف بـ full page heapالاختبار الطويل أساساً بالسجلّ الذاتيّهل أثقل من اللازم؟النزول إلى light page heapإعادة إنتاج محلّيّة تحت المصحّح

الشكل 9: page heap ليس أداة تُستخدَم دائماً، بل تُبدَّل الشفرة حسب المشهد بعد التطبيق الواسع بـ Basics.

3.4. !avrf / !htrace / السجلّات

كلمة أوّلاً. verifier stop الذي ظهر عدّة مرّات حتّى هنا حدث كشف يخرجه Application Verifier عندما يحكم بأنّ «هذا الاستخدام غير سليم». ليس سطر سجلّ عاديّاً، وميزته الكسر في مكانه إذا شُغِّل تحت المصحّح. للـ stop رقم، فيظهر بشكل VERIFIER STOP 00000300. هناك stop يمكن المتابعة منه، وstop لا يمكن المتابعة منه (لا خيار سوى إنهاء العمليّة).

Application Verifier لا ينتهي بإخراج stop. هناك امتدادات مصحّح وسجلّات تسهّل تتبّع ما حدث.

  • !avrf
    • النظر إلى إعداد verifier الحاليّ والـ stop الجاري
  • !htrace
    • النظر إلى مكدّس open / close / invalid reference للمقبض
  • !heap -p -a
    • تتبّع كتلة الكومة التالفة بالجمع مع page heap
  • سجلّات AppVerifier
    • يمكن إبقاء سجلّ عند حدوث stop

خصوصاً عند تفعيل Handles، يُفعَّل handle tracing تلقائيّاً وهذا ممتنّ. بهذا يسهل لاحقاً تتبّع «أين فُتح هذا المقبض وأين أُغلق».

التدفّق من verifier stop إلى التحقيقيبيّن أنّ كشف استخدام غير سليم يخرج verifier stop مرقَّماً، ويكسر في مكانه تحت المصحّح، فيُؤكَّد الإعداد والـ stop بـ avrf وتاريخ المقبض بـ htrace.كشف استخدام غير سليمverifier stop (مرقَّم)كسر تحت المصحّحتأكيد الإعداد والـ stop بـ avrfتأكيد تاريخ المقبض بـ htracestop يمكن المتابعة منه وstop لا يمكن

الشكل 10: verifier stop ليس سطر سجلّ عاديّاً، بل تحت المصحّح يكسر في مكانه فيصير نقطة انطلاق التحقيق.

4. لماذا أُدخل في هذه الحالة

4.1. الغرض ليس «إيجاد خطأ» فقط

غرض هذه الحالة لم يكن مجرّد «إيجاد خطأ واحد بـ AppVerifier». بتعبير أكثر عمليّة، ما أُريد تأكيده التالي.

  • إذا حدث تسرّب موارد لاحقاً على مسار فشل آخر
  • هل يبقى سياق في السجلّ بشكل سليم
  • هل يمكن التتبّع حتّى النهاية مع معلومات المصحّح
  • هل لا تصير الحالة «ما حدث غير معلوم»

أي أنّه استُخدم لا كـ كاشف فقط، بل كـ اختبار لبنية الرصد.

4.2. إحداث ظاهرة تشبه نقص الذاكرة

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

لذلك اتّجهنا بـ Low Resource Simulation إلى وطء مسار الفشل الذي يُتوقَّع عند نقص الذاكرة أو نقص الموارد عمداً.

بهذا يسهل الإجابة عن أسئلة كهذه.

  • إذا فشل CreateEvent، هل يبقى cameraId وphase في السجلّ
  • هل يجري clean up بشكل سليم بعد تهيئة ناقصة
  • إذا فشل VirtualAlloc، هل ينكسر الأمر بإعادة المحاولة
  • هل يعود المقبض عند فشل CreateFile في مسار الحفظ

ما يُراد التأكيد عليه أنّ الغرض ليس إحداث الشذوذ نفسه، بل أن يكون شكل الانكسار عند الشذوذ قابلاً للقراءة.

بنية رصد تُؤكَّد بـ fault injectionيبيّن وطء الفشل عمداً بـ Low Resource Simulation، وتأكيد هل يبقى سياق في السجلّ، وهل يجري التنظيف، وهل ينكسر الأمر بإعادة المحاولة. الغرض ليس إحداث الشذوذ بل أن يكون شكل الانكسار قابلاً للقراءة.وطء الفشل عمداًهل يبقى سياق في السجلّهل يجري clean upهل ينكسر الأمر بإعادة المحاولةحالة شكل الانكسار قابل للقراءة

الشكل 11: غرض fault injection ليس إحداث الشذوذ، بل تأكيد هل شكل الانكسار عند الشذوذ قابل للقراءة.

4.3. التحقّق من إمكان التتبّع عند شذوذ المقابض

كما في handle leak الذي ظهر في الجزء الأوّل، حول المقابض يسهل انحراف آخر موضع سقوط عن السبب الحقيقيّ.

لذلك ما أُريد تأكيده كهذا.

  • عند خروج invalid handle stop، هل يمكن تتبّع open / close بـ !htrace
  • هل يرتبط بـ resourceId / sessionId / phase في السجلّ الذاتيّ
  • هل يعود handle count بعد الفشل
  • عند جعل harness عمليّة قصيرة العمر، هل يسهل رؤية فرق التسريب

إذا ظهر هذا القدر، يمكن الانتقال من مجرّد «ظهر خطأ» إلى «أيّ مسؤوليّة انهارت فيها إدارة العمر».

تأكيد إمكان التتبّع عند شذوذ المقابضيبيّن تأكيد هل يمكن تتبّع open وclose بـ htrace عند خروج invalid handle stop، وهل يرتبط بسياق السجلّ الذاتيّ، وهل يعود handle count، للوصول إلى تحديد المسؤوليّة التي انهارت فيها إدارة العمر.invalid handle stopتتبّع open وclose بـ htraceالربط بسياق السجلّ الذاتيّتأكيد عودة handle countتحديد المسؤوليّة التي انهارت فيها إدارة العمر

الشكل 12: عند شذوذ المقابض لا نتوقّف عند «ظهر خطأ»، بل نؤكّد إمكان التتبّع حتّى أيّ مسؤوليّة انهارت فيها إدارة العمر.

5. كيف تُحدَث ظاهرة تشبه نقص الذاكرة أو نقص الموارد

5.1. فكرة Low Resource Simulation

Low Resource Simulation هو ما يُسمّى fault injection. الصورة ليست إعادة إنتاج بيئة منخفضة الموارد طبق الأصل، بل خلط اصطناعيّ لفشل API نموذجيّ يحدث عند انخفاض الموارد.

لذلك موضع الاستخدام واضح جدّاً.

  • تأكيد التنظيف بعد مسار الفشل
  • تأكيد صلابة retry / reconnect
  • تأكيد تهيئة يختلط فيها نجاح جزئيّ وفشل جزئيّ
  • تأكيد بقاء السجلّ حتّى عند «فشل لا يحدث عادة»

الحيلة هنا عدم إفشال كلّ شيء من البداية. إذا جُمع الكلّ دفعة واحدة تنفجر السجلّات ويضيع «ماذا ننظر إليه».

طريقة تضييق fault injectionيبيّن أنّ إفشال كلّ شيء من البداية ينفجر السجلّات فلا يُعرَف ماذا يُنظَر إليه، لذا يُفتَح مضيَّقاً من الفشل القريب من مسار الفشل المراد النظر إليه.إفشال الكلّ من البدايةانفجار السجلّات فلا تُقرأفتح الفشل المراد فقطوضوح ما يُنظَر إليه

الشكل 13: حيلة fault injection عدم جمع الكلّ، بل فتح ما يقرب من مسار الفشل المراد النظر إليه أوّلاً.

5.2. ما يمكن إفشاله

في Low Resource Simulation يمكن إفشال أنواع API التالية نموذجيّاً باحتمال.

النوع مثال مثال في تطبيق التحكّم بالأجهزة
Heap_Alloc تخصيص كومة مخزن مؤقّت، بيانات وصف الصورة، تخصيص داخل غلاف SDK
Virtual_Alloc تخصيص ذاكرة افتراضيّة مخزن إطارات أكبر، مخزن حلقيّ
File CreateFile وغيرها open لمسار الحفظ أو ملفّ السجلّ
Event CreateEvent وغيرها إشعار جاهزيّة الإطار، مزامنة stop/reconnect
MapView CreateMapView وغيرها ذاكرة مشتركة أو memory mapped file
Ole_Alloc SysAllocString وغيرها حدود COM / OLE
Wait عائلة WaitForXXX حول فشل انتظار المزامنة
Registry الوصول إلى السجلّ قراءة الإعداد وكتابته أو إعداد حول التعريف

في العمل، فتح ما يقرب من مسار الفشل المراد النظر إليه في هذه الحالة أوّلاً أهمّ من فتح الكلّ معاً.

5.3. طريقة التطبيق في العمل

كصورة لسطر الأوامر يصير مثلاً هكذا.

appverif /verify CameraHarness.exe
appverif /verify CameraHarness.exe /faults
appverif -enable lowres -for CameraHarness.exe -with heap_alloc=20000 virtual_alloc=20000 file=20000 event=20000
appverif -query lowres -for CameraHarness.exe

لا معنى للنسخ إن لم يُقرأ القصد، لذا نكتب ماذا يفعل كلّ سطر.

الأمر ماذا يفعل
appverif /verify CameraHarness.exe تفعيل مجموعة اختبارات Basics لـ CameraHarness.exe
appverif /verify CameraHarness.exe /faults فوق ذلك تفعيل fault injection. لكنّ الهدف OLE_ALLOC وHEAP_ALLOC فقط
appverif -enable lowres -for CameraHarness.exe -with heap_alloc=20000 ... تفعيل lowres (Low Resource Simulation) وتعيين نوع API المراد إفشاله والاحتمال فرداً
appverif -query lowres -for CameraHarness.exe عرض ما هو معيَّن بأيّ احتمال الآن
appverif /n CameraHarness.exe حذف إعداد ذلك EXE (نفس غرض -disable * -for أو -delete settings -for)

نضبط أيضاً قراءة الوسائط.

  • الاحتمال جزء من مليون. ما يمكن تعيينه عدد صحيح من 0 إلى 1,000,000، و20000 هو 20000 / 1,000,000 أي 2%. ليس «مرّة كلّ 20 ألفاً». وثائق Microsoft أيضاً تذكر -with registry=20000 file=20000 كمثال لإفشال API السجلّ والملفّات بـ 2%.
  • بعد /faults يمكن صفّ احتمال ومهلة سماح واسم DLL. الصيغة /faults [احتمال [مهلة بالميلي ثانية [DLL ...]]]. إذا أُغفل الاحتمال يصير 5%، وإذا أُغفلت مهلة السماح تصير 500 ميلي ثانية. مهلة السماح تعني «لا يُدخَل fault خلال هذا الزمن من تشغيل العمليّة»، لمنع فشل المعالجة عند التشغيل نفسها فلا يمكن تجربة شيء.
  • /n إلغاء. اعتبر n بمعنى «no verifier» تقريباً. الأمر المقابل لعدم ترك التفعيل مستمرّاً.

خرج -query lowres يعود تقريباً بهذا الشكل. هنا يمكن تأكيد هل الاحتمال المعيَّن داخل، وهل فُتحت أنواع لم تُقصَد.

Settings for CameraHarness.exe:
Test [lowres] enabled.

Include = *
Exclude =
TimeOut = 2000 (0x7D0)
WAIT = 0 (0x0)
HEAP_ALLOC = 20000 (0x4E20)
VIRTUAL_ALLOC = 0 (0x0)
REGISTRY = 0 (0x0)
FILE = 20000 (0x4E20)
EVENT = 20000 (0x4E20)
MAP_VIEW = 0 (0x0)
OLE_ALLOC = 0 (0x0)
STACKS = false

Include وExclude تضييق الوحدات المستهدفة، وTimeOut الزمن الذي لا يُدخَل فيه fault فور التشغيل. القيمة الافتراضيّة تختلف حسب طريقة إدخال الإعداد، لذا التأكيد بهذا الخرج أوثق من الافتراض.

كفكرة، بهذا الشكل.

  1. أوّلاً تدوير المسار العاديّ بـ Basics فقط
  2. ثمّ إضافة Low Resource Simulation والتدوير مع fault injection
  3. عند الحاجة إعطاء احتمال للفشل المراد فقط مثل file أو event
  4. إذا أُريد التوجيه إلى DLL معيَّن، يُدخَل مضيَّقاً إلى ذلك DLL

اختصار /faults مريح، لكن بهذا وحده التركيز على OLE_ALLOC وHEAP_ALLOC. إذا أُريد النظر إلى مسار فشل CreateFile أو CreateEvent، فأوثق كتابة -enable lowres -with file=... event=... أيضاً.

في تطبيقات التحكّم بالأجهزة، التضييق إلى DLL غلاف الكاميرا أو مسار الحفظ أوضح للقراءة غالباً من نثر fault على التطبيق كلّه.

ترتيب تطبيق fault injectionتطبيق مرحليّ: أوّلاً المسار العاديّ بـ Basics فقط، ثمّ التدوير مع إضافة Low Resource Simulation، ثمّ تعيين احتمال للفشل المراد فقط، ثمّ الإدخال مضيَّقاً إلى DLL معيَّن عند الحاجة.المسار العاديّ بـ Basics فقطالتدوير مع إضافة Low Resourceتعيين احتمال للفشل المراد فقطالإدخال مضيَّقاً إلى DLL معيَّن

الشكل 14: لا يُستهدف من البداية، بل يُضيَّق fault injection مرحليّاً من المسار العاديّ بـ Basics.

نضع أيضاً الكتابة العمليّة لـ «التضييق إلى DLL». الوسائط من الثالث فصاعداً في /faults تعيين الوحدة المستهدفة.

appverif /verify CameraHarness.exe /faults 50000 1000 CameraSdkWrapper.dll

بهذا، عند تشغيل CameraHarness.exe، يُفشَل باحتمال 5% (50000 / 1,000,000) العمليّات التي بدأت من CameraSdkWrapper.dll فقط، بعد مرور 1000 ميلي ثانية من التشغيل. اسم الوحدة يُكتَب مع الامتداد، بلا مسار. يمكن تعيين وحدات تُحمَّل غير .dll أيضاً مثل .ocx.

هل التضييق نافذ يُؤكَّد من صفّي Include وExclude في appverif -query lowres -for CameraHarness.exe. إذا بقي * فما زال الهدف العمليّة كلّها.

حركة fault injection المضيَّق إلى DLLيبيّن أنّ تعيين الاحتمال ومهلة السماح والوحدة المستهدفة في وسائط faults يفشل بعد انتهاء مهلة السماح من التشغيل العمليّات التي بدأت من DLL المعيَّن فقط بالاحتمال المعيَّن، ويُؤكَّد التضييق بـ Include وExclude في query.تعيين الاحتمال ومهلة السماح واسم DLLلا حقن خلال مهلة السماح من التشغيلفشل العمليّات الصادرة عن DLL المعيَّن فقطالتأكيد بـ Include وExclude في query

الشكل 15: fault injection المضيَّق إلى DLL يفشل بعد انتهاء مهلة السماح العمليّات التي بدأت من الوحدة المعيَّنة فقط.

إذا شُغِّل تحت المصحّح يمكن أيضاً تغيير النطاق في الوسط.

!avrf -trg dll CameraSdkWrapper.dll
!avrf -skp dll VendorSdk.dll

-trg «استهدف هنا»، و-skp «تجاوز هنا». يمكن أيضاً تأكيد إعداد fault injection الحاليّ بـ !avrf -flt، أو النظر إلى مكدّس الفشل المحقون أخيراً بـ !avrf -flt stacks 10.

مثلاً يمكن صنع سيناريوهات كهذه.

  • فشل CreateEvent فور بدء reconnect
  • فشل CreateFile عند بدء الحفظ
  • فشل تخصيص مخزن مؤقّت
  • فشل SysAllocString في تحويل COM
  • تأكيد مسار فشل API الانتظار

هذه لا تُوطأ عادة باختبار المسار السليم العاديّ. لذلك قيمة وطئها عمداً موجودة.

6. كيف يُنظَر إلى شذوذ المقابض

6.1. فحص Handles

حول المقابض يُستخدَم أوّلاً Handles. بهذا يسهل كشف استخدام invalid handle.

ما ينفع نموذجيّاً حوادث كهذه.

  • إعادة استخدام مقبض أُغلق
  • تمرير قيمة مقبض تالفة
  • استخدام مقبض لم يُهيَّأ بعد فشل في الوسط
  • لمس من خيط آخر بعد انهيار lifetime

ما يبدو في التشغيل الطويل «خطأ غريب أحياناً فقط» قد يتوقّف في مكانه تحت verifier. هذا التقديم يساعد كثيراً.

حوادث ينفع فيها فحص Handlesيبيّن أنّ حوادث مثل إعادة استخدام مقبض أُغلق، وقيمة مقبض تالفة، ومقبض غير مهيَّأ بعد فشل في الوسط، وإساءة استخدام من خيط آخر بانهيار العمر، يمكن إيقافها في مكانها تحت verifier.إعادة استخدام ما أُغلقverifier stop في مكانهقيمة handle تالفةhandle غير مهيَّأإساءة استخدام بانهيار العمر

الشكل 16: حوادث تمرّ في التشغيل الطويل كـ «خطأ غريب أحياناً» يوقفها فحص Handles في مكانها.

6.2. النظر إلى مكدّس open / close بـ !htrace

ما يمتنّ في Handles انسجامه مع handle tracing.

من هنا يُستخدَم المصحّح، لذا يُدخَل WinDbg أوّلاً. يُوزَّع كـ Debugging Tools for Windows، ويمكن إدخاله من مثبّت Windows SDK نفسه الذي فيه Application Verifier.

windbg -xd av -xd ch -xd sov CameraHarness.exe
!avrf
!htrace 0x00000ABC

خيارات السطر الأوّل ليست تعويذة. الاستثناءات التي يرميها Application Verifier عند الكشف ثلاثة أنواع.

الخيار الاستثناء متى يخرج
av انتهاك وصول (0xC0000005) عند كشف تجاوز مخزن الكومة
ch مقبض غير صالح (0xC0000008) عند كشف استخدام invalid handle
sov فيضان المكدّس (0xC00000FD) عند الحكم بنقص المكدّس الابتدائيّ

و-xd تعيين إمساك ذلك الاستثناء في الفرصة الثانية. الفرصة الأولى يعالجها Application Verifier نفسه لتركيب معلومات stop، لذا مقاطعة المصحّح أوّلاً غير مناسبة. إذا عُيِّن في مصحّح شُغِّل أصلاً، فهو نفسه ضرب sxd av وsxd ch وsxd sov.

ما يُراد النظر إليه بـ !htrace تقريباً هذا.

  • أين فُتح ذلك المقبض
  • أين أُغلق
  • هل أُشير إليه كـ invalid handle
  • هل تراكمت open أكثر ممّا يُفترَض

نضع أيضاً شكل الظهور الفعليّ. التالي مثال خرج وارد في الوثائق الرسميّة، وليس من بيئتنا، لكنّ الشكل نفسه.

عند وطء invalid handle يخرج أوّلاً هكذا.

Invalid handle - code c0000008 (first chance)
===================================================
VERIFIER STOP 00000300: pid 0x558: invalid handle exception for current stack trace
        C0000008 : Exception code.
        0012FBF8 : Exception record. Use .exr to display it.
        0012FC0C : Context record. Use .cxr to display it.
        00000000 :
===================================================
This verifier stop is continuable.
After debugging it use 'go' to continue.
===================================================

ثمّ بضرب !avrf يظهر ما هو مفعَّل الآن وأيّ stop يحدث. السطر الأخير خلاصة.

0:000> !avrf
Global flags: 00000100
Application verifier global flag is set.
Application verifier settings (00000004):
   - no heap checking enabled!
   - handle checks
Page heap is not active for this process.
Current stop 00000300 : c0000008 0012fbf8 0012fc0c 00000000 .
    Using an invalid handle (either closed or simply bad).

بالنظر إلى تاريخ ذلك المقبض بـ !htrace تصطفّ OPEN / CLOSE / BAD REFERENCE كلٌّ مع مكدّس.

0:000> !htrace 7DC

--------------------------------------
Handle 0x7DC - BAD REFERENCE:
0x801902BE: ntoskrnl!NtSetEvent+0x6C
0x010012C1: badhandle!mainCRTStartup+0xE3
--------------------------------------
Handle 0x7DC - CLOSE:
0x801E1EDD: ntoskrnl!NtClose+0x19
0x010012C1: badhandle!mainCRTStartup+0xE3
--------------------------------------
Handle 0x7DC - OPEN:
0x77DE265C: KERNEL32!CreateEventA+0x66
0x010011A0: badhandle!main+0x20
--------------------------------------

القراءة صريحة: إذا جاء BAD REFERENCE بعد CLOSE فمعناه إعادة استخدام مقبض أُغلق. بالنظر إلى مكدّس OPEN يُعرَف أيضاً أين أُنشئ ذلك المقبض.

ما يزعج في handle leak أو handle misuse أنّ آخر API سقطت ليست السبب الحقيقيّ. بوجود !htrace يمكن تتبّع تاريخ ذلك المقبض بتفصيل كبير.

طريقة قراءة تاريخ المقبض بـ htraceيبيّن أنّ htrace يصفّ OPEN وCLOSE وBAD REFERENCE للمقبض كلّاً مع مكدّس، وأنّ مجيء BAD REFERENCE بعد CLOSE يعني إعادة استخدام مقبض أُغلق، وأنّ مكدّس OPEN يكشف أيضاً موضع الإنشاء.OPEN (موضع الإنشاء)CLOSE (موضع الإغلاق)BAD REFERENCEتبيّن إعادة استخدام handle أُغلقكلّ سجلّ يحمل مكدّساً

الشكل 17: قراءة htrace صريحة: إذا اصطفّ BAD REFERENCE بعد CLOSE فإعادة استخدام مقبض أُغلق.

6.3. كيف يُجمع مع السجلّ الذاتيّ

مع ذلك، Application Verifier وحده لا يكفي. خصوصاً تحقيق تسريب EXE مقيم طويل الأمد بهذه الأداة وحدها متعب جدّاً.

لذلك في العمل يُجمع التالي.

  • Handle Count دوريّ
  • sessionId
  • resourceId
  • phase
  • سجلّ دورة حياة create/open وclose/dispose
  • dump وخرج المصحّح عند verifier stop

بهذا يمكن التتبّع مثلاً هكذا.

  1. بـ heartbeat يتّضح أنّ ميل Handle Count مشبوه
  2. بسجلّ دورة الحياة يُضيَّق مورد فيه Create بلا Close
  3. بـ verifier run يُخرَج invalid handle أو إساءة الاستخدام في وقت أبكر
  4. بـ !htrace يُنظَر إلى مكدّس open / close

بهذا الجمع يصير التتبّع أسهل كثيراً.

ترتيب جمع السجلّ الذاتيّ مع verifierيبيّن التتبّع بهذا الترتيب: الانتباه إلى ميل Handle Count بـ heartbeat، وتضييق المورد بلا Close بسجلّ دورة الحياة، وإخراج إساءة الاستخدام في وقت أبكر بـ verifier run، والنظر إلى مكدّس open وclose بـ htrace.الانتباه إلى ميل Handle Countتضييق المورد بسجلّ دورة الحياةإخراج إساءة الاستخدام في وقت أبكر بـ verifier runالنظر إلى المكدّس بـ htrace

الشكل 18: كشف الميل بالسجلّ الذاتيّ وكشف إساءة الاستخدام بـ verifier، يُربَطان بهذا الترتيب.

7. طريقة بناء بنية اختبار المسارات الشاذّة

7.1. إمالة وحدة التنفيذ إلى harness

Application Verifier لا يمكن تفعيله لاحقاً على عمليّة جارية. تعيين ثمّ تشغيل.

وفوق ذلك يبقى الإعداد حتّى يُحذف صراحة. لذلك في العمل الإمالة إلى harness EXE للاختبار أسهل من التطبيق الإنتاجيّ نفسه.

مثلاً تكوين كهذا.

Scenario RunnerCameraHarness.exeCameraSdkWrapper.dllVendor SDKStructured LogDump / Debugger

الشكل 19: تكوين harness يُدار بعمليّة واحدة لكلّ سيناريو. هدف verifier ليس DLL بل harness EXE الذي يشغّله.

بهذا،

  • يمكن التدوير بعمليّة واحدة لكلّ سيناريو
  • يسهل رؤية فرق التسريب
  • يسهل تبديل إعداد AppVerifier بين ON/OFF
  • حتّى عند تجربة DLL يمكن التعامل من جانب EXE

هذه الفوائد موجودة.

صورة الأمر هكذا.

appverif /verify CameraHarness.exe
appverif /n CameraHarness.exe

/verify تفعيل Basics، و/n حذف الإعداد (انظر أيضاً جدول 5.3). التفعيل قبل التشغيل، والإلغاء صراحة. تدوير هذا بافتراض harness يقلّل أيضاً حوادث الإعداد.

7.2. تقسيم قائمة الاختبار

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

  1. المسار العاديّ + Basics
    • لا حقن فشل
    • تأكيد عدم خروج verifier stop
  2. عائلة fault injection
    • Low Resource Simulation
    • إفشال event / file / heap_alloc / virtual_alloc وغيرها عمداً
  3. عائلة تعميق الكومة
    • Heaps
    • full page heap
    • إعادة إنتاج محلّيّة تحت المصحّح

بتقسيم هذا، يصعب اختلاط «هل ينكسر في الاستخدام العاديّ» مع «هل ينكسر عند انخفاض الموارد فقط».

خصوصاً بوجود fault injection أو غيابه يتغيّر مسار الشيفرة الممرور به كثيراً. لذلك يُفضَّل تدوير run بلا fault وrun مع fault كليهما.

قائمة اختبار مقسومة إلى ثلاثةيبيّن تقسيم الاختبار إلى ثلاثة: المسار العاديّ زائد Basics بلا حقن، وعائلة fault injection التي تفشل عمداً بـ Low Resource Simulation، وعائلة تعميق الكومة التي تدير full page heap تحت المصحّح.طريقة تدوير اختبار المسارات الشاذّةالمسار العاديّ وBasicsعائلة fault injectionعائلة تعميق الكومةتأكيد عدم خروج stopحقن الفشل المقصودإعادة إنتاج محلّيّة تحت المصحّح

الشكل 20: عدم فعل الكلّ في مرّة واحدة وتقسيم القائمة إلى ثلاثة يمنع اختلاط أين ينكسر الأمر.

7.3. ما يُجمَع

في الحدّ الأدنى يُراد أخذ هذا القدر.

النوع المطلوب
سجلّ التطبيق cameraId, sessionId, phase, handleCount, error code
حالة العمليّة Handle Count, Private Bytes, Thread Count
معلومات المصحّح !avrf, !htrace, و!heap -p -a عند الحاجة
dump عند verifier stop أو عند الإنهاء الشاذّ
سجلّ AppVerifier سجلّ stop، وتحويله إلى XML للتجميع عند الحاجة

عند الحاجة يمكن أيضاً تحويل سجلّ جانب AppVerifier إلى XML وتجميعه. لكن النظر إليه وحده كثيراً ما لا يغلق السبب، لذا افتراض القراءة بمحاذاة السجلّ الذاتيّ أنسب للعمل.

كثرة السجلّات نفسها ليست فضلاً. ارتباط السببيّة لاحقاً هو المهمّ.

7.4. شروط القبول

شرط القبول «لم يسقط» وحده ضعيف أيضاً. في سياق هذه الحالة لزم على الأقلّ التالي.

  • عدم خروج verifier stop في المسار العاديّ + Basics
  • بقاء الفشل المتوقَّع في السجلّ حتّى مع fault injection
  • تنظيف الموارد المهيَّأة ناقصة بشكل سليم
  • عودة Handle Count قرب baseline بعد reconnect / retry
  • إمكان التتبّع بـ sessionId / phase / المكدّس عند خروج verifier stop
  • عدم صيرورة الفشل «ما حدث غير معلوم»

المهمّ هنا تقييم عدم الانكسار وإمكان التتبّع عند الانكسار منفصلين.

محوران لشروط القبوليبيّن تقييم شروط القبول على محورين: عدم الانكسار بعدم خروج verifier stop في المسار العاديّ وتنظيف الموارد، وإمكان التتبّع عند الانكسار ببقاء الفشل المتوقَّع في السجلّ وإمكان التتبّع بالسياق والمكدّس.شروط القبولعدم الانكسارإمكان التتبّع عند الانكسارعدم خروج stopتنظيف المواردبقاء الفشل في السجلّإمكان التتبّع بالمكدّس

الشكل 21: «لم يسقط» وحده ضعيف، ويُقيَّم عدم الانكسار وإمكان التتبّع كمحورين منفصلين.

7.5. تنبيهات

Application Verifier مريح جدّاً، لكنّه ليس سحراً.

  • مسار الشيفرة الذي لم يُمَرّ به فعليّاً لا يُتحقَّق منه
  • full page heap ثقيل
  • قد يخرج stop من جانب SDK طرف ثالث أيضاً
  • مسار الشيفرة الممرور به يختلف كثيراً بوجود fault injection أو غيابه
  • ليست أداة لتحقيق تسريب كومة managed خالص بهذه الأداة وحدها

لذلك كموقع هكذا.

  • الميل الطويل بالسجلّ الذاتيّ والعدّادات
  • إساءة الاستخدام عند الحدود الأصليّة بـ Application Verifier
  • استعادة السببيّة عند الشذوذ بـ structured log + dump + المصحّح

هذا التقسيم أنسب للعمل.

الصورة الكلّيّة لتقسيم التحقيقيبيّن التقسيم: الميل الطويل بالسجلّ الذاتيّ والعدّادات، وإساءة الاستخدام عند الحدود الأصليّة بـ Application Verifier، واستعادة السببيّة عند الشذوذ بالسجلّ وdump والمصحّح.الميل الطويلالسجلّ الذاتيّ والعدّاداتإساءة الاستخدام عند الحدود الأصليّةApplication Verifierاستعادة السببيّة عند الشذوذالسجلّ وdump والمصحّح

الشكل 22: Application Verifier ليس عصا سحريّة كليّة، بل تُقسَم الأداة حسب المراد النظر إليه.

8. دليل اختيار تقريبيّ

  • اشتباه invalid handle أو double close
    • Handles + !htrace
  • اشتباه heap corruption / use-after-free
    • Heaps + full page heap + !heap -p -a
  • إرادة إحداث ظاهرة تشبه نقص الذاكرة أو نقص الموارد
    • Low Resource Simulation
  • انكسار تدريجيّ في التشغيل الطويل
    • أوّلاً Handle Count / Private Bytes / سجلّ دورة الحياة الذاتيّ
  • إرادة تجربة DLL
    • تفعيل Application Verifier على harness EXE الذي يستدعي ذلك DLL

جمع الكلّ من البداية يصير عادة ضباب سجلّات. تطبيق الشفرة القريبة من مسار الفشل المراد النظر إليه أوضح كثيراً.

9. الخلاصة

موقع Application Verifier متحقّق وقت التشغيل لحدود native / Win32 في Windows. باستخدام Handles / Heaps / Locks / Memory / TLS / Low Resource Simulation وغيرها يمكن وطء مسار الفشل الذي يصعب ظهوره عادة في وقت أبكر.

ما نفع في سياق هذه الحالة سهولة التتبّع بـ !htrace عند شذوذ المقابض، وإمكان إحداث ظاهرة تشبه نقص الذاكرة أو نقص الموارد دون كسر الجهاز كلّه، وتأكيد هل السجلّ الذاتيّ ينفع حقّاً عندئذ.

كطريقة تدوير في العمل، فصل المسار العاديّ + Basics عن عائلة fault injection، وتجهيز harness EXE وتدوير السيناريو بعمليّة قصيرة العمر. فوق ذلك الجمع مع السجلّ الذاتيّ وdump ومعلومات المصحّح، والنظر إلى ميل التسريب الطويل نفسه بعدّادات ذاتيّة. هذا التقسيم.

Application Verifier أداة لـ «الذهاب لاستقبال» الشذوذ نادر الظهور، لا «انتظار حدوثه مصادفة».

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

الجزء الأوّل: تحقيق تعطّل الكاميرا الصناعيّة بعد تشغيل طويل: فصل handle leak

10. روابط مرجعيّة

أحدث المقالات التي تشترك في نفس الوسوم. عمّق فهمك بمواضيع مرتبطة.

صفحة دراسة حالة توضّح بنية مشابهة للتشخيص أو تحديد الأولويات أو إعادة التصميم.

ترتبط هذه المقالة بشكل طبيعي بصفحات الخدمات التالية.

الأسئلة الشائعة

أسئلة شائعة حول موضوع هذه المقالة.

ما هو Application Verifier؟
أداة تحقّق وقت التشغيل لتطبيقات user-mode في Windows. تراقب استخدام التطبيق الجاري لـ OS API وطريقة تعامله مع الموارد، فتكشف استخداماً مشبوهاً مثل invalid handle أو heap corruption، ويمكنها أيضاً حقن فشل عمداً. بخلاف التحليل الساكن أو اختبار الوحدة، هي أداة تنظر كيف ينكسر الأمر عند المرور فعليّاً بمسار الشيفرة ذلك، لذا تناسب إبراز مسار الفشل الذي لا يظهر في اختبار الوظائف العاديّ.
هل يمكن إعادة إنتاج نقص الذاكرة بـ Application Verifier؟
باستخدام Low Resource Simulation يمكن إحداث ظاهرة قريبة من نقص الذاكرة أو نقص الموارد في وقت أبكر دون استنزاف RAM الجهاز فعلاً. الآليّة fault injection: إفشال استدعاءات API مثل HeapAlloc وVirtualAlloc وCreateFile وCreateEvent عمداً باحتمال ثابت. يمكن أيضاً حقن الفشل موجَّهاً إلى DLL معيَّن، فيسهل التعامل حتّى في تكوين يختلط فيه غلاف ذاتيّ مع SDK البائع. لكن إفشال كلّ شيء من البداية يجعل السجلّات غير قابلة للقراءة، لذا الحيلة فتح ما يقرب من مسار الفشل المراد النظر إليه أوّلاً.
هل يُستخدَم Application Verifier في تحقيق handle leak؟
بتفعيل فحص Handles يمكن كشف استخدام invalid handle مثل إعادة استخدام مقبض أُغلق، ويُفعَّل handle tracing تلقائيّاً أيضاً فيمكن تتبّع مكدّس open / close لذلك المقبض بـ !htrace. لكن إلقاء تحقيق تسريب EXE مقيم طويل الأمد على Application Verifier وحده غير واقعيّ. الجمع مع تسجيل دوريّ لـ Handle Count وسجلّ ذاتيّ لدورة حياة المورد، بحيث يكشف السجلّ الذاتيّ الميل ويكشف verifier إساءة الاستخدام، أنسب للعمل.
كيف يُستخدَم Application Verifier لاختبار DLL؟
هدف تفعيل Application Verifier هو EXE الاختبار الذي يشغّل ذلك DLL فعليّاً. لا يمكن التفعيل لاحقاً على عمليّة جارية، ويلزم التعيين ثمّ التشغيل. والإعداد يبقى حتّى يُحذف صراحة، لذا الإمالة إلى harness EXE للاختبار أسهل من التطبيق الإنتاجيّ نفسه. التدوير بعمليّة واحدة لكلّ سيناريو يسهّل أيضاً رؤية فرق التسريب وتبديل إعداد ON/OFF.

الملف الشخصي للمؤلف

صفحة الملف الشخصي لمؤلف المقالة.

غو كومورا

مؤسّس شركة كومورا سوفت ذ.م.م.

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

العودة إلى المدونة