هذه قصة قصيرة حول كيفية استخدام PVS-Studio كان من الممكن العثور على خطأ في التعليمات البرمجية المصدر للمكتبة المستخدمة في PVS-Studio. علاوة على ذلك ، ليس نظريًا ، لكنه حقيقي - لقد تجلى الخطأ في التطبيق عند استخدام المكتبة في المحلل.
في PVS-Studio_Cmd (وكذلك بعض الأدوات المساعدة الأخرى) نستخدم مكتبة خاصة لتحليل وسيطات سطر الأوامر - CommandLine.
اشتركت اليوم في دعم الوضع الجديد في PVS-Studio_Cmd ، وقد حدث أن اضطررت إلى استخدام مكتبة تحليل الحجج هذه. في عملية كتابة التعليمات البرمجية ، أقوم أيضًا بتصحيحها ، حيث يجب أن أعمل مع واجهات برمجة التطبيقات غير المألوفة.
لذلك ، يتم كتابة التعليمات البرمجية ، تجميع ، تشغيل للتنفيذ ، الثاني ...
تنفيذ التعليمات البرمجية في المكتبة حيث يحدث استثناء من النوع
NullReferenceException . من الجانب ، ليس واضحًا تمامًا - أنا لا أعطي أي إشارات فارغة صريحة إلى الطريقة.
فقط في حالة ، أنا أنظر إلى التعليقات على الأسلوب يسمى. من غير المرجح أن يصفوا الشروط الخاصة باستثناء نوع
NullReferenceException (حيث عادة ، كما يبدو لي ، فإن استثناءات من هذا النوع غير متوقعة).
في التعليقات على الطريقة ، لا توجد معلومات حول أي
NullReferenceException (مع ذلك ، من المتوقع).
من أجل معرفة ما الذي يسبب الاستثناء (وأين) بالضبط ، قررت تنزيل رمز مصدر المشروع ، وتجميع وتوصيل نسخة تصحيح المكتبة من المحلل. الكود المصدري للمشروع
متاح على جيثب . الإصدار 1.9.71 مطلوب ، لأنه بالضبط هذا النوع الذي يستخدم الآن في محلل.
يمكنني تحميل الإصدار المناسب من الكود المصدري ، وجمع ، وتوصيل مكتبة التصحيح بالمحلل ، وتشغيل الكود للتنفيذ ، وانظر:
لذلك ، يكون مكان الاستثناء واضحًا -
helpInfo خالية ، مما يؤدي إلى استثناء نوع
NullReferenceException عند الوصول إلى خاصية المثيل
الأيسر .
ثم أصبحت مدروس. في الآونة الأخيرة ، تم تحسين PVS-Studio for C # جيدًا في العديد من المجالات ، بما في ذلك في مجال البحث عن إلغاء المرجع من المراجع المحتمل أن تكون خالية. على وجه الخصوص ، تم تحسين التحليل interprocedural. لذلك ، أصبح من الممتع بالنسبة لي على الفور التحقق من الكود المصدري لمعرفة ما إذا كان بإمكان PVS-Studio العثور على الخطأ قيد المناقشة.
راجعت الكود المصدري ، ومن بين التحذيرات الأخرى ، رأيت بالضبط ما كنت آمل فيه.
تحذير PVS-Studio :
V3080 dereference فارغة محتملة داخل الأسلوب في 'helpInfo.Left'. النظر في فحص الوسيطة 2: helpInfo. Parser.cs 405
نعم هناك! بالضبط ما تحتاجه. لنلقِ نظرة على الكود المصدري بمزيد من التفاصيل.
private bool DoParseArgumentsVerbs( string[] args, object options, ref object verbInstance) { var verbs = ReflectionHelper.RetrievePropertyList<VerbOptionAttribute>(options); var helpInfo = ReflectionHelper.RetrieveMethod<HelpVerbOptionAttribute>(options); if (args.Length == 0) { if (helpInfo != null || _settings.HelpWriter != null) { DisplayHelpVerbText(options, helpInfo, null);
ينشئ المحلل رسالة تحذير عند استدعاء الأسلوب
DisplayHelpVerbText ويحذر من الوسيطة الثانية -
helpInfo . لاحظ أن هذه الطريقة موجودة في فرع
ثم عبارة if . يتكون التعبير الشرطي بطريقة يمكن من خلالها تنفيذ الفرع بقيم المتغيرات التالية:
- helpInfo == null ؛
- _settings.HelpWriter! = null ؛
دعنا نرى
نص أسلوب
DisplayHelpVerbText :
private void DisplayHelpVerbText( object options, Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo, string verb) { string helpText; if (verb == null) { HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, null, out helpText); } else { HelpVerbOptionAttribute.InvokeMethod(options, helpInfo, verb, out helpText); } if (_settings.HelpWriter != null) { _settings.HelpWriter.Write(helpText); } }
نظرًا لأن
الفعل == null (راجع استدعاء الأسلوب) ، نحن مهتمون في ذلك الوقت بفرع
if . على الرغم من أن الوضع في الفرع
الآخر سيكون مماثلاً ، إلا أننا سننظر في الفرع في ذلك الوقت ، حيث كان التنفيذ في حالتنا الخاصة من خلاله. تذكر أن
helpInfo يمكن أن تكون
خالية .
الآن دعونا ننظر إلى
نص أسلوب
HelpVerbOptionAttribute.InvokeMethod . في الواقع ، لقد رأيته بالفعل في لقطة الشاشة أعلاه:
internal static void InvokeMethod( object target, Pair<MethodInfo, HelpVerbOptionAttribute> helpInfo, string verb, out string text) { text = null; var method = helpInfo.Left; if (!CheckMethodSignature(method)) { throw new MemberAccessException( SR.MemberAccessException_BadSignatureForHelpVerbOptionAttribute .FormatInvariant(method.Name)); } text = (string)method.Invoke(target, new object[] { verb }); }
helpInfo.Left يسمى دون قيد أو شرط ، على الرغم من أن
helpInfo يمكن أن تكون
خالية . حذر المحلل من هذا ، وهذا ما حدث.
استنتاجاتضح أنه من المضحك أنه بمساعدة PVS-Studio ، كان من الممكن العثور على خطأ في رمز المكتبة المستخدمة في PVS-Studio. أعتقد أن هذا نوع من استمرار الإجابة على السؤال "هل يجد PVS-Studio أخطاء في شفرة PVS-Studio؟". :) يمكن العثور على أخطاء ليس فقط في رمز PVS-Studio ، ولكن أيضًا في رمز المكتبات المستخدمة.
أخيرًا ، أقترح
تنزيل المحلل ومحاولة التحقق من مشروعك - ماذا لو وجدت شيئًا مثيرًا للاهتمام أيضًا؟

إذا كنت ترغب في مشاركة هذه المقالة مع جمهور يتحدث الإنجليزية ، فالرجاء استخدام الرابط الخاص بترجمة: Sergey Vasiliev.
قصة كيف وجدت PVS-Studio خطأ في المكتبة المستخدمة في ... PVS-Studio