كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال

كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال
Travis CI هي خدمة ويب موزعة لبناء واختبار البرامج التي تستخدم GitHub كاستضافة التعليمات البرمجية المصدر. بالإضافة إلى سيناريوهات التشغيل المذكورة أعلاه، يمكنك إضافة شكرك الخاص إلى خيارات التكوين الشاملة. في هذه المقالة سنقوم بتكوين Travis CI للعمل مع PVS-Studio باستخدام مثال كود PPSSPP.

مقدمة

ترافيس سي هي خدمة ويب لبناء واختبار البرمجيات. وعادة ما يتم استخدامه بالتزامن مع ممارسات التكامل المستمر.

بي بي إس إس بي بي - محاكي وحدة تحكم ألعاب PSP. البرنامج قادر على محاكاة إطلاق أي ألعاب من صور القرص المخصصة لجهاز Sony PSP. تم إصدار البرنامج في 1 نوفمبر 2012. PPSSPP مرخص بموجب GPL v2. يمكن لأي شخص إجراء تحسينات على كود مصدر المشروع.

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

إعداد ترافيس CI

سنحتاج إلى مستودع على GitHub، حيث يوجد المشروع الذي نحتاجه، بالإضافة إلى مفتاح PVS-Studio (يمكنك الحصول عليه مفتاح المحاكمة أو مجاني للمشاريع مفتوحة المصدر).

دعنا نذهب إلى الموقع ترافيس سي. بعد الترخيص باستخدام حساب GitHub الخاص بك، سنرى قائمة بالمستودعات:

كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال
للاختبار، قمت بتشعب PPSSPP.

نقوم بتنشيط المستودع الذي نريد جمعه:

كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال
في الوقت الحالي، لا يستطيع Travis CI بناء مشروعنا لأنه لا توجد تعليمات للبناء. لذلك حان الوقت للتكوين.

أثناء التحليل، ستكون بعض المتغيرات مفيدة لنا، على سبيل المثال، مفتاح PVS-Studio، والذي سيكون من غير المرغوب فيه تحديده في ملف التكوين. لذلك دعونا نضيف متغيرات البيئة باستخدام إعدادات البناء في Travis CI:

كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال
نحن بحاجة إلى:

  • PVS_USERNAME - اسم المستخدم
  • PVS_KEY - المفتاح
  • MAIL_USER - البريد الإلكتروني الذي سيتم استخدامه لإرسال التقرير
  • MAIL_PASSWORD - كلمة مرور البريد الإلكتروني

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

لذلك، أضفنا متغيرات البيئة التي نحتاجها:

كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال
الآن لنقم بإنشاء ملف .travis.yml ووضعه في جذر المشروع. كان لدى PPSSPP بالفعل ملف تكوين لـ Travis CI، ومع ذلك، كان كبيرًا جدًا وغير مناسب تمامًا للمثال، لذلك كان علينا تبسيطه بشكل كبير وترك العناصر الأساسية فقط.

أولاً، دعنا نشير إلى اللغة، وإصدار Ubuntu Linux الذي نريد استخدامه في الجهاز الظاهري، والحزم اللازمة للإنشاء:

language: cpp
dist: xenial

addons:
  apt:
    update: true
    packages:
      - ant
      - aria2
      - build-essential
      - cmake
      - libgl1-mesa-dev
      - libglu1-mesa-dev
      - libsdl2-dev
      - pv
      - sendemail
      - software-properties-common
    sources:
      - sourceline: 'ppa:ubuntu-toolchain-r/test'
      - sourceline: 'ppa:ubuntu-sdk-team/ppa'

جميع الحزم المدرجة مطلوبة حصريًا لـ PPSSPP.

الآن نشير إلى مصفوفة التجميع:

matrix:
  include:
    - os: linux
      compiler: "gcc"
      env: PPSSPP_BUILD_TYPE=Linux PVS_ANALYZE=Yes
    - os: linux
      compiler: "clang"
      env: PPSSPP_BUILD_TYPE=Linux

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

كل ما تبقى هو تقديم تعليمات التجميع الخاصة بالمشروع:

before_install:
  - travis_retry bash .travis.sh travis_before_install

install:
  - travis_retry bash .travis.sh travis_install

script:
  - bash .travis.sh travis_script

after_success:
  - bash .travis.sh travis_after_success

يتيح لك Travis CI إضافة أوامرك الخاصة لمراحل مختلفة من عمر الجهاز الظاهري. قسم before_install يتم تنفيذها قبل تثبيت الحزم. ثم تثبيت، والذي يتبع تثبيت الحزم من القائمة addons.aptالذي أشرنا إليه أعلاه. يتم التجمع نفسه في سيناريو. إذا سار كل شيء على ما يرام، فسنجد أنفسنا فيه after_success (في هذا القسم سنقوم بإجراء تحليل ثابت). هذه ليست كل الخطوات التي يمكن تعديلها، إذا كنت بحاجة إلى المزيد، فعليك البحث فيها وثائق ترافيس CI.

لسهولة القراءة، تم وضع الأوامر في برنامج نصي منفصل .ترافيس.ش، والذي يتم وضعه في جذر المشروع.

لذلك لدينا الملف التالي .travis.yml:

language: cpp
dist: xenial

addons:
  apt:
    update: true
    packages:
      - ant
      - aria2
      - build-essential
      - cmake
      - libgl1-mesa-dev
      - libglu1-mesa-dev
      - libsdl2-dev
      - pv
      - sendemail
      - software-properties-common
    sources:
      - sourceline: 'ppa:ubuntu-toolchain-r/test'
      - sourceline: 'ppa:ubuntu-sdk-team/ppa'

matrix:
  include:
    - os: linux
      compiler: "gcc"
      env: PVS_ANALYZE=Yes
    - os: linux
      compiler: "clang"

before_install:
  - travis_retry bash .travis.sh travis_before_install

install:
  - travis_retry bash .travis.sh travis_install

script:
  - bash .travis.sh travis_script

after_success:
  - bash .travis.sh travis_after_success

قبل تثبيت الحزم، سنقوم بتحديث الوحدات الفرعية. هذا ضروري لبناء PPSSPP. دعونا نضيف الوظيفة الأولى إلى .ترافيس.ش (لاحظ الامتداد):

travis_before_install() {
  git submodule update --init --recursive
}

نأتي الآن مباشرةً إلى إعداد التشغيل التلقائي لـ PVS-Studio في Travis CI. نحتاج أولاً إلى تثبيت حزمة PVS-Studio على النظام:

travis_install() {
  if [ "$CXX" = "g++" ]; then
    sudo apt-get install -qq g++-4.8
  fi
  
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    wget -q -O - https://files.viva64.com/etc/pubkey.txt 
      | sudo apt-key add -
    sudo wget -O /etc/apt/sources.list.d/viva64.list 
      https://files.viva64.com/etc/viva64.list  
    
    sudo apt-get update -qq
    sudo apt-get install -qq pvs-studio 
                             libio-socket-ssl-perl 
                             libnet-ssleay-perl
  fi
    
  download_extract 
    "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" 
    cmake-3.6.2-Linux-x86_64.tar.gz
}

في بداية الوظيفة travis_install نقوم بتثبيت المترجمين الذين نحتاجهم باستخدام متغيرات البيئة. ثم إذا كان المتغير $PVS_ANALYZE قيمة المتاجر نعم (وقد أشرنا إليه في الباب الحياة الفطرية أثناء تكوين مصفوفة البناء)، نقوم بتثبيت الحزمة pvs-studio. وبالإضافة إلى ذلك، يشار أيضا إلى الحزم libio-socket-ssl-perl и libnet-ssleay-بيرلومع ذلك، فهي مطلوبة لإرسال النتائج بالبريد، لذا فهي ليست ضرورية إذا اخترت طريقة أخرى لتسليم تقريرك.

وظيفة download_extract تنزيل وتفكيك الأرشيف المحدد:

download_extract() {
  aria2c -x 16 $1 -o $2
  tar -xf $2
}

حان الوقت لوضع المشروع معًا. يحدث هذا في القسم سيناريو:

travis_script() {
  if [ -d cmake-3.6.2-Linux-x86_64 ]; then
    export PATH=$(pwd)/cmake-3.6.2-Linux-x86_64/bin:$PATH
  fi
  
  CMAKE_ARGS="-DHEADLESS=ON ${CMAKE_ARGS}"
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  fi
  cmake $CMAKE_ARGS CMakeLists.txt
  make
}

في الواقع، هذا تكوين أصلي مبسط، باستثناء هذه السطور:

if [ "$PVS_ANALYZE" = "Yes" ]; then
  CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
fi

في هذا القسم من التعليمات البرمجية وضعنا ل cmake علامة لتصدير أوامر التجميع. يعد هذا ضروريًا لمحلل الكود الثابت. يمكنك قراءة المزيد عن هذا في المقال "كيفية تشغيل PVS-Studio على Linux وmacOS".

إذا نجح التجمع، فسوف نصل إليه after_success، حيث نقوم بإجراء تحليل ثابت:

travis_after_success() {
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
    pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                    -o PVS-Studio-${CC}.log 
                                    --disableLicenseExpirationCheck
    
    plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
    sendemail -t [email protected] 
              -u "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -m "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -s smtp.gmail.com:587 
              -xu $MAIL_USER 
              -xp $MAIL_PASSWORD 
              -o tls=yes 
              -f $MAIL_USER 
              -a PVS-Studio-${CC}.log PVS-Studio-${CC}.html
  fi
}

دعونا نلقي نظرة فاحصة على السطور التالية:

pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                -o PVS-Studio-${CC}.log 
                                --disableLicenseExpirationCheck
plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html

يقوم السطر الأول بإنشاء ملف ترخيص من اسم المستخدم والمفتاح الذي حددناه في البداية عند إعداد متغيرات بيئة Travis CI.

السطر الثاني يبدأ التحليل مباشرة. علَم يحدد عدد المواضيع للتحليل، العلم يشير إلى الترخيص والعلم -o يحدد الملف لسجلات الإخراج، والعلم -تعطيلLicenseExpirationCheck مطلوب للإصدارات التجريبية، لأنه بشكل افتراضي محلل pvs-studio سيحذر المستخدم من أن الترخيص على وشك الانتهاء. لمنع حدوث ذلك، يمكنك تحديد هذه العلامة.

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

في هذا المثال، قررت إرسال التقارير عبر البريد باستخدام الأمر ارسل بريد الكتروني.

ونتيجة لذلك، حصلنا على الملف التالي .ترافيس.ش:

#/bin/bash

travis_before_install() {
  git submodule update --init --recursive
}

download_extract() {
  aria2c -x 16 $1 -o $2
  tar -xf $2
}

travis_install() {
  if [ "$CXX" = "g++" ]; then
    sudo apt-get install -qq g++-4.8
  fi
  
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    wget -q -O - https://files.viva64.com/etc/pubkey.txt 
      | sudo apt-key add -
    sudo wget -O /etc/apt/sources.list.d/viva64.list 
      https://files.viva64.com/etc/viva64.list  
    
    sudo apt-get update -qq
    sudo apt-get install -qq pvs-studio 
                             libio-socket-ssl-perl 
                             libnet-ssleay-perl
  fi
    
  download_extract 
    "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" 
    cmake-3.6.2-Linux-x86_64.tar.gz
}
travis_script() {
  if [ -d cmake-3.6.2-Linux-x86_64 ]; then
    export PATH=$(pwd)/cmake-3.6.2-Linux-x86_64/bin:$PATH
  fi
  
  CMAKE_ARGS="-DHEADLESS=ON ${CMAKE_ARGS}"
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    CMAKE_ARGS="-DCMAKE_EXPORT_COMPILE_COMMANDS=On ${CMAKE_ARGS}"
  fi
  cmake $CMAKE_ARGS CMakeLists.txt
  make
}
travis_after_success() {
  if [ "$PVS_ANALYZE" = "Yes" ]; then
    pvs-studio-analyzer credentials $PVS_USERNAME $PVS_KEY -o PVS-Studio.lic
    pvs-studio-analyzer analyze -j2 -l PVS-Studio.lic 
                                    -o PVS-Studio-${CC}.log 
                                    --disableLicenseExpirationCheck
    
    plog-converter -t html PVS-Studio-${CC}.log -o PVS-Studio-${CC}.html
    sendemail -t [email protected] 
              -u "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -m "PVS-Studio $CC report, commit:$TRAVIS_COMMIT" 
              -s smtp.gmail.com:587 
              -xu $MAIL_USER 
              -xp $MAIL_PASSWORD 
              -o tls=yes 
              -f $MAIL_USER 
              -a PVS-Studio-${CC}.log PVS-Studio-${CC}.html
  fi
}
set -e
set -x

$1;

حان الوقت الآن لدفع التغييرات إلى مستودع git، وبعد ذلك سيقوم Travis CI بتشغيل الإنشاء تلقائيًا. انقر على "ppsspp" للانتقال إلى تقارير البناء:

كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال
سنرى نظرة عامة على البناء الحالي:

كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال
إذا اكتمل البناء بنجاح، فسنتلقى بريدًا إلكترونيًا يتضمن نتائج التحليل الثابت. وبطبيعة الحال، فإن البريد ليس هو الطريقة الوحيدة لتلقي التقرير. يمكنك اختيار أي طريقة تنفيذ. ولكن من المهم أن تتذكر أنه بعد اكتمال الإنشاء، لن يكون من الممكن الوصول إلى ملفات الجهاز الظاهري.

ملخص الخطأ

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

التحسين الخطير

void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
  sha1_context ctx;

  sha1_starts( &ctx );
  sha1_update( &ctx, input, ilen );
  sha1_finish( &ctx, output );

  memset( &ctx, 0, sizeof( sha1_context ) );
}

تحذير PVS-Studio: V597 يمكن للمترجم حذف استدعاء الدالة "memset"، والذي يستخدم لمسح المخزن المؤقت "sum". يجب استخدام الدالة RtlSecureZeroMemory() لمسح البيانات الخاصة. sha1.cpp 325

يوجد هذا الجزء من التعليمات البرمجية في وحدة التجزئة الآمنة، ومع ذلك، فهو يحتوي على ثغرة أمنية خطيرة (سي دبليو إي-14). دعونا نلقي نظرة على قائمة التجميع التي تم إنشاؤها عند تجميع إصدار Debug:

; Line 355
  mov r8d, 20
  xor edx, edx
  lea rcx, QWORD PTR sum$[rsp]
  call memset
; Line 356

كل شيء في محله والوظيفة memeset يتم تنفيذه، وبالتالي الكتابة فوق البيانات الهامة في ذاكرة الوصول العشوائي، ومع ذلك، لا نفرح حتى الآن. دعونا نلقي نظرة على قائمة التجميع لإصدار الإصدار مع التحسين:

; 354  :
; 355  :  memset( sum, 0, sizeof( sum ) );
; 356  :}

كما يتبين من القائمة، تجاهل المترجم المكالمة memeset. هذا يرجع إلى حقيقة أنه في الوظيفة sha1 بعد المكالمة memeset لا مزيد من الإشارة إلى الهيكل CTX. لذلك، لا يرى المترجم أي فائدة في إضاعة وقت المعالج في الكتابة فوق الذاكرة التي لا يتم استخدامها في المستقبل. يمكنك إصلاح ذلك باستخدام الوظيفة RtlSecureZeroMemory أو مماثلة لها.

تصحيح:

void sha1( unsigned char *input, int ilen, unsigned char output[20] )
{
  sha1_context ctx;

  sha1_starts( &ctx );
  sha1_update( &ctx, input, ilen );
  sha1_finish( &ctx, output );

  RtlSecureZeroMemory(&ctx, sizeof( sha1_context ) );
} 

مقارنة لا لزوم لها

static u32 sceAudioOutputPannedBlocking
             (u32 chan, int leftvol, int rightvol, u32 samplePtr) {
  int result = 0;
  // For some reason, this is the only one that checks for negative.
  if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
    ....
  } else {
    if (leftvol >= 0) {
      chans[chan].leftVolume = leftvol;
    }
    if (rightvol >= 0) {
      chans[chan].rightVolume = rightvol;
    }
    chans[chan].sampleAddress = samplePtr;
    result = __AudioEnqueue(chans[chan], chan, true);
  }
}

تحذير PVS-Studio: V547 التعبير 'leftvol >= 0' يكون صحيحًا دائمًا. sceAudio.cpp 120

انتبه إلى الفرع الآخر لأول مرة if. سيتم تنفيذ التعليمات البرمجية فقط في حالة استيفاء كافة الشروط اليسار> 0xFFFF || رايتفول > 0xFFFF || اليسار < 0 || اليمين <0 سوف يتبين أنها كاذبة. وبالتالي نحصل على العبارات التالية، والتي ستكون صحيحة بالنسبة للفرع else: leftvol <= 0xFFFF, Rightvol <= 0xFFFF, الحجم الأيسر >=0 и اليمين> = 0. لاحظ العبارتين الأخيرتين. هل يعقل التحقق من الشرط الضروري لتنفيذ هذا الجزء من التعليمات البرمجية؟

حتى نتمكن من إزالة هذه العبارات الشرطية بأمان:

static u32 sceAudioOutputPannedBlocking
(u32 chan, int leftvol, int rightvol, u32 samplePtr) {
  int result = 0;
  // For some reason, this is the only one that checks for negative.
  if (leftvol > 0xFFFF || rightvol > 0xFFFF || leftvol < 0 || rightvol < 0) {
    ....
  } else {
    chans[chan].leftVolume = leftvol;
    chans[chan].rightVolume = rightvol;

    chans[chan].sampleAddress = samplePtr;
    result = __AudioEnqueue(chans[chan], chan, true);
  }
}

سيناريو آخر. هناك نوع من الخطأ المخفي وراء هذه الشروط الزائدة عن الحاجة. ربما لم يتحققوا مما هو مطلوب.

Ctrl+C Ctrl+V يعيد الضربات

static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
  if (!Memory::IsValidAddress(psmfData) ||
      !Memory::IsValidAddress(psmfData)) {
    return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
  }
  ....
}

V501 توجد تعبيرات فرعية متطابقة '!Memory::IsValidAddress(psmfData)' على يسار ويمين '||' المشغل أو العامل. scePsmf.cpp 703

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

الخيار الصحيح:

static u32 scePsmfSetPsmf(u32 psmfStruct, u32 psmfData) {
  if (!Memory::IsValidAddress(psmfStruct) ||
      !Memory::IsValidAddress(psmfData)) {
    return hleReportError(ME, SCE_KERNEL_ERROR_ILLEGAL_ADDRESS, "bad address");
  }
  ....
}

المتغير المنسي

extern void ud_translate_att(
  int size = 0;
  ....
  if (size == 8) {
    ud_asmprintf(u, "b");
  } else if (size == 16) {
    ud_asmprintf(u, "w");
  } else if (size == 64) {
    ud_asmprintf(u, "q");
  }
  ....
}

تحذير PVS-Studio: V547 التعبير 'الحجم == 8' خطأ دائمًا. مزامنة.ج 195

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

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

على ما يبدو، نسي مؤلف جزء التعليمات البرمجية الكتابة فوق المتغير الأحجام قبل ذلك.

قلة النوم

هذا هو المكان الذي سننتهي فيه على الأرجح بالأخطاء. الغرض من هذه المقالة هو عرض عمل PVS-Studio مع Travis CI، وليس تحليل المشروع بأكبر قدر ممكن من الدقة. إذا كنت تريد أخطاء أكبر وأجمل، فيمكنك دائمًا الإعجاب بها هنا :).

اختتام

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

وصلات مفيدة

كيفية إعداد PVS-Studio في Travis CI باستخدام محاكي PSP كمثال

إذا كنت ترغب في مشاركة هذه المقالة مع جمهور يتحدث الإنجليزية ، فيرجى استخدام رابط الترجمة: Maxim Zvyagintsev. كيفية إعداد PVS-Studio في Travis CI باستخدام مثال محاكي وحدة تحكم ألعاب PSP.

المصدر: www.habr.com

إضافة تعليق