Azure PowerShell: «principalement inoffensif»

Image 6

Bonjour à tous. Aujourd'hui, nous avons un autre projet Microsoft à l'essai. Par le titre de l'article, vous pouvez deviner que cette fois les développeurs n'ont pas pu nous plaire avec un grand nombre d'erreurs. Nous espérons que les auteurs du projet ne seront pas offensés par ce nom. Après tout, un petit nombre d'erreurs est excellent, n'est-ce pas? Cependant, quelque chose d'intéressant a été trouvé dans le code Azure PowerShell. Nous vous suggérons de vous familiariser avec les fonctionnalités de ce projet et de regarder les erreurs trouvées avec l'analyseur PV # C PVS-Studio.

À propos du projet


Azure PowerShell est une applet de commande qui vous permet de gérer les ressources Azure directement à partir de la ligne de commande PowerShell . L'objectif principal de cet ensemble est de simplifier l'apprentissage et le démarrage rapide du développement pour Azure. Azure PowerShell fournit aux administrateurs et aux développeurs de puissantes fonctionnalités pour créer, déployer et gérer des applications Microsoft Azure.

Azure PowerShell est développé dans l'environnement .NET Standard et est pris en charge par PowerShell 5.1 pour Windows et PowerShell 6.x et versions ultérieures pour toutes les plateformes. Le code source Azure PowerShell est disponible sur GitHub.

Récemment, les projets Microsoft ont souvent attiré mon attention. À mon avis, la qualité de ces projets est généralement à son meilleur. Bien sûr, non sans exception, tout comme l'article " WinForms: Erreurs, Holmes ". Cependant, cette fois, tout est normal. Le projet est volumineux: 6845 fichiers .cs le code source contient environ 700 mille lignes, hors vide (tests, ainsi que des avertissements du troisième niveau de fiabilité, je n'ai pas pris en compte). Il y avait très peu d'erreurs pour un tel volume de code: pas plus d'une centaine. Il y a beaucoup de situations du même type, donc pour l'article, j'ai sélectionné les points positifs les plus intéressants. Les erreurs, comme je le fais habituellement, sont triées par les numéros de diagnostic PVS-Studio.

J'ai également rencontré des fragments de code qui ressemblent à des erreurs, mais je ne pouvais pas tirer de conclusion sans ambiguïté sur l'existence d'un problème réel, car je ne connaissais pas suffisamment les fonctionnalités de conception de PowerShell. J'espère que parmi les lecteurs il y aura des experts en la matière et m'aidera. À ce sujet ci-dessous.

Avant le début du «débriefing», je note la particularité du projet en termes de structure. Le code source Azure PowerShell comprend plus de soixante-dix solutions Visual Studio. Certaines solutions incluent des projets d'autres solutions. Une telle structure a un peu ralenti l'analyse (pas beaucoup). Le reste de la vérification n'a pas causé de difficultés. Pour plus de commodité, dans la ligne du message d'erreur (entre parenthèses), je vais indiquer le nom de la solution dans laquelle cette erreur a été détectée.

Résultats de validation


V3001 Il existe des sous-expressions identiques 'strTimespan.Contains ("M")' à gauche et à droite de '||' opérateur. 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")) .... } 

Un exemple d'une erreur assez évidente, que seul le développeur est capable de corriger. Dans ce cas, il est totalement incompréhensible que nous ayons affaire à une duplication de code qui n'affecte rien, ou au lieu de «M», quelque chose d'autre devrait apparaître dans l'un des deux derniers contrôles.

V3001 Il existe des sous-expressions identiques 'this.AggregationType! = Null' à gauche et à droite de l'opérateur '&&'. GetAzureRmMetricCommand.cs 156 (moniteur)

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

Il n'y a probablement pas d'erreur ici. Ceci est un exemple de code redondant. Parfois, un tel code peut indiquer un niveau insuffisant de connaissances des développeurs. Le fait est que this.AggregationType! = Null et this.AggregationType.HasValue sont identiques. Il suffit d'en utiliser un (n'importe lequel). Personnellement, je préfère l' option HasValue :

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

V3003 L'utilisation du modèle 'if (A) {...} else if (A) {...}' a été détectée. Il y a une probabilité de présence d'erreur logique. Vérifiez les lignes: 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 ); } .... } 

Les deux autres éléments si les blocs sont absolument identiques, y compris la condition et le corps du bloc. Ces erreurs sont généralement commises lors de l'utilisation de la méthode copier-coller dans le travail. La question est encore la criticité de cette erreur. S'il ne s'agit pas d'une simple duplication de code, alors nous pouvons parler du manque de vérification nécessaire et de l'ensemble d'actions correspondant. L'auteur doit modifier le code.

V3005 La variable 'this.VM.OSProfile.WindowsConfiguration.ProvisionVMAgent' est affectée à elle-même. SetAzureVMOperatingSystemCommand.cs 298 (Calcul)

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

La valeur de la propriété est assignée à elle-même. Jetez un œil à son annonce:

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

La description de JsonProperty indique «Demande au Newtonsoft.Json.JsonSerializer de toujours sérialiser le membre avec le nom spécifié». Il semble que tout soit simple et il y a une erreur évidente. Il est également déroutant de l'utiliser explicitement pour accéder à une propriété. Peut-être, par erreur, une autre variable n'a pas été spécifiée à la place de cela . Mais pour l'instant, nous ne tirerons pas de conclusions. Le fait est que dans le code Azure PowerShell, j'ai rencontré beaucoup de ces affectations (la propriété est assignée à elle-même). Voici un autre exemple d'affectation très similaire à une erreur:

V3005 La variable 'this.LastHeartbeat' est assignée à elle-même. PSFabricDetails.cs 804 (RecoveryServices)

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

Faites attention à la deuxième affectation et aux suivantes. Du côté droit de l'expression, ce n'est pas cela qui apparaît du tout, mais les détails . Jetez un œil à la déclaration de cette propriété. LastHeartbeat :

 public DateTime? LastHeartbeat { get; set; } 

Enfin, recherchez une propriété du même nom dans la classe InMageAzureV2ReplicationDetails . Une telle propriété y est déclarée:

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

Eh bien, dans ce cas, je suis prêt à admettre que ce déclenchement est une véritable erreur. Mais que faire des déclencheurs suivants? En eux, contrairement aux deux fragments de code précédents, il y a une affectation multiple de propriétés à eux-mêmes. C'est déjà moins comme une erreur:

  • V3005 La variable 'this.ResourceGroupName' est assignée à elle-même. RemoveAzureRmExpressRouteConnectionCommand.cs 84 (CognitiveServices)
  • V3005 La variable 'this.ExpressRouteGatewayName' est assignée à elle-même. RemoveAzureRmExpressRouteConnectionCommand.cs 85 (CognitiveServices)
  • V3005 La variable 'this.Name' est assignée à elle-même. RemoveAzureRmExpressRouteConnectionCommand.cs 86 (CognitiveServices)

 [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; } .... } .... } 

La méthode Execute contient trois affectations consécutives de propriétés à elles-mêmes. Au cas où, j'ai donné une déclaration complète de la classe RemoveExpressRouteConnectionCommand avec tous ses attributs, ainsi qu'une déclaration de la propriété ResourceGroupName (les deux autres propriétés sont déclarées de la même manière). C'est un tel déclenchement qui m'a fait réfléchir à la question: "Est-ce une erreur?" Je soupçonne qu'une sorte de magie interne du développement PowerShell peut se produire ici. J'espère que parmi les lecteurs, il y a des experts qui connaissent bien la question. Je ne suis pas prêt à tirer aucune conclusion dans ce cas.

V3006 L'objet a été créé mais il n'est pas utilisé. Le mot clé 'throw' peut être manquant: throw new ArgumentException (FOO). StartAzureRmRecoveryServicesAsrTestFailoverJob.cs 259 (RecoveryServices)

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

Le mot clé throw a été ignoré. De plus, le commentaire dit que l'exception devrait simplement être levée. Dans la solution RecoveryServices , j'ai rencontré plusieurs erreurs similaires:

  • V3006 L'objet a été créé mais il n'est pas utilisé. Le mot clé 'throw' peut être manquant: throw new ArgumentException (FOO). StartAzureRmRecoveryServicesAsrTestFailoverJob.cs 305 (RecoveryServices)
  • V3006 L'objet a été créé mais il n'est pas utilisé. Le mot clé 'throw' peut être manquant: throw new ArgumentException (FOO). StartAzureRmRecoveryServicesAsrUnPlannedFailover.cs 278 (RecoveryServices)
  • V3006 L'objet a été créé mais il n'est pas utilisé. Le mot clé 'throw' peut être manquant: throw new ArgumentException (FOO). StartAzureRmRecoveryServicesAsrUnPlannedFailover.cs 322 (RecoveryServices)
  • V3006 L'objet a été créé mais il n'est pas utilisé. Le mot clé 'throw' peut être manquant: throw new ArgumentException (FOO). UpdateAzureRmRecoveryServicesAsrProtectionDirection.cs 421 (RecoveryServices)
  • V3006 L'objet a été créé mais il n'est pas utilisé. Le mot clé 'throw' peut être manquant: throw new ArgumentException (FOO). UpdateAzureRmRecoveryServicesAsrProtectionDirection.cs 452 (RecoveryServices)

V3022 L' expression 'apiType.HasValue' est toujours fausse. 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"); } 

La logique du travail est violée. Si apiType contient une valeur, le contrôle n'atteindra pas l'expression de retour à la fin de la méthode (toutes les branches de commutateur contiennent return ). Sinon, la méthode renverra toujours PsApiManagementApiType.Http.ToString ("g") et apiType.Value.ToString ("g") , respectivement, ne sera jamais renvoyé.

V3022 L' expression 'automationJob! = Null && automationJob == null' est toujours fausse. NodeConfigurationDeployment.cs 199 (Automation)

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

Le code paradoxal. Deux contrôles qui se contredisent. La deuxième vérification d'égalité nulle contient probablement la mauvaise variable.

V3022 L' expression est toujours fausse. 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"); } .... } 

La vérification est inutile et une exception ne sera jamais levée. La condition requiert l'égalité simultanée de la variable linkedServiceType avec trois valeurs différentes. Les opérateurs && et || sont probablement confus. Code corrigé:

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

V3022 L' expression 'Ekus == null' est toujours fausse. PSKeyVaultCertificatePolicy.cs 129 (KeyVault)

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

Vérification superflue de la variable Ekus pour l'égalité nulle . Probablement rien de mal, mais le code a l'air moche.

V3023 Envisagez d'inspecter cette expression. L'expression est excessive ou contient une erreur d'impression. PolicyRetentionObjects.cs 207 (RecoveryServices)

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

Contrôle excessif ou condition erronée. Vérifier RetentionTimes.Count == 0 n'a aucun sens, car après cette vérification RetentionTimes.Count! = 1 .

V3025 Format incorrect. Un nombre différent d'éléments de format est attendu lors de l'appel de la fonction 'Format'. Arguments non utilisés: this.ResourceGroupName. NewScheduledQueryRuleCommand.cs 117 (Moniteur)

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

Erreur dans la chaîne de format. Le qualificatif {0} est utilisé deux fois, avec deux arguments passés à la méthode Format . L'option correcte:

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

Une autre erreur similaire:

  • V3025 Format incorrect. Un nombre différent d'éléments de format est attendu lors de l'appel de la fonction 'Format'. Arguments non utilisés: this.ResourceGroupName. RemoveScheduledQueryRuleCommand.cs 88 (Moniteur)

V3042 Exception NullReferenceException possible. Le '?.' et '.' les opérateurs sont utilisés pour accéder aux membres de l'objet 'imageAndOsType' VirtualMachineScaleSetStrategy.cs 81 (Compute)

 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) // <= }, }, .... } 

Lors de la création d'un objet VirtualMachineScaleSetVMProfile , la variable imageAndOsType est utilisée sans vérifier la valeur null . Cependant, lors de la création de VirtualMachineScaleSetStorageProfile , cette variable est déjà vérifiée à l'aide de l'opérateur d'accès conditionnel, et deux fois. Le code semble dangereux.

V3042 Exception NullReferenceException possible. Le '?.' et '.' les opérateurs sont utilisés pour accéder aux membres de l'objet 'existingContacts' 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(....); // <= } .... } 

Comme dans le cas d'une exécution normale, et suite à la gestion de l'exception, la variable existingContacts peut obtenir la valeur Null , après quoi le travail se poursuivra. Plus loin dans le code, cette variable est utilisée sans aucune vérification.

V3066 Ordre incorrect possible des arguments passés à la méthode 'PersistSyncServerRegistration': 'storageSyncServiceUid' et '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); } .... } 

L'analyseur suspectait que l'ordre de transmission des arguments à la méthode PersistSyncServerRegistration était confus . Déclaration de méthode:

 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); .... } 

En effet, quelque chose est mélangé ici avec les arguments numéro sept et huit. La vérification du code par l'auteur est requise.

V3077 Le setter de la propriété 'GetGuid' n'utilise pas son paramètre 'value'. RecoveryServicesBackupCmdletBase.cs 54 (RecoveryServices)

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

Le passeur n'utilise pas le paramètre transmis. Au lieu de cela, ils obtiennent un nouveau GUID et l'affectent au champ _guid . Je pense que la plupart des lecteurs conviendront que ce code semble au moins laid. L'utilisation d'une telle construction n'est pas très pratique: pour (re) initialiser la propriété GetGuid , vous devez lui attribuer une fausse valeur, ce qui n'est pas du tout évident. Mais surtout, j'ai été amusé par le moment où les auteurs eux-mêmes utilisent cette construction. Il n'y a qu'un seul endroit dans le code où GetGuid fonctionne . Jetez un oeil:

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

Super!

V3091 Analyse empirique. Il est possible qu'une faute de frappe soit présente à l'intérieur du littéral de chaîne: "ID du groupe de gestion". Le mot «Id» est suspect. Constants.cs 36 (Ressources)

 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"; } 

L'analyseur a indiqué une erreur possible dans la chaîne affectée à la constante GroupName . La conclusion est basée sur une analyse empirique d'autres affectations en tenant compte des noms de variables. Je pense que dans ce cas, l'analyseur a raison, et la valeur de la constante GroupName devrait être de la forme «Management Group name». L'erreur est probablement due au fait que la valeur de la constante GroupId a été copiée , mais ils ont oublié de la modifier.

Une autre erreur similaire:

  • V3091 Analyse empirique. Il est possible qu'une faute de frappe soit présente à l'intérieur du littéral de chaîne. Le mot «Nom» est suspect. ParamHelpMsgs.cs 153 (RecoveryServices)

V3093 Le '|' L'opérateur évalue les deux opérandes. Peut-être un court-circuit '||' l'opérateur doit être utilisé à la place. PSKeyVaultCertificatePolicy.cs 114 (KeyVault)

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

On soupçonne qu'une erreur a été commise et l'opérateur || doit également être utilisé entre les dernières conditions du bloc if . La réponse exacte, comme cela arrive souvent, ne peut être donnée que par le développeur.

V3095 L'objet 'certificate' a été utilisé avant d'être vérifié par rapport à null. Vérifiez les lignes: 41, 43. CertificateInfo.cs 41 (Automation)

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

Classique L'objet est utilisé en premier, et alors seulement le lien est vérifié pour null . Nous rencontrons très souvent de telles erreurs. Considérez une autre erreur similaire.

V3095 L'objet 'clusterCred' a été utilisé avant d'être vérifié par rapport à null. Vérifiez les lignes: 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) .... } 

Et quelques erreurs plus similaires:

  • V3095 L'objet '_profile' a été utilisé avant d'être vérifié par rapport à null. Vérifiez les lignes: 47, 49. RMProfileClient.cs 47 (Comptes)
  • V3095 L'objet 'this.LoadBalancer.BackendAddressPools' a été utilisé avant d'être vérifié par rapport à null. Vérifiez les lignes: 56, 63. AddAzureRmLoadBalancerBackendAddressPoolConfigCommand.cs 56 (CognitiveServices)
  • En général, dans le code Azure PowerShell, j'ai rencontré beaucoup plus d'erreurs V3095 . Mais ils sont tous assez similaires, donc je ne m'attarderai pas là-dessus plus en détail.

V3125 L'objet 'startTime' a été utilisé après avoir été vérifié par rapport à null. Vérifiez les lignes: 1752, 1738. AutomationPSClientDSC.cs 1752 (Automation)

 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)); // <= } .... } 

Également un type d'erreur assez courant. La variable startTime a été vérifiée pour la valeur lors de la première utilisation. La prochaine fois que vous l'utiliserez, ne le faites pas. Mais cela pourrait être encore pire. Jetez un œil au deuxième bloc if . Je pense qu'il ne devrait pas y avoir du tout de variable startTime . Ceci est indiqué à la fois par l'absence de sa vérification de la présence d'une valeur avant utilisation et par la chaîne formée pour passer à la méthode Add . La première partie de cette ligne mentionne une autre variable ( lastModifiedTime ).

V3125 L'objet 'firstPage' a été utilisé après avoir été vérifié par rapport à null. Vérifiez les lignes: 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)) // <= { .... } .... } 

Une autre erreur évidente. La variable firstPage est utilisée de manière non sécurisée, bien que plus tôt dans le code, il y ait une utilisation de cette variable avec une vérification préliminaire de null .

La V3125 dans le code Azure PowerShell a été encore plus réussie que la V3095 décrite précédemment. Tous sont également du même type. Je pense que nous pouvons nous limiter aux deux que nous avons examinés.

V3137 La variable 'apiVersionSetId' est affectée mais n'est pas utilisée à la fin de la fonction. 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)) // <= } } 

L'analyseur signale que la variable locale apiVersionSetId a été initialisée, mais n'a pas été utilisée. Un tel schéma indique souvent une erreur. Je pense que dans ce cas, la probabilité d'erreur est élevée, étant donné que le nom de la variable locale apiVersionSetId et le nom de la propriété ApiVersionSetId ne diffèrent que dans la première lettre. Jetez un œil au code. Après avoir initialisé apiVersionSetId (d'une manière ou d'une autre), seule la propriété ApiVersionSetId est utilisée dans le code. Très, très suspect.

V3137 La variable 'cacheId' est affectée mais n'est pas utilisée à la fin de la fonction. 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); // <= .... } 

La situation, en répétant presque exactement le précédent. La variable locale cacheId n'est pas utilisée après l'initialisation. Au lieu de cela, ils utilisent une propriété avec un nom très similaire, CacheId . Je ne sais pas, c'est peut-être un tel modèle chez les développeurs Azure PowerShell. Mais cela ressemble à une erreur.

V3143 Le paramètre 'value' est réécrit dans un configurateur de propriétés et n'est plus utilisé par la suite. 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; } // <= } 

Le champ partnerType est déclaré comme suit :

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

Contrairement au nom de la solution dans laquelle cette erreur a été détectée (LogicApp), je ne vois pas la logique ici. L'utilisation de la valeur dans un setter pour l'enregistrement n'est pas si rare, mais dans ce cas, nous parlons de perdre la valeur d'origine. Ça a l'air bizarre. Le code dispose d'un accès en lecture unique à cette propriété. Vous devriez peut-être à nouveau demander l'avis d'un expert. Peut-être que je ne comprends pas quelque chose. Le fait est que j'ai rencontré un peu plus des mêmes schémas:

  • V3143 Le paramètre 'value' est réécrit dans un configurateur de propriétés et n'est plus utilisé par la suite. NewAzureIntegrationAccountSchemaCommand.cs 79 (LogicApp)
  • V3143 Le paramètre 'value' est réécrit dans un configurateur de propriétés et n'est plus utilisé par la suite. NewAzureIntegrationAccountSchemaCommand.cs 87 (LogicApp)
  • V3143 Le paramètre 'value' est réécrit dans un configurateur de propriétés et n'est plus utilisé par la suite. UpdateAzureIntegrationAccountPartnerCommand.cs 67 (LogicApp)
  • V3143 Le paramètre 'value' est réécrit dans un configurateur de propriétés et n'est plus utilisé par la suite. UpdateAzureIntegrationAccountSchemaCommand.cs 80 (LogicApp)
  • V3143 Le paramètre 'value' est réécrit dans un configurateur de propriétés et n'est plus utilisé par la suite. UpdateAzureIntegrationAccountSchemaCommand.cs 88 (LogicApp)

Conclusion


C'est tous les bogues intéressants qui ont été trouvés dans le code Azure PowerShell.Passionnés et simplement intéressés, je propose de mener une étude indépendante des erreurs dans le code de ce (ou de tout autre) projet. J'aurais probablement pu manquer quelque chose d'autre d'intéressant. Pour ce faire, il vous suffit de télécharger et d'installer PVS-Studio .

Merci d'avoir lu. Un code sans code!



Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Sergey Khrenov. Azure PowerShell: principalement inoffensif .

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


All Articles