أزور PowerShell: غير مؤذية في الغالب

صورة 6

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

عن المشروع


Azure PowerShell هي مجموعة من الأوامر ( cmdlet ) التي تمكنك من إدارة موارد Azure مباشرة من سطر الأوامر PowerShell . الغرض الرئيسي من هذه المجموعة هو تبسيط عملية الدراسة والبدء بسرعة في تطوير Azure. يوفر Azure PowerShell للمسؤولين والمطورين ميزات مقنعة لإنشاء تطبيقات Microsoft Azure ونشرها وإدارتها.

تم تطوير Azure PowerShell في بيئة .NET Standard ، ويدعمه PowerShell 5.1 لنظام التشغيل Windows و PowerShell 6.x والإصدارات الأحدث لكافة الأنظمة الأساسية. شفرة المصدر Azure PowerShell متاحة على جيثب.

لقد كنت مؤخرًا أحصل على مشروعات Microsoft للفحص. في رأيي ، فإن جودة هذه المشاريع عادة ما تكون من الدرجة الأولى. على الرغم من ، بالطبع ، ليس من دون استثناءات ، كما هو موضح في المقال " WinForms: أخطاء ، هولمز ". ولكن هذه المرة كل شيء على ما يرام. المشروع كبير: تحتوي ملفات شفرة المصدر 6845 .cs على حوالي 700000 سطر ، باستثناء الخطوط الفارغة (لم أكن آخذ في الاعتبار اختبارات وتحذيرات المستوى الثالث من اليقين). تم العثور على أخطاء قليلة جدًا لمثل هذا الكود من التعليمات البرمجية: لا يزيد عن مائة. كان هناك الكثير من الحالات المماثلة ، لذلك اخترت الأكثر إثارة للاهتمام لهذه المادة. كالعادة ، قمت بتصنيف الأخطاء حسب أرقام تحذيرات PVS-Studio.

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

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

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


V3001 هناك تعابير فرعية مماثلة 'strTimespan.Contains ("M")' إلى اليسار وإلى يمين '||' المشغل. AzureServiceBusCmdletBase.cs 187 (EventGrid)

public static TimeSpan ParseTimespan(string strTimespan) { .... if (strTimespan.Contains("P") || strTimespan.Contains("D") || strTimespan.Contains("T") || strTimespan.Contains("H") || strTimespan.Contains("M") || strTimespan.Contains("M")) .... } 

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

V3001 هناك تعبيرات فرعية متطابقة 'this.AggregationType! = Null' إلى اليسار وإلى يمين المشغل '&&'. GetAzureRmMetricCommand.cs 156 (شاشة)

 public AggregationType? AggregationType { get; set; } .... protected override void ProcessRecordInternal() { .... string aggregation = (this.AggregationType != null && this.AggregationType.HasValue) ? this.AggregationType.Value.ToString() : null; .... } 

ربما لا يوجد خطأ هنا. هذا مثال على الكود الزائد. في بعض الأحيان قد يشير هذا الرمز إلى عدم معرفة المطور. النقطة المهمة هي أن الاختبارات this.AggregationType! = خالية و this.AggregationType.HasValue متطابقة. يكفي استخدام واحد منهم فقط (أي واحد). أنا شخصياً أفضل الخيار مع HasValue:

 string aggregation = this.AggregationType.HasValue ? this.AggregationType.Value.ToString() : null; 

V3003 استخدام النموذج "if (A) {...} آخر إذا تم اكتشاف (A) {...}". هناك احتمال لوجود خطأ منطقي. خطوط التحقق: 152 ، 163. GetAzureRmRecoveryServicesBackupProtectionPolicy.cs 152 (RecoveryServices)

 public override void ExecuteCmdlet() { .... if( WorkloadType == Models.WorkloadType.AzureVM ) { .... } .... else if( WorkloadType == Models.WorkloadType.AzureFiles ) { if( BackupManagementType != Models.BackupManagementType.AzureStorage ) { throw new ArgumentException( Resources.AzureFileUnsupportedBackupManagementTypeException ); } serviceClientProviderType = ServiceClientHelpers. GetServiceClientProviderType( Models.WorkloadType.AzureFiles ); } else if( WorkloadType == Models.WorkloadType.AzureFiles ) { if( BackupManagementType != Models.BackupManagementType.AzureStorage ) { throw new ArgumentException( Resources.AzureFileUnsupportedBackupManagementTypeException ); } serviceClientProviderType = ServiceClientHelpers. GetServiceClientProviderType( Models.WorkloadType.AzureFiles ); } .... } 

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

V3005 يتم تعيين المتغير 'this.VM.OSProfile.WindowsConfiguration.ProvisionVMAgent' لنفسه. SetAzureVMOperatingSystemCommand.cs 298 (حساب)

 public override void ExecuteCmdlet() { .... // OS Profile this.VM.OSProfile.WindowsConfiguration.ProvisionVMAgent = this.VM.OSProfile.WindowsConfiguration.ProvisionVMAgent; .... } 

قيمة الخاصية مخصصة ذاتيا. ألقِ نظرة على إعلانها:

 [JsonProperty(PropertyName = "provisionVMAgent")] public bool? ProvisionVMAgent { get; set; } 

ينص وصف JsonProperty على ما يلي: "يرشد Newtonsoft.Json.JsonSerializer لإجراء تسلسل دائم للعضو بالاسم المحدد." يبدو أن كل شيء مذنب وقد حدث خطأ واضح. الاستخدام الصريح لهذا للوصول إلى الممتلكات هو أيضا مربكة للغاية. ربما ، لم يتم تحديد متغير آخر عن طريق الخطأ بدلاً من هذا. ولكن دعونا لا نقفز إلى الاستنتاجات. حقيقة الأمر هي أنني صادفت الكثير من مثل هذه المهام (خاصية مخصصة ذاتيا). فيما يلي مثال على مهمة ، تشبه إلى حد بعيد خطأ:

V3005 يتم تعيين متغير "this.LastHeartbeat" لنفسه. PSFabricDetails.cs 804 (خدمات الاسترداد)

 public ASRInMageAzureV2SpecificRPIDetails( InMageAzureV2ReplicationDetails details) { this.LastHeartbeat = this.LastHeartbeat; // <= this.RecoveryAvailabilitySetId = details.RecoveryAvailabilitySetId; this.AgentVersion = details.AgentVersion; this.DiscoveryType = details.DiscoveryType; .... } 

دعونا نلقي نظرة فاحصة على المهام الثانية واللاحقة. في الجزء الأيمن من التعبير ، تتم التفاصيل بدلاً من هذا. انظر الآن إلى الإعلان عن خاصية this.LastHeartbeat :
 public DateTime? LastHeartbeat { get; set; } 

أخيرًا ، لنجد الخاصية التي تحمل الاسم نفسه في فئة InMageAzureV2ReplicationDetails . تم إعلان هذه الممتلكات هناك:

 public class InMageAzureV2ReplicationDetails : ReplicationProviderSpecificSettings { .... [JsonProperty(PropertyName = "lastHeartbeat")] public DateTime? LastHeartbeat { get; set; } .... } 

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

  • V3005 يتم تعيين المتغير 'this.ResourceGroupName' لنفسه. RemoveAzureRmExpressRouteConnectionCommand.cs 84 (الخدمات المعرفية)
  • V3005 يتم تعيين متغير "this.ExpressRouteGatewayName" لنفسه. RemoveAzureRmExpressRouteConnectionCommand.cs 85 (الخدمات المعرفية)
  • V3005 يتم تعيين متغير "this.Name" لنفسه. RemoveAzureRmExpressRouteConnectionCommand.cs 86 (الخدمات المعرفية)

 [Cmdlet(VerbsCommon.Remove, ResourceManager.Common.AzureRMConstants.AzureRMPrefix + "ExpressRouteConnection", DefaultParameterSetName = CortexParameterSetNames.ByExpressRouteConnectionName, SupportsShouldProcess = true), OutputType(typeof(bool))] public class RemoveExpressRouteConnectionCommand : ExpressRouteConnectionBaseCmdlet { [Parameter( Mandatory = true, ParameterSetName = CortexParameterSetNames.ByExpressRouteConnectionName, HelpMessage = "The resource group name.")] [ResourceGroupCompleter] [ValidateNotNullOrEmpty] public string ResourceGroupName { get; set; } .... public override void Execute() { if (....) { this.ResourceGroupName = this.ResourceGroupName; this.ExpressRouteGatewayName = this.ExpressRouteGatewayName; this.Name = this.Name; } .... } .... } 

تحتوي طريقة التنفيذ على تعيينات ذاتية لثلاث خصائص في صف واحد. فقط في الحالة ، استشهدت بالإعلان الكامل للفئة RemoveExpressRouteConnectionCommand وجميع سماته ، وكذلك إعلان خاصية ResourceGroupName (يتم الإعلان عن خاصيتين أخريين بطريقة مماثلة). كانت هذه التحذيرات هي التي دفعتني إلى التفكير في السؤال: "هل هذا خطأ؟" أظن أن بعض السحر الداخلي لتطوير PowerShell قد يحدث هنا. آمل أن يكون هناك خبراء على دراية بهذه القضية بين القراء. لست مستعدًا لاستخلاص أي استنتاجات في هذه الحالة.

V3006 تم تكوين العنصر ولكن لا يتم استخدامه. الكلمة المفتاحية "رمي" قد تكون مفقودة: رمي ArgumentException (FOO) جديد. StartAzureRmRecoveryServicesAsrTestFailoverJob.cs 259 (خدمات الاسترداد)

 private void StartRPITestFailover() { .... if (....) { .... } else { new ArgumentException( Resources .UnsupportedDirectionForTFO); // Throw Unsupported Direction // Exception } .... } 

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

  • V3006 تم تكوين العنصر ولكن لا يتم استخدامه. الكلمة المفتاحية "رمي" قد تكون مفقودة: رمي ArgumentException (FOO) جديد. StartAzureRmRecoveryServicesAsrTestFailoverJob.cs 305 (خدمات الاسترداد)
  • V3006 تم تكوين العنصر ولكن لا يتم استخدامه. الكلمة المفتاحية "رمي" قد تكون مفقودة: رمي ArgumentException (FOO) جديد. StartAzureRmRecoveryServicesAsrUnPlannedFailover.cs 278 (خدمات الاسترداد)
  • V3006 تم تكوين العنصر ولكن لا يتم استخدامه. الكلمة المفتاحية "رمي" قد تكون مفقودة: رمي ArgumentException (FOO) جديد. StartAzureRmRecoveryServicesAsrUnPlannedFailover.cs 322 (خدمات الاسترداد)
  • V3006 تم تكوين العنصر ولكن لا يتم استخدامه. الكلمة المفتاحية "رمي" قد تكون مفقودة: رمي ArgumentException (FOO) جديد. UpdateAzureRmRecoveryServicesAsrProtectionDirection.cs 421 (خدمات الاسترداد)
  • V3006 تم تكوين العنصر ولكن لا يتم استخدامه. الكلمة المفتاحية "رمي" قد تكون مفقودة: رمي ArgumentException (FOO) جديد. UpdateAzureRmRecoveryServicesAsrProtectionDirection.cs 452 (خدمات الاسترداد)

تعبير V3022 "apiType.HasValue" غير صحيح دائمًا. ApiManagementClient.cs 1134 (ApiManagement)

 private string GetApiTypeForImport(...., PsApiManagementApiType? apiType) { .... if (apiType.HasValue) { switch(apiType.Value) { case PsApiManagementApiType.Http: return SoapApiType.SoapToRest; case PsApiManagementApiType.Soap: return SoapApiType.SoapPassThrough; default: return SoapApiType.SoapPassThrough; } } return apiType.HasValue ? // <= apiType.Value.ToString("g") : PsApiManagementApiType.Http.ToString("g"); } 

لقد تم كسر منطق العمل. إذا كان apiType يحتوي على قيمة ، فلن يصل عنصر التحكم إلى تعبير الإرجاع في نهاية الطريقة (تحتوي جميع فروع التبديل على إرجاع ). وإلا ، فستُرجع الطريقة دائمًا PsApiManagementApiType.Http.ToString ("g") ، بينما لن يتم إرجاع قيمة apiType.Value.ToString ("g") أبدًا.

V3022 Expression 'automationJob! = Null && automationJob == null' غير صحيح دائمًا. NodeConfigurationDeployment.cs 199 (التنفيذ التلقائي)

 public NodeConfigurationDeployment( ...., Management.Automation.Models.Job automationJob = null, ....) { .... if (automationJob != null && automationJob == null) return; .... } 

رمز مكافحة بديهية. اثنين من الشيكات التي تتناقض مع بعضها البعض. ربما يحتوي الاختيار الثاني لـ null على المتغير الخاطئ.

تعبير V3022 غير صحيح دائمًا. DataFactoryClient.Encrypt.cs 37 (DataFactory)

 public virtual string OnPremisesEncryptString(....) { .... if ( linkedServiceType == LinkedServiceType.OnPremisesSqlLinkedService && linkedServiceType == LinkedServiceType.OnPremisesOracleLinkedService && linkedServiceType == LinkedServiceType.OnPremisesFileSystemLinkedService && (value == null || value.Length == 0)) { throw new ArgumentNullException("value"); } .... } 

التحقق لا طائل منه ولن يتم طرح الاستثناء. الشرط يتطلب مساواة المتغير linkServiceType المتزامن مع ثلاث قيم مختلفة. المشغلون && و || من المرجح أن يكون الخلط. كود ثابت:

 if (( linkedServiceType == LinkedServiceType.OnPremisesSqlLinkedService || linkedServiceType == LinkedServiceType.OnPremisesOracleLinkedService || linkedServiceType == LinkedServiceType.OnPremisesFileSystemLinkedService) && (value == null || value.Length == 0)) .... 

تعبير V3022 'Ekus == null' غير صحيح دائمًا. PSKeyVaultCertificatePolicy.cs 129 (KeyVault)

 internal CertificatePolicy ToCertificatePolicy() { .... if (Ekus != null) { x509CertificateProperties.Ekus = Ekus == null ? null : new List<string>(Ekus); } .... } 

تحقق زائدة من متغير Ekus لإلغاء فارغة . ربما يكون ذلك جيدًا ، لكن الرمز لا يبدو لطيفًا.

V3023 النظر في فحص هذا التعبير. التعبير مفرط أو يحتوي على خطأ مطبعي. PolicyRetentionObjects.cs 207 (خدمات الاسترداد)

 public virtual void Validate() { if (RetentionTimes == null || RetentionTimes.Count == 0 || RetentionTimes.Count != 1) { throw new ArgumentException( Resources.InvalidRetentionTimesInPolicyException); } } 

إليك فحصًا مفرطًا أو حالة مفرطة. الاختيار RetentionTimes.Count == 0 لا معنى له ، كما هو الحال بعد ذلك ، يتم التحقق من RetentionTimes.Count! = 1 .

V3025 تنسيق غير صحيح. من المتوقع وجود عدد مختلف من عناصر التنسيق أثناء استدعاء وظيفة "التنسيق". الوسيطات غير المستخدمة: this.ResourceGroupName. NewScheduledQueryRuleCommand.cs 117 (شاشة)

 protected override void ProcessRecordInternal() { .... if (this.ShouldProcess(this.Name, string.Format("Creating Log Alert Rule '{0}' in resource group {0}", this.Name, this.ResourceGroupName))) { .... } .... } 

خطأ في خط التنسيق. يتم استخدام المحدد {0} مرتين ، ويتم تمرير طريقة التنسيق على وسيطين. هنا هو الإصدار الصحيح:

 if (this.ShouldProcess(this.Name, string.Format("Creating Log Alert Rule '{0}' in resource group {1}", this.Name, this.ResourceGroupName))) .... 

خطأ مشابه آخر:

  • V3025 تنسيق غير صحيح. من المتوقع وجود عدد مختلف من عناصر التنسيق أثناء استدعاء وظيفة "التنسيق". الوسيطات غير المستخدمة: this.ResourceGroupName. RemoveScheduledQueryRuleCommand.cs 88 (الشاشة)

V3042 ممكن NullReferenceException. "؟" و "." تستخدم عوامل التشغيل للوصول إلى أعضاء كائن "imageAndOsType" VirtualMachineScaleSetStrategy.cs 81 (حساب)

 internal static ResourceConfig<VirtualMachineScaleSet> CreateVirtualMachineScaleSetConfig(...., ImageAndOsType imageAndOsType, ....) { .... VirtualMachineProfile = new VirtualMachineScaleSetVMProfile { OsProfile = new VirtualMachineScaleSetOSProfile { ...., WindowsConfiguration = imageAndOsType.CreateWindowsConfiguration(), // <= ...., }, StorageProfile = new VirtualMachineScaleSetStorageProfile { ImageReference = imageAndOsType?.Image, // <= DataDisks = DataDiskStrategy.CreateVmssDataDisks( imageAndOsType?.DataDiskLuns, dataDisks) // <= }, }, .... } 

عند إنشاء كائن VirtualMachineScaleSetVMProfile ، يتم التحقق من متغير imageAndOsType لإلغاء فراغه دون أي فحص أولي. ومع ذلك ، عند إنشاء VirtualMachineScaleSetStorageProfile ، يتم التحقق من هذا المتغير بالفعل باستخدام عامل الوصول المشروط مرتين. الرمز لا يبدو آمنا.

V3042 ممكن NullReferenceException. "؟" و "." تستخدم عوامل التشغيل للوصول إلى أعضاء كائن "ContContacts "الموجود RemoveAzureKeyVaultCertificateContact.cs 123 (KeyVault)

 public override void ExecuteCmdlet() { .... List<PSKeyVaultCertificateContact> existingContacts; try { existingContacts = this.DataServiceClient. GetCertificateContacts(VaultName)?.ToList(); } catch (KeyVaultErrorException exception) { .... existingContacts = null; } foreach (var email in EmailAddress) { existingContacts.RemoveAll(....); // <= } .... } 

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

V3066 ترتيب غير صحيح محتمل للوسائط تم تمريره إلى طريقة "PersistSyncServerRegistration": 'storageSyncServiceUid' و 'discoveryUri'. EcsManagementInteropClient.cs 364 (StorageSync)

 public class EcsManagementInteropClient : IEcsManagement { .... public int PersistSyncServerRegistration(....) { return m_managementObject.PersistSyncServerRegistration( serviceUri, subscriptionId, storageSyncServiceName, resourceGroupName, clusterId, clusterName, storageSyncServiceUid, // <= discoveryUri, // <= serviceLocation, resourceLocation); } .... } 

يشتبه المحلل في أن ترتيب الوسيطات الخاصة بأسلوب PersistSyncServerRegistration مشوش. إعلان الطريقة:

 public interface IEcsManagement : IDisposable { .... int PersistSyncServerRegistration( [In, MarshalAs(UnmanagedType.BStr)] string serviceUri, [In, MarshalAs(UnmanagedType.BStr)] string subscriptionId, [In, MarshalAs(UnmanagedType.BStr)] string storageSyncServiceName, [In, MarshalAs(UnmanagedType.BStr)] string resourceGroupName, [In, MarshalAs(UnmanagedType.BStr)] string clusterId, [In, MarshalAs(UnmanagedType.BStr)] string clusterName, [In, MarshalAs(UnmanagedType.BStr)] string discoveryUri, // <= [In, MarshalAs(UnmanagedType.BStr)] string storageSyncServiceUid, // <= [In, MarshalAs(UnmanagedType.BStr)] string serviceLocation, [In, MarshalAs(UnmanagedType.BStr)] string resourceLocation); .... } 

في الواقع ، هناك خطأ ما في الحجج رقم سبعة وثمانية. يتعين على المؤلف التحقق من الرمز.

V3077 لا يستخدم محدد خاصية "GetGuid" معلمة "القيمة" الخاصة به. RecoveryServicesBackupCmdletBase.cs 54 (RecoveryServices)

 public abstract class RecoveryServicesBackupCmdletBase : AzureRMCmdlet { .... static string _guid; protected static string GetGuid { get { return _guid; } set { _guid = Guid.NewGuid().ToString(); } } .... } 

لا يستخدم setter المعلمة التي تم تمريرها. بدلاً من ذلك ، يقوم بإنشاء GUID جديد ويقوم بتعيينه إلى الحقل _guid . أعتقد أن معظم القراء سيوافقون على أن هذا الرمز يبدو قبيحًا على الأقل. هذا البناء ليس ملائمًا جدًا للاستخدام: عندما (تتم إعادة) تهيئة خاصية GetGuid ، يتعين على المرء تعيين قيمة وهمية لها ، وهو أمر غير واضح جدًا. لكن الأهم من ذلك كله أنني كنت مستمتعًا بالطريقة التي استخدم بها المؤلفون هذا النمط. هناك مكان واحد فقط ، حيث يتم التعامل مع GetGuid . التحقق من ذلك:

 public override void ExecuteCmdlet() { .... var itemResponse = ServiceClientAdapter.CreateOrUpdateProtectionIntent( GetGuid ?? Guid.NewGuid().ToString(), ....); .... } 

! الرائعة

V3091 التحليل التجريبي. من الممكن وجود خطأ مطبعي داخل السلسلة الحرفية: "معرف مجموعة الإدارة". كلمة "معرف" مشبوهة. الثوابت. 36 (الموارد)

 public class HelpMessages { public const string SubscriptionId = "Subscription Id of the subscription associated with the management"; public const string GroupId = "Management Group Id"; // <= public const string Recurse = "Recursively list the children of the management group"; public const string ParentId = "Parent Id of the management group"; public const string GroupName = "Management Group Id"; // <= public const string DisplayName = "Display Name of the management group"; public const string Expand = "Expand the output to list the children of the management group"; public const string Force = "Force the action and skip confirmations"; public const string InputObject = "Input Object from the Get call"; public const string ParentObject = "Parent Object"; } 

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

خطأ مشابه آخر:

  • V3091 التحليل التجريبي. من الممكن وجود خطأ مطبعي داخل السلسلة الحرفية. كلمة "الاسم" مشبوهة. ParamHelpMsgs.cs 153 (خدمات الاسترداد)

V3093 The '|' المشغل بتقييم كل المعاملات. ربما ماس كهربائى "| يجب استخدام المشغل بدلاً من ذلك. PSKeyVaultCertificatePolicy.cs 114 (KeyVault)

 internal CertificatePolicy ToCertificatePolicy() { .... if (!string.IsNullOrWhiteSpace(SubjectName) || DnsNames != null || Ekus != null || KeyUsage != null | // <= ValidityInMonths.HasValue) { .... } .... } 

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

V3095 تم استخدام عنصر "الشهادة" قبل أن يتم التحقق منه ضد قيمة خالية. خطوط التحقق: 41 ، 43. شهادةInfo.cs 41 (أتمتة)

 public CertificateInfo( ...., Azure.Management.Automation.Models.Certificate certificate) { .... this.Name = certificate.Name; if (certificate == null) return; .... } 

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

V3095 تم استخدام العنصر 'clusterCred' قبل أن يتم التحقق منه ضد قيمة خالية. خطوط التحقق: 115 ، 118. InvokeHiveCommand.cs 115 (HDInsight)

 public override void ExecuteCmdlet() { .... _credential = new BasicAuthenticationCloudCredentials { Username = clusterCred.UserName, Password = clusterCred.Password.ConvertToString() }; if (clusterConnection == null || clusterCred == null) .... } 

إليك بعض الأخطاء المتشابهة:

  • V3095 تم استخدام العنصر '_profile' قبل أن يتم التحقق منه مقابل خالية. خطوط التحقق: 47 ، 49. RMProfileClient.cs 47 (الحسابات)
  • V3095 تم استخدام العنصر 'this.LoadBalancer.BackendAddressPools' قبل أن يتم التحقق منه ضد القيمة الخالية. خطوط التحقق: 56 ، 63. AddAzureRmLoadBalancerBackendAddressPoolConfigCommand.cs 56 (CognitiveServices)
  • بشكل عام ، رأيت العديد من أخطاء V3095 في رمز Azure PowerShell. لكن جميعهم متشابهون تمامًا ، لذلك لن أتناول هذه المسألة.

V3125 تم استخدام كائن "startTime" بعد أن تم التحقق منه مقابل لاغٍ. خطوط التحقق: 1752 ، 1738. AutomationPSClientDSC.cs 1752 (التنفيذ التلقائي)

 private string GetNodeReportListFilterString( ...., DateTimeOffset? startTime, ...., DateTimeOffset? lastModifiedTime) { .... if (startTime.HasValue) { odataFilter.Add("properties/startTime ge " + this.FormatDateTime(startTime.Value)); // <= } .... if (lastModifiedTime.HasValue) { odataFilter.Add("properties/lastModifiedTime ge " + this.FormatDateTime(startTime.Value)); // <= } .... } 

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

V3125 تم استخدام العنصر ' firstPage ' بعد أن تم التحقق منه ضد قيمة خالية. خطوط التحقق: 113 ، 108. IntegrationAccountAgreementOperations.cs 113 (LogicApp)

 public IList<IntegrationAccountAgreement> ListIntegrationAccountAgreements(....) { var compositeList = new List<IntegrationAccountAgreement>(); var firstPage = this.LogicManagementClient. IntegrationAccountAgreements.List(....); if (firstPage != null) { compositeList.AddRange(firstPage); } if (!string.IsNullOrEmpty(firstPage.NextPageLink)) // <= { .... } .... } 

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

لقد وجدت أكثر من تحذيرات V3125 في رمز Azure PowerShell أكثر من التحذيرات الموضحة أعلاه. كل منهم أيضا من نفس النوع. أعتقد أن اثنين منهم اعتبرناه كافيين.

V3137 يتم تعيين متغير "apiVersionSetId" ولكن لا يتم استخدامه بحلول نهاية الوظيفة. GetAzureApiManagementApiVersionSet.cs 69 (ApiManagement)

 public String ApiVersionSetId { get; set; } .... public override void ExecuteApiManagementCmdlet() { .... string apiVersionSetId; if (ParameterSetName.Equals(ContextParameterSet)) { .... apiVersionSetId = ApiVersionSetId; } else { apiVersionSetId = ....; } if (string.IsNullOrEmpty(ApiVersionSetId)) // <= { WriteObject(....); } else { WriteObject(Client.GetApiVersionSet(...., ApiVersionSetId)) // <= } } 

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

V3137 يتم تعيين متغير "cacheId" ولكن لا يتم استخدامه بحلول نهاية الوظيفة. RemoveAzureApiManagementCache.cs 94 (ApiManagement)

 public String CacheId { get; set; } .... public override void ExecuteApiManagementCmdlet() { .... string cacheId; if (....) { .... cacheId = InputObject.CacheId; } else if (....) { .... cacheId = cache.CacheId; } else { .... cacheId = CacheId; } var actionDescription = string.Format(...., CacheId); // <= var actionWarning = string.Format(...., CacheId); // <= .... Client.CacheRemove(resourceGroupName, serviceName, CacheId); // <= .... } 

هذه هي الحالة نفسها تقريباً كما هو موضح سابقًا. لا يتم استخدام المتغير المحلي cacheId بعد التهيئة بأي طريقة. بدلاً من ذلك ، يتم استخدام خاصية أخرى باسم CacheId مشابه جدًا. لا أعرف بالتأكيد ، ربما يكون هذا مجرد نمط برمجة لمطوري Azure PowerShell. على أي حال ، يبدو وكأنه خطأ.

V3143 تتم إعادة كتابة المعلمة "value" داخل محدد خاصية ، ولا يتم استخدامها بعد ذلك. NewAzureIntegrationAccountPartnerCommand.cs 67 (LogicApp)

 [Parameter(Mandatory = false, HelpMessage = "The integration account partner type.", ValueFromPipelineByPropertyName = false)] [ValidateSet("B2B", IgnoreCase = false)] [ValidateNotNullOrEmpty] public string PartnerType { get { return this.partnerType; } set { value = this.partnerType; } // <= } 

يتم الإعلان عن الحقل partnerType بالطريقة التالية:

 /// <summary> /// Default partner type. /// </summary> private string partnerType = "B2B"; 

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

  • V3143 تتم إعادة كتابة المعلمة "value" داخل محدد خاصية ، ولا يتم استخدامها بعد ذلك. NewAzureIntegrationAccountSchemaCommand.cs 79 (LogicApp)
  • V3143 تتم إعادة كتابة المعلمة "value" داخل محدد خاصية ، ولا يتم استخدامها بعد ذلك. NewAzureIntegrationAccountSchemaCommand.cs 87 (LogicApp)
  • V3143 تتم إعادة كتابة المعلمة "value" داخل محدد خاصية ، ولا يتم استخدامها بعد ذلك. UpdateAzureIntegrationAccountPartnerCommand.cs 67 (LogicApp)
  • V3143 تتم إعادة كتابة المعلمة "value" داخل محدد خاصية ، ولا يتم استخدامها بعد ذلك. UpdateAzureIntegrationAccountSchemaCommand.cs 80 (LogicApp)
  • V3143 تتم إعادة كتابة المعلمة "value" داخل محدد خاصية ، ولا يتم استخدامها بعد ذلك. UpdateAzureIntegrationAccountSchemaCommand.cs 88 (LogicApp)

استنتاج


هذه كلها أخطاء مثيرة للاهتمام تم العثور عليها في رمز Azure PowerShell. نرحب المتحمسين وأولئك المهتمين بمراجعة الأخطاء في هذا المشروع (أو أي مشروع آخر). ربما أفتقد شيئًا غريبًا. للقيام بالمراجعة ، ما عليك سوى تنزيل وتثبيت PVS-Studio .

شكرا لك على القراءة حتى النهاية. وبطبيعة الحال ، رمز بوجليس للجميع!

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


All Articles