يوجد PVS-Studio الآن في Chocolatey: فحص الشوكولاتة من Azure DevOps

الشكل 4

نواصل جعل استخدام PVS-Studio أكثر ملاءمة. محللنا متاح الآن في Chocolatey ، مدير الحزم لـ Windows. نحن نعتقد أن هذا سوف يسهل نشر PVS-Studio ، على وجه الخصوص ، في الخدمات السحابية. لكي لا تذهب بعيدًا ، تحقق من شفرة المصدر للشوكولاتة نفسها. سيكون نظام CI هو Azure DevOps.

فيما يلي قائمة بمقالاتنا الأخرى حول التكامل السحابي:


أنصحك بالاهتمام بالمقالة الأولى حول التكامل مع Azure DevOps ، لأنه في هذه الحالة يتم حذف بعض النقاط حتى لا يتم تكرارها.

إذن ، أبطال هذه المقالة:

PVS-Studio هي أداة ثابتة لتحليل الكود مصممة للكشف عن الأخطاء ونقاط الضعف المحتملة في البرامج المكتوبة بلغات C و C ++ و C # و Java. يعمل على أنظمة 64 بت على أنظمة التشغيل Windows و Linux و macOS ، ويمكنه تحليل التعليمات البرمجية المصممة لمنصات ARM 32 بت و 64 بت والمدمجة. إذا كانت هذه هي المرة الأولى التي تحاول فيها تحليل الشفرة الثابتة للتحقق من مشروعاتك ، فإننا نوصي بقراءة المقال حول كيفية مشاهدة تحذيرات PVS-Studio الأكثر إثارة للاهتمام وتقييم إمكانات هذه الأداة.

Azure DevOps- مجموعة من الخدمات السحابية ، تغطي بشكل مشترك عملية التطوير بأكملها. تتضمن المنصة أدوات مثل Azure Pipelines و Azure Boards و Azure Artifacts و Azure Repos و Azure Test Plans ، والتي تسرع عملية إنشاء البرامج وتحسين جودتها.

Chocolatey هو مدير حزم مفتوح المصدر لنظام Windows. الهدف من المشروع هو أتمتة دورة حياة البرنامج بالكامل من التثبيت إلى التحديث وإلغاء التثبيت على أنظمة تشغيل Windows.

حول استخدام الشوكولاتة


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

الأمر لتثبيت أحدث إصدار محلل:

choco install pvs-studio

الأمر لتثبيت نسخة محددة من حزمة PVS-Studio:

choco install pvs-studio --version=7.05.35617.2075

بشكل افتراضي ، يتم تثبيت قلب المحلل فقط - المكون الأساسي. يمكن تمرير جميع الأعلام الأخرى (مستقل ، JavaCore ، IDEA ، MSVS2010 ، MSVS2012 ، MSVS2013 ، MSVS2015 ، MSVS2017 ، MSVS2019) باستخدام - معلمات الحزمة.

مثال على الأمر الذي سيقوم بتثبيت المحلل مع مكون إضافي لبرنامج Visual Studio 2019:

choco install pvs-studio --package-parameters="'/MSVS2019'"

الآن دعونا نلقي نظرة على مثال للاستخدام الملائم للمحلل تحت Azure DevOps.

التخصيص


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

أولاً ، قم بتهيئة المشغل على المشغل ، مشيرًا إلى أننا نقوم فقط بإجراء التغييرات في الفرع الرئيسي :

trigger:
- master

بعد ذلك ، نحتاج إلى اختيار جهاز افتراضي. في الوقت الحالي ، سيكون وكيلًا مستضافًا من قبل Microsoft مع Windows Server 2019 و Visual Studio 2019:

pool:
  vmImage: 'windows-latest'

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

الشكل 2


هنا تحتاج إلى اختيار المكان الذي سنضيف فيه الامتداد ، وانقر فوق الزر تثبيت .

الشكل 5


بعد التثبيت بنجاح ، انقر فوق المتابعة إلى المؤسسة :

الشكل 9


يمكنك الآن رؤية النموذج الخاص بمهمة الشوكولاتة في نافذة المهام عند تحرير ملف التكوين azure-pipelines.yml:

الشكل 6


انقر فوق شوكولاتة وانظر قائمة الحقول:

الشكل 7


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

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

بعد ذلك ، دعنا ننتقل إلى الجزء الرئيسي من ملفنا:

- task: CmdLine@2
  inputs:
    script: 

نحتاج الآن إلى إنشاء ملف بترخيص المحلل. هنا PVSNAME و PVSKEY هي أسماء المتغيرات التي نحدد قيمها في الإعدادات. سيقومون بتخزين مفتاح تسجيل الدخول ورخصة PVS-Studio. لتعيين قيمها ، افتح قائمة المتغيرات-> متغير جديد . أنشئ متغيرات PVSNAME لتسجيل الدخول و PVSKEY لمفتاح المحلل. تذكر تحديد خانة الاختيار الاحتفاظ بهذا السر السري لـ PVSKEY . كود الفريق:

all "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" credentials 
–u $(PVSNAME) –n $(PVSKEY)

دعونا نبني المشروع باستخدام ملف الخفافيش الموجود في المستودع:

all build.bat

أنشئ مجلدًا حيث ستكمن الملفات مع نتائج عمل المحلل:

all mkdir PVSTestResults

قم بتشغيل تحليل المشروع:

all "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" 
–t .\src\chocolatey.sln –o .\PVSTestResults\Choco.plog 

نقوم بتحويل تقريرنا إلى تنسيق html باستخدام الأداة المساعدة Plogonverter:

all "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" 
–t html –o \PVSTestResults\ .\PVSTestResults\Choco.plog

تحتاج الآن إلى إنشاء مهمة حتى تتمكن من تحميل التقرير.

- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: PVSTestResults
    artifactName: PVSTestResults
    condition: always()

يبدو ملف التكوين الكامل كما يلي:

trigger:
- master

pool:
  vmImage: 'windows-latest'

steps:
- task: ChocolateyCommand@0
  inputs:
    command: 'install'
    installPackageId: 'pvs-studio'

- task: CmdLine@2
  inputs:
    script: |
      call "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" 
      credentials –u $(PVSNAME) –n $(PVSKEY)
      call build.bat
      call mkdir PVSTestResults
      call "C:\Program Files (x86)\PVS-Studio\PVS-Studio_Cmd.exe" 
      –t .\src\chocolatey.sln –o .\PVSTestResults\Choco.plog
      call "C:\Program Files (x86)\PVS-Studio\PlogConverter.exe" 
      –t html –o .\PVSTestResults\ .\PVSTestResults\Choco.plog

- task: PublishBuildArtifacts@1
  inputs:
    pathToPublish: PVSTestResults
    artifactName: PVSTestResults
    condition: always()

انقر حفظ-> حفظ-> تشغيل لبدء المهمة. قم بتحميل التقرير بالانتقال إلى علامة تبويب المهمة.

الرقم 8



يحتوي مشروع الشوكولاتة على إجمالي 37،615 سطرًا من كود C #. خذ بعين الاعتبار بعض الأخطاء الموجودة.

نتائج التحقق


تحذير

محلل N1 تحذير: V3005 تم تعيين متغير "الموفر" لنفسه. CrytpoHashProviderSpecs.cs 38

public abstract class CrytpoHashProviderSpecsBase : TinySpec
{
  ....
  protected CryptoHashProvider Provider;
  ....
  public override void Context()
  {
    Provider = Provider = new CryptoHashProvider(FileSystem.Object);
  }
}

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

تحذير

محلل N2 تحذير: V3093 [CWE-480] يقوم عامل التشغيل "&" بتقييم كلا المعاملين. ربما يجب استخدام عامل تشغيل "&&" للدائرة القصيرة بدلاً من ذلك. Platform.cs 64

public static PlatformType get_platform()
{
  switch (Environment.OSVersion.Platform)
  {
    case PlatformID.MacOSX:
    {
      ....
    }
    case PlatformID.Unix:
    if(file_system.directory_exists("/Applications")
      & file_system.directory_exists("/System")
      & file_system.directory_exists("/Users")
      & file_system.directory_exists("/Volumes"))
      {
        return PlatformType.Mac;
      }
        else
          return PlatformType.Linux;
    default:
      return PlatformType.Windows;
  }
}

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

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

if ((k < nct) & (s[k] != 0.0))

حتى إذا كان الفهرس k غير صحيح ، فسيتم استخدامه للوصول إلى عنصر الصفيف. نتيجة لذلك ، سيتم طرح IndexOutOfRangeException .

تحذيرات N3 ،

محلل N4 تحذير: V3022 [CWE-571] التعبير "shortPrompt" صحيح دائمًا.
تحذير محلل InteractivePrompt.cs 101 : V3022 [CWE-571] التعبير "shortPrompt" صحيح دائمًا. InteractivePrompt.cs 105

public static string 
prompt_for_confirmation(.... bool shortPrompt = false, ....)
{
  ....
  if (shortPrompt)
  {
    var choicePrompt = choice.is_equal_to(defaultChoice) //1
    ?
    shortPrompt //2
    ?
    "[[{0}]{1}]".format_with(choice.Substring(0, 1).ToUpperInvariant(), //3
    choice.Substring(1,choice.Length - 1))
    :
    "[{0}]".format_with(choice.ToUpperInvariant()) //0
    : 
    shortPrompt //4
    ? 
    "[{0}]{1}".format_with(choice.Substring(0,1).ToUpperInvariant(), //5
    choice.Substring(1,choice.Length - 1)) 
    :
    choice; //0
    ....
  }
  ....
}

في هذه الحالة ، هناك منطق غريب للعامل الثلاثي. دعونا نلقي نظرة فاحصة: إذا تم استيفاء الشرط المميز بالرقم 1 ، فإننا ننتقل إلى الشرط 2 ، والذي يكون دائمًا صحيحًا ، مما يعني أن السطر 3 مستوفٍ. إذا تبين أن الشرط 1 خطأ ، فإننا ننتقل إلى الخط المميز بالرقم 4 ، وهو الشرط الذي يتم فيه أيضًا صحيح دائمًا ، مما يعني أنه تم تنفيذ السطر 5. وبالتالي ، لن يتم استيفاء الشروط المحددة بالتعليق 0 مطلقًا ، وهو ما قد لا يكون منطق العمل الذي توقعه المبرمج.

تحذير

محلل N5 تحذير: V3123[CWE-783] لعل عامل التشغيل "؟:" يعمل بطريقة مختلفة عما كان متوقعًا. أولويتها أقل من أولوية المشغلين الآخرين في حالتها. خيارات. cs 1019

private static string GetArgumentName (...., string description)
{
  string[] nameStart;
  if (maxIndex == 1)
  {
    nameStart = new string[]{"{0:", "{"};
  }
  else
  {
    nameStart = new string[]{"{" + index + ":"};
  }
  for (int i = 0; i < nameStart.Length; ++i) 
  {
    int start, j = 0;
    do 
    {
      start = description.IndexOf (nameStart [i], j);
    } 
    while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false);
    ....
    return maxIndex == 1 ? "VALUE" : "VALUE" + (index + 1);
  }
}

عمل التشخيص على الخط:

while (start >= 0 && j != 0 ? description [j++ - 1] == '{' : false)

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

تحذير

محلل N6 تحذير: V3022 [CWE-571] التعبير ' installPackageVersions.Count ! = 1' صحيح دائمًا. نوجيت سيرفيس 1405

private void remove_nuget_cache_for_package(....)
{
  if (!config.AllVersions && installedPackageVersions.Count > 1)
  {
    const string allVersionsChoice = "All versions";
    if (installedPackageVersions.Count != 1)
    {
      choices.Add(allVersionsChoice);
    }
    ....
  }
  ....
}

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

تحذير

محلل N7 تحذير: V3001 هناك CommandArguments.contains متماثلة للتعبيرات الفرعية ("- apikey") 'إلى اليسار وإلى يمين' || ' المشغل أو العامل. ArgumentsUtility.cs 42

public static bool arguments_contain_sensitive_information(string
 commandArguments)
{
  return commandArguments.contains("-install-arguments-sensitive")
  || commandArguments.contains("-package-parameters-sensitive")
  || commandArguments.contains("apikey ")
  || commandArguments.contains("config ")
  || commandArguments.contains("push ")
  || commandArguments.contains("-p ")
  || commandArguments.contains("-p=")
  || commandArguments.contains("-password")
  || commandArguments.contains("-cp ")
  || commandArguments.contains("-cp=")
  || commandArguments.contains("-certpassword")
  || commandArguments.contains("-k ")
  || commandArguments.contains("-k=")
  || commandArguments.contains("-key ")
  || commandArguments.contains("-key=")
  || commandArguments.contains("-apikey")
  || commandArguments.contains("-api-key")
  || commandArguments.contains("-apikey")
  || commandArguments.contains("-api-key");
}

قام المبرمج الذي كتب هذا الجزء من الشفرة بنسخ آخر سطرين ونسي تحريرهما. وبسبب هذا ، فقد مستخدمو Chocolatey القدرة على تطبيق معلمة apikey بعدة طرق أخرى. على غرار المعلمات أعلاه ، يمكنني تقديم مثل هذه الخيارات:

commandArguments.contains("-apikey=");
commandArguments.contains("-api-key=");

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

ملاحظة ، وكالعادة ، يميل هذا الخطأ إلى الظهور في نهاية شرط متعدد الخطوط :). انظر المنشور " تأثير الخط الأخير ".

تحذير

محلل N8 تحذير: V3095 [CWE-476] تم استخدام كائن " installPackage " قبل التحقق من صحته. التحقق من الخطوط: 910 ، 917. NugetService.cs 910

public virtual ConcurrentDictionary<string, PackageResult> get_outdated(....)
{
  ....
  var pinnedPackageResult = outdatedPackages.GetOrAdd(
    packageName, 
    new PackageResult(installedPackage, 
                      _fileSystem.combine_paths(
                        ApplicationParameters.PackagesLocation, 
                        installedPackage.Id)));
  ....
  if (   installedPackage != null
      && !string.IsNullOrWhiteSpace(installedPackage.Version.SpecialVersion) 
      && !config.UpgradeCommand.ExcludePrerelease)
  {
    ....
  }
  ....
}

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

استنتاج


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

ندعوك لتنزيل وتجربة PVS-Studio. سيؤدي الاستخدام المنتظم لمحلل ثابت إلى تحسين جودة وموثوقية الشفرة التي طورها فريقك ويساعد على منع العديد من ثغرات يوم الصفر .

ملاحظة


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



إذا كنت تريد مشاركة هذه المقالة مع جمهور ناطق باللغة الإنجليزية ، فيرجى استخدام رابط الترجمة: فلاديسلاف ستولياروف. PVS-Studio الآن في شوكولاتي: فحص الشوكولاتة تحت Azure DevOps .

All Articles