
Salutations à tous les fans de critiquer le code de quelqu'un d'autre. :) Aujourd'hui, dans notre laboratoire, le nouveau matériel de recherche est le code source du projet AWS SDK pour .NET. À un moment donné, nous avons écrit un article sur la vérification du kit SDK AWS pour C ++. Ensuite, il n'y avait rien de particulièrement intéressant. Voyons comment la version .NET du kit AWS SDK nous plaira. Une bonne occasion de démontrer une fois de plus les capacités de l'analyseur PVS-Studio, ainsi que de rendre le monde un peu plus parfait.
Le Kit de développement logiciel (SDK) .NET Amazon Web Services (AWS) est une boîte à outils de développeur conçue pour créer des applications basées sur .NET dans l'infrastructure AWS et simplifier considérablement le processus d'écriture de code. Le SDK comprend des suites d'API .NET pour divers services AWS tels qu'Amazon S3, Amazon EC2, DynamoDB et autres. Le code source du SDK est hébergé sur
GitHub .
Comme je l'ai dit, à un moment donné, nous avons écrit
un article sur la vérification du kit SDK AWS pour C ++. L'article s'est avéré être petit - il n'y a eu que quelques erreurs sur 512 000 lignes de code. Cette fois, nous avons affaire à une quantité de code beaucoup plus importante, dont environ 34 000 fichiers cs, et le nombre total de lignes de code (à l'exclusion des lignes vides) est impressionnant de 5 millions. Une petite partie du code (200 000 lignes dans 664 fichiers cs) tombe sur les tests, je ne les ai pas considérés.
Si la qualité du code .NET de la version SDK est approximativement la même que celle de C ++ (deux erreurs par 512 KLOC), alors nous devrions obtenir environ 10 fois plus d'erreurs. C'est, bien sûr, une méthode de calcul très inexacte qui ne prend pas en compte les caractéristiques du langage et de nombreux autres facteurs, mais je ne pense pas que le lecteur veuille maintenant se plonger dans des discussions ennuyeuses. Au lieu de cela, je propose d'aller directement aux résultats.
La vérification a été effectuée à l'aide de PVS-Studio version 6.27. Incroyablement, l'analyseur a pu détecter environ 40 erreurs dans le code AWS SDK for .NET qui méritaient d'être mentionnées. Cela indique non seulement la haute qualité du code SDK (environ 4 erreurs pour 512 KLOC), mais également la qualité comparable du travail C # de l'analyseur PVS-Studio par rapport à C ++. Excellent résultat!
Les auteurs du kit AWS SDK pour .NET sont excellents. De projet en projet, ils démontrent une qualité de code incroyable. Cela peut servir de bon exemple pour d'autres équipes. Mais, bien sûr, je ne serais pas le développeur d'un analyseur statique si je n'avais pas inséré mes 5 kopecks. :) Nous travaillons déjà avec l'équipe d'Amazon Lumberyard sur l'utilisation de PVS-Studio. Mais comme il s'agit d'une très grande entreprise avec un tas de divisions à travers le monde, il est très probable que l'équipe AWS SDK for .NET n'ait jamais entendu parler de PVS-Studio. En tout cas, dans le code SDK, je n'ai trouvé aucun signe d'utilisation de notre analyseur, bien que cela ne signifie rien. Cependant, l'équipe, au minimum,
utilise l' analyseur intégré à Visual Studio. C'est bien, mais les vérifications de code peuvent être
améliorées :).
En conséquence, j'ai quand même réussi à trouver des erreurs dans le code du SDK, et enfin, il est temps de les partager.
Erreur de logiqueAvertissement PVS-Studio: V3008 [CWE-563] La variable 'this.linker.s3.region' reçoit des valeurs successives deux fois. C'est peut-être une erreur. Vérifiez les lignes: 116, 114. AWSSDK.DynamoDBv2.Net45 S3Link.cs 116
public string Region { get { .... } set { if (String.IsNullOrEmpty(value)) { this.linker.s3.region = "us-east-1"; } this.linker.s3.region = value; } }
L'analyseur avertit de la réaffectation de la valeur de la même variable. À partir du code, il devient clair que cela est dû à une erreur qui viole la logique de fonctionnement: la valeur de la variable
this.linker.s3.region sera toujours égale à la
valeur , quelle que soit la condition
if (String.IsNullOrEmpty (value)) . Dans le corps du bloc
if , le
retour a été ignoré. Le code doit être corrigé comme suit:
public string Region { get { .... } set { if (String.IsNullOrEmpty(value)) { this.linker.s3.region = "us-east-1"; return; } this.linker.s3.region = value; } }
Récursion infiniePVS-Studio Warning: V3110 [CWE-674] Possible récursion infinie à l'intérieur de la propriété 'OnFailure'. AWSSDK.ElasticMapReduce.Net45 ResizeJobFlowStep.cs 171
OnFailure? onFailure = null; public OnFailure? OnFailure { get { return this.OnFailure; }
Un exemple de faute de frappe classique qui provoque une récursion infinie dans l'
accesseur get de la propriété
OnFailure . Au lieu de renvoyer la valeur du champ privé,
onFailure fait référence à la propriété
OnFailure . Option corrigée:
public OnFailure? OnFailure { get { return this.onFailure; } set { this.onFailure = value; } }
Vous demandez: "Comment cela a-t-il fonctionné?" Jusqu'à présent, aucun moyen. La propriété n'est utilisée nulle part, mais elle est temporaire. À un moment donné, quelqu'un commencera à l'utiliser et obtiendra certainement un résultat inattendu. Pour éviter de telles fautes de frappe, il est recommandé de ne pas utiliser d'identificateurs qui ne diffèrent que dans la première casse.
Une autre note à cette conception est l'utilisation d'un identifiant qui correspond complètement au nom du type
OnFailure . Du point de vue du compilateur, c'est tout à fait acceptable, mais cela rend la perception humaine du code plus difficile.
Une autre erreur similaire:
Avertissement PVS-Studio: V3110 [CWE-674] Possible récursion infinie à l'intérieur de la propriété 'SSES3'. AWSSDK.S3.Net45 InventoryEncryption.cs 37
private SSES3 sSES3; public SSES3 SSES3 { get { return this.SSES3; } set { this.SSES3 = value; } }
La situation est identique à celle décrite ci-dessus. Seulement ici, une récursion infinie se produira lors de l'accès à la propriété
SSES3 pour la lecture et l'écriture. Option corrigée:
public SSES3 SSES3 { get { return this.sSES3; } set { this.sSES3 = value; } }
Test de pleine conscienceCe qui suit est une tâche d'un programmeur désireux d'utiliser la technique du copier-coller. Regardez à quoi ressemble le code dans l'éditeur Visual Studio et essayez de trouver l'erreur.

Avertissement PVS-Studio: V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 91, 95. AWSSDK.AppSync.Net45 CreateApiKeyResponseUnmarshaller.cs 91
J'ai réduit le corps de la méthode
UnmarshallException , supprimant tous les éléments inutiles. Vous pouvez maintenant voir que des vérifications identiques se succèdent:
public override AmazonServiceException UnmarshallException(....) { .... if (errorResponse.Code != null && errorResponse.Code.Equals("LimitExceededException")) { return new LimitExceededException(errorResponse.Message, innerException, errorResponse.Type, errorResponse.Code, errorResponse.RequestId, statusCode); } if (errorResponse.Code != null && errorResponse.Code.Equals("LimitExceededException")) { return new LimitExceededException(errorResponse.Message, innerException, errorResponse.Type, errorResponse.Code, errorResponse.RequestId, statusCode); } .... }
Il peut sembler que l'erreur n'est pas grossière - juste une vérification supplémentaire. Mais souvent, un tel modèle peut indiquer des problèmes plus graves dans le code lorsque certaines vérifications nécessaires ne sont pas effectuées.
Il y a quelques erreurs plus similaires dans le code.
Avertissements de PVS-Studio:- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 75, 79. AWSSDK.CloudDirectory.Net45 CreateSchemaResponseUnmarshaller.cs 75
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 105, 109. AWSSDK.CloudDirectory.Net45 GetSchemaAsJsonResponseUnmarshaller.cs 105
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 201, 205. AWSSDK.CodeCommit.Net45 PostCommentForPullRequestResponseUnmarshaller.cs 201
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 101, 105. AWSSDK.CognitoIdentityProvider.Net45 VerifySoftwareTokenResponseUnmarshaller.cs 101
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 72, 76. AWSSDK.Glue.Net45 UpdateConnectionResponseUnmarshaller.cs 72
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 123, 127. AWSSDK.Neptune.Net45 RestoreDBClusterFromSnapshotResponseUnmarshaller.cs 123
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 167, 171. AWSSDK.Neptune.Net45 RestoreDBClusterFromSnapshotResponseUnmarshaller.cs 167
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 127, 131. AWSSDK.RDS.Net45 RestoreDBClusterFromSnapshotResponseUnmarshaller.cs 127
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 171, 175. AWSSDK.RDS.Net45 RestoreDBClusterFromSnapshotResponseUnmarshaller.cs 171
- V3029 Les expressions conditionnelles des instructions «if» situées côte à côte sont identiques. Vérifiez les lignes: 99, 103. AWSSDK.Rekognition.Net45 RecognizeCelebritiesResponseUnmarshaller.cs 99
Tu es quoiPVS-Studio Warning: V3062 Un objet 'attributeName' est utilisé comme argument de sa propre méthode. Pensez à vérifier le premier argument réel de la méthode «Contient». AWSSDK.MobileAnalytics.Net45 CustomEvent.cs 261
L'analyseur a détecté une erreur dans la méthode
GetAttribute : la chaîne est vérifiée pour le fait qu'elle se contient. De la description de la méthode, il s'ensuit que si le nom d'attribut (clé
attributeName ) est trouvé (dans le dictionnaire
_attributes ), alors la valeur d'attribut doit être retournée, sinon
null . En réalité, comme la condition
attributeName.Contains (attributeName) est toujours vraie, une tentative est faite pour renvoyer une valeur par une clé qui peut ne pas être trouvée dans le dictionnaire. Ensuite, au lieu de retourner
null, une exception KeyNotFoundException sera levée.
Essayons de corriger ce code. Pour mieux comprendre comment procéder, jetez un œil à une autre méthode:
Cette méthode vérifie si le nom d'attribut (clé
attributeName )
existe dans le dictionnaire
_attributes .
Revenons à la méthode
GetAttribute et
corrigeons l'erreur:
public string GetAttribute(string attributeName) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } string ret = null; lock(_lock) { if(_attributes.ContainsKey(attributeName)) ret = _attributes[attributeName]; } return ret; }
Maintenant, la méthode fait exactement ce qui est indiqué dans la description.
Et encore une petite remarque sur ce fragment de code. J'ai remarqué que les auteurs utilisent le
verrouillage lorsqu'ils travaillent avec le dictionnaire
_attributes . De toute évidence, cela est nécessaire avec un accès multi-thread, mais la construction du
verrou est plutôt lente et lourde. Au lieu de
Dictionary dans ce cas, il pourrait être plus pratique d'utiliser une version thread-safe du dictionnaire -
ConcurrentDictionary . Ensuite, le besoin de
verrouillage disparaît. Bien que, je ne connaisse peut-être aucune caractéristique du projet.
Comportement suspectAvertissement PVS-Studio: V3063 [CWE-571] Une partie de l'expression conditionnelle est toujours vraie si elle est évaluée: string.IsNullOrEmpty (inferredIndexName). AWSSDK.DynamoDBv2.PCL ContextInternal.cs 802
private static string GetQueryIndexName(....) { .... string inferredIndexName = null; if (string.IsNullOrEmpty(specifiedIndexName) && indexNames.Count == 1) { inferredIndexName = indexNames[0]; } else if (indexNames.Contains(specifiedIndexName, StringComparer.Ordinal)) { inferredIndexName = specifiedIndexName; } else if (string.IsNullOrEmpty(inferredIndexName) &&
L'analyseur a alerté la
vérification de string.IsNullOrEmpty (inferredIndexName) . En effet, la chaîne
inferredIndexName est affectée
null , puis la valeur de cette variable n'est modifiée nulle part, puis pour une raison quelconque, elle est vérifiée pour
null ou une chaîne vide. Ça a l'air suspect. Examinons de près l'extrait de code donné. Je ne l'ai délibérément pas réduit pour une meilleure compréhension de la situation. Ainsi, dans la première
instruction if (et également dans la suivante), la variable
specifiedIndexName est vérifiée d'une manière ou d'une autre. Selon le résultat des vérifications, la variable
inferredIndexName reçoit une nouvelle valeur. Prenons maintenant la troisième
instruction if . Le corps de cet opérateur (levant une exception) sera exécuté si
indexNames.Count> 0 , car la première partie de la condition est
string.IsNullOrEmpty (inferredIndexName) est toujours vrai. Peut-être que les variables
specifiedIndexName et
inferredIndexName sont simplement confondues. Ou le troisième chèque doit être sans
autre , représentant une
instruction if autonome:
if (string.IsNullOrEmpty(specifiedIndexName) && indexNames.Count == 1) { inferredIndexName = indexNames[0]; } else if (indexNames.Contains(specifiedIndexName, StringComparer.Ordinal)) { inferredIndexName = specifiedIndexName; } if (string.IsNullOrEmpty(inferredIndexName) && indexNames.Count > 0) throw new InvalidOperationException(....);
Dans ce cas, il est difficile de donner une réponse définitive sur les options de correction de ce code. Mais il est absolument nécessaire que l'auteur l'inspecte.
NullReferenceExceptionAvertissement PVS-Studio: V3095 [CWE-476] L'objet 'conditionValues' a été utilisé avant d'être vérifié par rapport à null. Vérifiez les lignes: 228, 238. AWSSDK.Core.Net45 JsonPolicyWriter.cs 228
private static void writeConditions(....) { .... foreach (....) { IList<string> conditionValues = keyEntry.Value; if (conditionValues.Count == 0)
Classiques du genre. La variable
conditionValues est utilisée sans d'abord vérifier la valeur
null . De plus, plus loin dans le code, une telle vérification est effectuée, mais il est trop tard. :)
Le code peut être corrigé comme suit:
private static void writeConditions(....) { .... foreach (....) { IList<string> conditionValues = keyEntry.Value; if (conditionValues != null && conditionValues.Count == 0) continue; .... if (conditionValues != null && conditionValues.Count != 0) { .... } .... } }
Quelques erreurs similaires ont été trouvées dans le code.
Avertissements de PVS-Studio:- V3095 [CWE-476] L'objet 'ts.Listeners' a été utilisé avant d'être vérifié par rapport à null. Vérifiez les lignes: 140, 143. AWSSDK.Core.Net45 Logger.Diagnostic.cs 140
- V3095 [CWE-476] L'objet 'obj' a été utilisé avant d'être vérifié par rapport à null. Vérifiez les lignes: 743, 745. AWSSDK.Core.Net45 JsonMapper.cs 743
- V3095 [CWE-476] L'objet 'multipartUploadMultipartUploadpartsList' a été utilisé avant d'être vérifié par rapport à null. Vérifiez les lignes: 65, 67. AWSSDK.S3.Net45 CompleteMultipartUploadRequestMarshaller.cs 65
L'avertissement suivant est très similaire dans sa signification, mais la situation est l'inverse de celle discutée ci-dessus.
Avertissement PVS-Studio: V3125 [CWE-476] L'objet 'état' a été utilisé après avoir été vérifié par rapport à null. Vérifiez les lignes: 139, 127. AWSSDK.Core.Net45 RefreshingAWSCredentials.cs 139
private void UpdateToGeneratedCredentials( CredentialsRefreshState state) { string errorMessage; if (ShouldUpdate) { .... if (state == null) errorMessage = "Unable to generate temporary credentials"; else .... throw new AmazonClientException(errorMessage); } state.Expiration -= PreemptExpiryTime;
L'un des fragments de code contient une vérification de la valeur de la variable d'
état pour l'égalité
nulle . En outre, selon le code, la variable d'
état est utilisée pour se désinscrire de l'événement
PreemptExpiryTime , tandis que la vérification de
null n'est plus effectuée et une
NullReferenceException est possible . Option de code plus sécurisée:
private void UpdateToGeneratedCredentials( CredentialsRefreshState state) { string errorMessage; if (ShouldUpdate) { .... if (state == null) errorMessage = "Unable to generate temporary credentials"; else .... throw new AmazonClientException(errorMessage); } if (state != null) state.Expiration -= PreemptExpiryTime; .... }
Il existe d'autres erreurs similaires dans le code.
Avertissements de PVS-Studio:- V3125 [CWE-476] L'objet 'wrappedRequest.Content' a été utilisé après avoir été vérifié par rapport à null. Vérifiez les lignes: 395, 383. AWSSDK.Core.Net45 HttpHandler.cs 395
- V3125 [CWE-476] L'objet 'datasetUpdates' a été utilisé après avoir été vérifié par rapport à null. Vérifiez les lignes: 477, 437. AWSSDK.CognitoSync.Net45 Dataset.cs 477
- V3125 [CWE-476] L'objet 'cORSConfigurationCORSConfigurationcORSRulesListValue' a été utilisé après avoir été vérifié par rapport à null. Vérifiez les lignes: 125, 111. AWSSDK.S3.Net45 PutCORSConfigurationRequestMarshaller.cs 125
- V3125 [CWE-476] L'objet 'lifecycleConfigurationLifecycleConfigurationrulesListValue' a été utilisé après avoir été vérifié par rapport à null. Vérifiez les lignes: 157, 68. AWSSDK.S3.Net45 PutLifecycleConfigurationRequestMarshaller.cs 157
- V3125 [CWE-476] L'objet 'this.Key' a été utilisé après avoir été vérifié par rapport à null. Vérifiez les lignes: 199, 183. AWSSDK.S3.Net45 S3PostUploadRequest.cs 199
Une réalité incontestéeAvertissement PVS-Studio: V3009 [CWE-393] Il est étrange que cette méthode renvoie toujours une seule et même valeur de 'true'. AWSSDK.Core.Net45 Lexer.cs 651
private static bool State19 (....) { while (....) { switch (....) { case '"': .... return true; case '\\': .... return true; default: .... continue; } } return true; }
La méthode renvoie toujours
true . Voyons à quel point cela est critique pour le code appelant. J'ai suivi l'utilisation de la méthode
State19 . Il participe au remplissage du tableau des gestionnaires
fsm_handler_table avec d'autres méthodes similaires (il y en a 28 avec des noms, respectivement, de
State1 à
State28 ). Il est important de noter ici qu'en plus de
State19 , des avertissements
V3009 [CWE-393] ont également été émis pour certains autres gestionnaires. Ce sont les gestionnaires:
State23, State26, State27, State28 . Alertes émises par l'analyseur pour eux:
- V3009 [CWE-393] Il est étrange que cette méthode renvoie toujours une seule et même valeur de 'true'. AWSSDK.Core.Net45 Lexer.cs 752
- V3009 [CWE-393] Il est étrange que cette méthode renvoie toujours une seule et même valeur de 'true'. AWSSDK.Core.Net45 Lexer.cs 810
- V3009 [CWE-393] Il est étrange que cette méthode renvoie toujours une seule et même valeur de 'true'. AWSSDK.Core.Net45 Lexer.cs 822
- V3009 [CWE-393] Il est étrange que cette méthode renvoie toujours une seule et même valeur de 'true'. AWSSDK.Core.Net45 Lexer.cs 834
Voici à quoi ressemble la déclaration et l'initialisation du tableau de gestionnaires:
private static StateHandler[] fsm_handler_table; .... private static void PopulateFsmTables () { fsm_handler_table = new StateHandler[28] { State1, State2, .... State19, .... State23, .... State26, State27, State28 };
Pour être complet, voyons le code de l'un des gestionnaires, auquel l'analyseur ne s'est pas plaint, par exemple,
State2 :
private static bool State2 (....) { .... if (....) { return true; } switch (....) { .... default: return false; } }
Et voici comment les gestionnaires sont appelés:
public bool NextToken () { .... while (true) { handler = fsm_handler_table[state - 1]; if (! handler (fsm_context))
Comme vous pouvez le voir, une exception sera levée si
false est retourné. Dans notre cas, pour les gestionnaires
State19, State23, State26, State27 et
State28, cela ne se produira jamais. Ça a l'air suspect. D'un autre côté, jusqu'à cinq gestionnaires ont un comportement similaire (retournent toujours
true ), donc peut-être que cela était prévu et n'est pas le résultat d'une faute de frappe.
Pourquoi ai-je insisté sur tout cela avec autant de détails? Cette situation est très indicative dans le sens où un analyseur statique n'est souvent capable d'indiquer qu'une conception suspecte. Et même une personne (pas une machine) qui n'a pas une connaissance suffisante du projet, ayant passé du temps à étudier le code, n'est toujours pas en mesure de donner une réponse exhaustive sur la présence d'une erreur. Le code doit être étudié par le développeur.
Des contrôles dénués de sensAvertissement PVS-Studio: V3022 [CWE-571] L'expression 'doLog' est toujours vraie. AWSSDK.Core.Net45 StoredProfileAWSCredentials.cs 235
private static bool ValidCredentialsExistInSharedFile(....) { .... var doLog = false; try { if (....) { return true; } else { doLog = true; } } catch (InvalidDataException) { doLog = true; } if (doLog)
Faites attention à la variable
doLog . Après l'initialisation avec
false , alors dans le code cette variable deviendra
vraie dans tous les cas. La vérification
if (doLog) est donc toujours vraie. Il y avait peut-être une branche plus tôt dans cette méthode dans laquelle la variable
doLog n'avait pas de valeur, puis au moment de la vérification, elle pouvait contenir la
fausse valeur obtenue lors de l'initialisation. Mais maintenant, il n'y a plus de branche.
Une autre erreur similaire:
Avertissement PVS-Studio: V3022 L' expression '! Résultat' est toujours fausse. AWSSDK.CognitoSync.PCL SQLiteLocalStorage.cs 353
public void PutValue(....) { .... bool result = PutValueHelper(....); if (!result) <= { _logger.DebugFormat("{0}", @"Cognito Sync - SQLiteStorage - Put Value Failed"); } else { UpdateLastModifiedTimestamp(....); } .... }
L'analyseur prétend que la valeur de la variable de
résultat est toujours
vraie . Cela n'est possible que si la méthode
PutValueHelper renvoie toujours
true . Jetez un œil à cette méthode:
private bool PutValueHelper(....) { .... if (....)) { return true; } if (record == null) { .... return true; } else { .... return true; } }
En effet, la méthode retournera
vrai dans n'importe quelle condition. De plus, l'analyseur a émis un avertissement pour cette méthode.
Avertissement PVS-Studio: V3009 [CWE-393] Il est étrange que cette méthode renvoie toujours une seule et même valeur de 'true'. SQLiteLocalStorage.cs 1016
Je n'ai délibérément pas cité cet avertissement plus tôt lorsque je considérais d'autres erreurs du
V3009 , mais je l'ai enregistré pour ce cas. Ainsi, l'analyseur avait raison d'indiquer l'erreur
V3022 dans le code appelant.
Copiez-collez. Encore une foisAvertissement PVS-Studio: V3001 Il existe des sous-expressions identiques 'this.token == JsonToken.String' à gauche et à droite de '||' opérateur. AWSSDK.Core.Net45 JsonReader.cs 343
public bool Read() { .... if ( (this.token == JsonToken.ObjectEnd || this.token == JsonToken.ArrayEnd || this.token == JsonToken.String ||
Comparez deux fois le champ
this.token avec la valeur
JsonToken.String de l'énumération
JsonToken . L'une des comparaisons devrait probablement contenir une valeur d'énumération différente. Si oui, alors une grave erreur a été commise.
Refactorisation + insouciance?Avertissement PVS-Studio: V3025 [CWE-685] 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: AWSConfigs.AWSRegionKey. AWSSDK.Core.Net45 AWSRegion.cs 116
public InstanceProfileAWSRegion() { .... if (region == null) { throw new InvalidOperationException( string.Format(CultureInfo.InvariantCulture, "EC2 instance metadata was not available or did not contain region information.", AWSConfigs.AWSRegionKey)); } .... }
Probablement, la chaîne de format de la méthode
string.Format contenait précédemment le spécificateur de sortie
{0} , pour lequel l'argument
AWSConfigs.AWSRegionKey a été défini. Ensuite, la ligne a été modifiée, le spécificateur a disparu, mais ils ont oublié de supprimer l'argument. Le fragment de code ci-dessus fonctionne sans erreur (une exception serait levée dans le cas contraire - un spécificateur sans argument), mais il a l'air moche. Le code doit être fixé comme suit:
if (region == null) { throw new InvalidOperationException( "EC2 instance metadata was not available or did not contain region information."); }
DangereuxAvertissement PVS-Studio: V3083 [CWE-367] L'appel non sécurisé de l'événement 'mOnSyncSuccess', NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.CognitoSync.PCL Dataset.cs 827
protected void FireSyncSuccessEvent(List<Record> records) { if (mOnSyncSuccess != null) { mOnSyncSuccess(this, new SyncSuccessEventArgs(records)); } }
Une situation assez courante d'un appel non sécurisé au gestionnaire d'événements. Entre la vérification de la variable
mOnSyncSuccess pour
null et l'appel du gestionnaire, un événement peut être désabonné et sa valeur deviendra nulle. La probabilité d'un tel scénario est faible, mais il vaut toujours mieux sécuriser le code:
protected void FireSyncSuccessEvent(List<Record> records) { mOnSyncSuccess?.Invoke(this, new SyncSuccessEventArgs(records)); }
Il existe d'autres erreurs similaires dans le code.
Avertissements de PVS-Studio:- V3083 [CWE-367] L'appel non sécurisé de l'événement 'mOnSyncFailure', NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.CognitoSync.PCL Dataset.cs 839
- V3083 [CWE-367] L'appel d'événement à risque, NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.PCL AmazonServiceClient.cs 332
- V3083 [CWE-367] L'appel d'événement à risque, NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.PCL AmazonServiceClient.cs 344
- V3083 [CWE-367] L'appel d'événement à risque, NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.PCL AmazonServiceClient.cs 357
- V3083 [CWE-367] L'appel non sécurisé de l'événement 'mExceptionEvent', NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.PCL AmazonServiceClient.cs 366
- V3083 [CWE-367] L'appel d'événement à risque, NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.PCL AmazonWebServiceRequest.cs 78
- V3083 [CWE-367] L'appel non sûr de l'événement 'OnRead', NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.PCL EventStream.cs 97
- V3083 [CWE-367] L'appel d'événement à risque, NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.Android NetworkReachability.cs 57
- V3083 [CWE-367] L'appel d'événement à risque, NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.Android NetworkReachability.cs 94
- V3083 [CWE-367] L'appel d'événement à risque, NullReferenceException est possible. Pensez à affecter un événement à une variable locale avant de l'invoquer. AWSSDK.Core.iOS NetworkReachability.cs 54
Classe inachevéeAvertissement PVS-Studio: le type V3126 implémentant l'interface IEquatable <T> de type 'JsonData' ne remplace pas la méthode 'GetHashCode'. AWSSDK.Core.Net45 JsonData.cs 26
public class JsonData : IJsonWrapper, IEquatable<JsonData> { .... }
La classe
JsonData contient beaucoup de code, donc je ne l'ai pas donné dans son intégralité, me limitant à le déclarer. Cette classe ne contient vraiment pas de méthode
GetHashCode substituée, ce qui n'est pas sûr car elle peut conduire à un comportement erroné lors de l'utilisation du type
JsonData pour fonctionner, par exemple, avec des collections. Il n'y a probablement pas de problème à l'heure actuelle, mais la stratégie d'utilisation de ce type peut changer à l'avenir. Cette erreur est décrite plus en détail dans la
documentation .
ConclusionC'est toutes les erreurs intéressantes que j'ai réussi à détecter dans le code AWS SDK for .NET à l'aide de l'analyseur statique PVS-Studio. Encore une fois, je souligne la qualité du projet. J'ai trouvé un très petit nombre d'erreurs pour 5 millions de lignes de code. Bien que, probablement, une analyse plus approfondie des avertissements émis me permette d'ajouter quelques erreurs de plus à cette liste. Mais il est également très probable que j'ai en vain attribué certains des avertissements décrits à des erreurs. Dans ce cas, des conclusions non ambiguës sont toujours faites uniquement par le développeur, qui se trouve dans le contexte du code en cours de vérification.
Si vous souhaitez partager cet article avec un public anglophone, veuillez utiliser le lien vers la traduction: Sergey Khrenov. Recherche d'erreurs dans le code source du SDK Amazon Web Services pour .NET