أعجب PVS-Studio بجودة كود Abbyy NeoML

image1.png


نشرت ABBYY مؤخرًا شفرة المصدر لإطار عمل NeoML الخاص بها. عرض علينا فحص هذه المكتبة باستخدام PVS-Studio. هذا مشروع مثير للاهتمام من وجهة نظر التحليل ، لذلك لم نضعه جانباً. لن تستغرق قراءة هذا المقال الكثير من الوقت ، حيث اتضح أن المشروع عالي الجودة :).



يمكن العثور على شفرة مصدر NeoML على GitHub . هذا الإطار متعدد المنصات ومصمم لتنفيذ نماذج التعلم الآلي. يتم استخدامه من قبل مطوري ABBYY لحل مشاكل رؤية الكمبيوتر ومعالجة اللغة الطبيعية ، بما في ذلك معالجة الصور وتحليل المستندات وما إلى ذلك. حاليًا ، يتم دعم لغات البرمجة مثل C ++ و Java و Objective-C ، ويجب إضافة Python إلى هذه القائمة قريبًا. اللغة الرئيسية التي كُتب بها الإطار نفسه هي C ++.



التحليل الجاري



كان إجراء التحليل على هذا الإطار بسيطًا جدًا. بعد إنشاء مشروع Visual Studio في CMake ، أطلقت تحليل PVS-Studio في Visual Studio للمشاريع التي تهمنا من Solution ، باستثناء مكتبات الجهات الخارجية. بالإضافة إلى NeoML نفسه ، تضمن الحل أيضًا مكتبات من ABBYY مثل NeoOnnx و NeoMathEngine. كما أدرجتها في قائمة المشاريع التي بدأ التحليل من أجلها.



تحليل النتائج



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



على سبيل المثال ، في هذا المشروع ، غالبًا ما يتم استدعاء طريقة افتراضية من المُنشئ. بشكل عام ، هذا نهج خطير. يستجيب تشخيص V1053 لمثل هذه الحالات : قد يؤدي استدعاء الوظيفة الافتراضية "foo" في المنشئ / المدمر إلى نتيجة غير متوقعة في وقت التشغيل . وقد تم إصدار ما مجموعه 10 تحذيرات من هذا القبيل. يمكنك قراءة المزيد حول سبب كون هذه ممارسة خطيرة والمشكلات التي تسببها في هذه المقالة بقلم سكوت مايرز "لا تتصل بالوظائف الافتراضية أثناء الإنشاء أو التدمير . ومع ذلك ، يبدو أن المطورين يفهمون ما يفعلونه ولا توجد أخطاء.



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



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



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



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



V802 على النظام الأساسي 64 بت ، يمكن تقليل حجم الهيكل من 24 إلى 16 بايت عن طريق إعادة ترتيب الحقول وفقًا لأحجامها بترتيب تنازلي. التجميع الهرمي. h 31



struct CParam {
  TDistanceFunc DistanceType; 
  double MaxClustersDistance;
  int MinClustersCount; 
};


ببساطة عن طريق تبديل حقل MaxClustersDistance من النوع المزدوج وعداد العد المسافة ، يمكنك تقليل حجم الهيكل من 24 إلى 16 بايت.



struct CParam {
  double MaxClustersDistance;
  int MinClustersCount; 
  TDistanceFunc DistanceType; 
};


TDistanceFunc هو تعداد ، لذا فإن حجمه يعادل int أو أقل ، لذلك يجب نقله إلى نهاية الهيكل.



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



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



أقدم لكم المثال الأكثر توضيحاً: V807 انخفاض الأداء. ضع في اعتبارك إنشاء مرجع لتجنب استخدام نفس التعبير بشكل متكرر. 469



image3.png


يمكن استبدال استدعاء curLevelStatistics [i] -> ThreadStatistics [j] باستدعاء متغير منفصل. لا يوجد استدعاء لأية طرق معقدة في هذه السلسلة ، لذلك قد لا يكون هناك الكثير من التحسين هنا ، ولكن في رأيي ، سيتم قراءة التعليمات البرمجية أسهل بكثير وأكثر إحكاما. بالإضافة إلى ذلك ، بدعم من هذا الرمز ، سيتبين بوضوح في المستقبل أنه من الضروري الوصول إلى هذه المؤشرات بالضبط ولا يوجد خطأ هنا. للتوضيح ، سأعطي رمزًا مع استبدال لمتغير:



auto threadStatistics = curLevelStatistics[i]->ThreadStatistics[j];

if(threadStatistics.FeatureIndex != NotFound ) {
  if(   threadStatistics.Criterion > criterion
     || ( .... ))
  {
    criterion = threadStatistics.Criterion;
    curLevelStatistics[i]->FeatureIndex    = threadStatistics.FeatureIndex;
    curLevelStatistics[i]->Threshold       = threadStatistics.Threshold;
    curLevelStatistics[i]->LeftStatistics  = threadStatistics.LeftStatistics;
    curLevelStatistics[i]->RightStatistics = threadStatistics.RightStatistics;
  }
}


خاتمة



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



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



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





إذا كنت تريد مشاركة هذه المقالة مع جمهور يتحدث الإنجليزية ، فيرجى استخدام رابط الترجمة: Victoria Khanieva. تأثرت خدمة PVS-Studio بجودة كود ABBYY NeoML .



All Articles