قصة كيف وجدت PVS-Studio خطأ في المكتبة المستخدمة في ... PVS-Studio

الصورة 1

هذه قصة قصيرة حول كيفية استخدام PVS-Studio كان من الممكن العثور على خطأ في التعليمات البرمجية المصدر للمكتبة المستخدمة في PVS-Studio. علاوة على ذلك ، ليس نظريًا ، لكنه حقيقي - لقد تجلى الخطأ في التطبيق عند استخدام المكتبة في المحلل.

في PVS-Studio_Cmd (وكذلك بعض الأدوات المساعدة الأخرى) نستخدم مكتبة خاصة لتحليل وسيطات سطر الأوامر - CommandLine.

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

لذلك ، يتم كتابة التعليمات البرمجية ، تجميع ، تشغيل للتنفيذ ، الثاني ...

الصورة 3


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

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

الصورة 2


في التعليقات على الطريقة ، لا توجد معلومات حول أي NullReferenceException (مع ذلك ، من المتوقع).

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

يمكنني تحميل الإصدار المناسب من الكود المصدري ، وجمع ، وتوصيل مكتبة التصحيح بالمحلل ، وتشغيل الكود للتنفيذ ، وانظر:

صورة 4


لذلك ، يكون مكان الاستثناء واضحًا - 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); // <= } return false; } .... } 

ينشئ المحلل رسالة تحذير عند استدعاء الأسلوب 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

Source: https://habr.com/ru/post/ar462949/


All Articles