Azure PowerShell: principalement inoffensif

Image 6

Bonjour à tous. Aujourd'hui, nous avons un autre projet Microsoft sur le chèque. Par le titre de cet article, vous pouvez deviner que cette fois, les développeurs ne nous ont pas "plu" avec un grand nombre d'erreurs. Nous espérons que les auteurs du projet ne seront pas offensés par le titre. Après tout, un petit nombre d'erreurs, c'est bien, non? Cependant, nous avons quand même réussi à trouver quelque chose d'intrigant dans le code Azure PowerShell. Nous vous suggérons de vous familiariser avec les fonctionnalités de ce projet et de vérifier les erreurs trouvées à l'aide de l'analyseur PVS-Studio C #.

À propos du projet


Azure PowerShell est un ensemble de commandlets ( cmdlet ) 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 le processus d'étude et de démarrer rapidement le développement pour Azure. Azure PowerShell fournit aux administrateurs et aux développeurs des fonctionnalités convaincantes pour créer, déployer et gérer des applications Microsoft Azure.

Azure PowerShell est développé dans l'environnement .NET Standard, 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, j'ai souvent reçu des projets Microsoft pour une vérification. À mon avis, la qualité de ces projets est généralement de premier ordre. Bien sûr, non sans exception, comme décrit dans l'article " WinForms: Erreurs, Holmes ". Mais cette fois, tout va bien. Le projet est volumineux: les fichiers de code source de 6845 .cs contiennent environ 700 000 lignes, à l'exclusion des lignes vides (je n'ai pas pris en compte les tests et avertissements du troisième niveau de certitude). Très peu d'erreurs ont été trouvées pour une telle quantité de code: pas plus d'une centaine. Il y avait beaucoup de cas similaires, j'ai donc choisi les plus intéressants pour l'article. Comme d'habitude, j'ai trié les erreurs en fonction des numéros d'avertissement de PVS-Studio.

De plus, je suis tombé sur des fragments de code qui ressemblaient à des erreurs, mais ne pouvaient pas être reconnus comme définitivement erronés, car je ne suis pas assez familier avec les particularités de développement de PowerShell. J'espère que parmi les lecteurs, il y aura des spécialistes de ce numéro qui m'aideront. Je vais le décrire en détail ci-dessous.

Avant la partie feedback, je voudrais mentionner la structure spécifique du projet. Le code source Azure PowerShell comprend plus de soixante-dix solutions Visual Studio. Certaines solutions incluent des projets d'autres. Cette structure a un peu ralenti l'analyse (pas beaucoup). Mais le chèque n'a pas posé d'autres difficultés. Pour plus de commodité, dans le message d'erreur (entre parenthèses), je spécifierai le nom de la solution où l'erreur a été trouvée.

Résultats d'analyse


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 un développeur peut corriger. Dans ce cas, il est absolument difficile de savoir si nous traitons la duplication de code qui n'affecte rien ou autre chose doit avoir lieu au lieu de "M" 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 aucune erreur ici. Ceci est un exemple de code redondant. Parfois, un tel code peut indiquer un manque de connaissances du développeur. Le fait est que les vérifications this.AggregationType! = Null et this.AggregationType.HasValue sont identiques. Il suffit d'en utiliser un seul (n'importe lequel). Personnellement, je préfère l'option avec 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 ); } .... } 

Deux autres si les blocs sont absolument identiques, y compris la condition et le corps du bloc. De telles erreurs sont généralement commises lors de l'utilisation de la méthode copier-coller. Le problème ici est encore une fois la criticité de l'erreur. S'il ne s'agit pas d'une simple duplication de code, il peut s'agir de la vérification nécessaire absente et d'un ensemble approprié d'actions. L'auteur doit définitivement 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 auto-assignée. Jetez un œil à sa déclaration:

 [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 sans culpabilité et l'erreur évidente a été commise. L'utilisation explicite de cela pour accéder à la propriété est également assez déroutante. Peut-être qu'une autre variable n'a pas été spécifiée par erreur à la place de cela. Mais ne sautons pas aux conclusions. Le fait est que j'ai rencontré pas mal de ces affectations (une propriété est auto-assignée). Voici un 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; .... } 

Examinons de plus près la deuxième affectation et les affectations suivantes. Dans la partie droite de l'expression, des détails ont lieu à la place de cela. Regardez maintenant la déclaration de la propriété this.LastHeartbeat :
 public DateTime? LastHeartbeat { get; set; } 

Enfin, recherchons la propriété du même nom dans la classe InMageAzureV2ReplicationDetails . Ces biens y sont déclarés:

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

Eh bien, dans ce cas, je suis prêt à admettre que c'est une véritable erreur. Mais que ferons-nous des prochains avertissements? Contrairement à deux fragments de code précédents, il existe plusieurs propriétés auto-attribuées. Eh bien, cela ressemble moins à 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 les auto-affectations de trois propriétés consécutives. Au cas où, j'ai cité la déclaration complète de la classe RemoveExpressRouteConnectionCommand et tous ses attributs, ainsi que la déclaration de propriété ResourceGroupName (les deux autres propriétés sont déclarées de manière similaire). Ce sont ces avertissements qui m'ont fait réfléchir à la question: "Est-ce une erreur?" Je soupçonne qu'une certaine magie interne du développement PowerShell peut se produire ici. J'espère que parmi les lecteurs, il y aura des experts informés de cette question. Je ne suis pas prêt à tirer des conclusions 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 est omis. Et le commentaire dit que l'exception doit juste être levée. J'ai rencontré plusieurs erreurs similaires dans la solution RecoveryServices :

  • 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 a été brisé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") , tandis que la valeur apiType.Value.ToString ("g") ne sera jamais renvoyée.

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

Code contre-intuitif. Deux contrôles qui se contredisent. La deuxième vérification de null 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"); } .... } 

Le chèque est inutile et l'exception ne sera jamais levée. La condition requiert l'égalité de la variable LinkedServiceType simultanée à trois valeurs différentes. Les opérateurs && et || sont susceptibles d'être confus. Code fixe:

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

Contrôle redondant de la variable Ekus pour null . C'est probablement bien, mais le code n'a pas l'air sympa.

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

Voici un contrôle excessif ou une condition excessive. La vérification RetentionTimes.Count == 0 est inutile, car après cela, la vérification RetentionTimes.Count! = 1 suit.

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

Une erreur dans la ligne de formatage. Le spécificateur {0} est utilisé deux fois et la méthode Format reçoit deux arguments. Voici la bonne version:

 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 de l'objet VirtualMachineScaleSetVMProfile , la variable imageAndOsType est vérifiée pour null sans aucune vérification préliminaire. 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, même deux fois. Le code ne semble pas sûr.

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

Dans l'exécution normale et suite à la gestion d'une exception, la variable existingContacts peut obtenir la valeur nulle , après quoi l'exécution se poursuivra. Plus loin dans le code, cette variable est utilisée sans raison particulière.

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 soupçonne que l'ordre des arguments de la méthode PersistSyncServerRegistration est 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 ne va pas ici avec les arguments numéro sept et huit. L'auteur doit vérifier le code.

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 setter n'utilise pas le paramètre passé. Au lieu de cela, il crée un nouveau GUID et l'affecte au champ _guid . Je pense que la plupart des lecteurs conviendraient qu'un tel code semble au moins laid. Cette construction n'est pas très pratique à utiliser: lors de la (re) initialisation de la propriété GetGuid , il faut lui assigner une fausse valeur, ce qui n'est pas très évident. Mais surtout, j'ai été amusé par la façon dont les auteurs ont utilisé ce modèle. Il n'y a qu'un seul endroit, où GetGuid est géré. Découvrez-le:

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

Génial!

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 signalé 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 des variables. Je pense que dans ce cas, l'analyseur a raison, et la valeur des constantes GroupName devrait être une sorte de "nom du groupe de gestion". L'erreur s'est probablement produite en raison du fait que la valeur de la constante GroupId a été copiée, mais n'a pas été modifiée.

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

Dans ce fragment, une erreur peut se produire et dans le bloc if entre deux dernières conditions, le || peut avoir été utilisé. Mais comme cela arrive souvent, seul le développeur peut donner la bonne réponse.

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. D'abord, l'objet est utilisé et ce n'est qu'après que la référence est vérifiée pour null . Nous rencontrons très souvent de telles erreurs. Prenons 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) .... } 

Voici quelques erreurs 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)
  • De manière générale, j'ai vu de nombreuses erreurs V3095 dans le code Azure PowerShell. Mais tous sont assez similaires, je ne m'attarderai donc pas sur cette question.

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

Il s'agit également d'un type d'erreurs assez répandu. La variable startTime est vérifiée pour une présence de valeur lors de sa première utilisation. Mais cela ne se fait pas lors de l'utilisation ultérieure. Eh bien, la situation peut être encore pire. Regardez le deuxième bloc if . Je pense que la variable startTime ne doit pas du tout être ici. Tout d'abord, il n'y a pas de vérification de la présence d'une valeur avant son utilisation. Deuxièmement, la chaîne formée pour être passée à la méthode Add confirme également ma suggestion. Une autre variable (lastModifiedTime ) est mentionnée dans la première partie de cette chaîne.

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 n'est pas utilisée en toute sécurité malgré le fait que plus tôt dans le code, cette variable est déjà utilisée en étant préalablement vérifiée pour null .

J'ai trouvé encore plus d'avertissements V3125 dans le code Azure PowerShell que ceux V3095 décrits ci-dessus. Tous sont également du même type. Je pense que deux d'entre eux que nous avons considérés suffisent.

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 été utilisée en aucune façon. Ce motif indique souvent une erreur. Je pense que dans ce cas, il s'agit très probablement d'une erreur, en particulier compte tenu du fait que le nom de la variable locale apiVersionSetId et le nom de la propriété ApiVersionSetId ne diffèrent que par le cas de la première lettre. Jetez un œil au code. Après avoir initialisé la propriété apiVersionSetId (d'une manière ou d'une autre), seule la propriété ApiVersionSetId est utilisée plus loin dans le code. Cela semble extrêmement 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); // <= .... } 

C'est le cas qui est presque le même que celui décrit précédemment. La variable locale cacheId n'est en aucun cas utilisée après l'initialisation. Au lieu de cela, une autre propriété avec un nom très similaire CacheId est utilisée. Je ne sais pas avec certitude, c'est peut-être juste un modèle de programmation des développeurs Azure PowerShell. Quoi qu'il en soit, 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é de la manière suivante:

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

Malgré le nom de la solution (LogicApp) où une erreur a été détectée, je n'y trouve pas de logique. La modification de la valeur dans le setter n'est pas rare, mais dans ce cas, il s'agit d'une perte de la valeur d'origine. Ça a l'air bizarre. Dans le code, la propriété n'est lue qu'une seule fois. Peut-être devons-nous demander à nouveau l'avis d'experts. Peut-être que je ne comprends tout simplement pas. Le fait est que je suis tombé sur plusieurs 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


Ce sont tous des bogues intéressants qui ont été trouvés dans le code Azure PowerShell. Les amateurs et ceux qui sont intéressés sont invités à examiner eux-mêmes les erreurs dans ce projet (ou tout autre). Je pourrais probablement manquer quelque chose de décalé. Pour effectuer la révision, il vous suffit de télécharger et d'installer PVS-Studio .

Merci d'avoir lu jusqu'à la fin. Et, bien sûr, du code sans code pour tout le monde!

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


All Articles