
Bienvenue à tous les fans de la corbeille du code de quelqu'un d'autre. :) Aujourd'hui, dans notre laboratoire, nous avons un nouveau matériel pour une recherche - le code source du projet AWS SDK for .NET. À l'époque, nous avons écrit un article sur la vérification d'AWS SDK pour C ++. Il n'y avait alors rien de particulièrement intéressant. Voyons ce que vaut .NET de la version AWS SDK. Encore une fois, c'est une excellente occasion de démontrer les capacités de l'analyseur PVS-Studio et de rendre le monde un peu meilleur.
Le SDK Amazon Web Services (AWS) pour .NET est un ensemble d'outils de développeur, destiné à créer des applications basées sur .NET dans l'infrastructure AWS. Cet ensemble permet de simplifier considérablement le processus d'écriture de code. Le SDK comprend des ensembles API .NET pour divers services AWS, tels que Amazon S3, Amazon EC2, DynamoDB et autres. Le code source du SDK est disponible sur
GitHub .
Comme je l'ai mentionné, à l'époque, nous avions déjà écrit l'
article sur la vérification d'AWS SDK pour C ++. L'article s'est avéré être petit - seulement quelques erreurs trouvées pour 512 000 lignes de code. Cette fois, nous avons affaire à une taille beaucoup plus grande du code, qui comprend 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 des fichiers 664-cs) revient aux tests, je ne les ai pas pris en compte.
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 un nombre d'erreurs environ 10 fois plus élevé. Bien sûr, il s'agit d'une méthodologie de calcul très inexacte, qui ne prend pas en compte les particularités linguistiques et de nombreux autres facteurs, mais je ne pense pas que le lecteur veuille maintenant entrer dans un raisonnement ennuyeux. Au lieu de cela, je suggère de passer aux résultats.
La vérification a été effectuée à l'aide de PVS-Studio 6.27. C'est tout simplement incroyable, mais le fait est que dans l'AWS SDK pour .NET, l'analyseur a réussi à détecter 40 erreurs, ce qui vaut la peine d'en parler. Il démontre non seulement une haute qualité du code SDK (environ 4 erreurs pour 512 KLOC), mais également une qualité comparable de l'analyseur C # PVS-Studio par rapport à C ++. Un super résultat!
Auteurs d'AWS SDK pour .NET, vous êtes de vrais champions! Avec chaque projet, vous démontrez une qualité exceptionnelle du code. Cela peut être un excellent exemple pour d'autres équipes. Cependant, bien sûr, je ne serais pas un développeur d'un analyseur statique, si je ne donnais pas mes 2 cents. :) Nous travaillons déjà avec une équipe Lumberyard d'Amazon sur l'utilisation de PVS-Studio. Comme il s'agit d'une très grande entreprise avec un tas d'unités dans le monde, il est très probable que l'équipe AWS SDK pour .NET n'ait jamais entendu parler de PVS-Studio. Quoi qu'il en soit, je n'ai trouvé aucun signe d'utilisation de notre analyseur dans le code SDK, bien qu'il ne dise rien. Cependant, au moins, l'équipe
utilise l'analyseur intégré à Visual Studio. C'est génial, mais les révisions de code peuvent toujours être
améliorées :).
En conséquence, j'ai réussi à trouver quelques bugs dans le code 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 met en garde contre l'attribution répétée de valeurs à la même variable. À partir du code, il devient clair que cela est dû à l'erreur qui viole la logique du travail du programme: la valeur de la variable
this.linker.s3.region sera toujours égale à la valeur de la valeur de la variable, quelle que soit la condition
if (String.IsNullOrEmpty (value)) .
La déclaration de
retour a été manquée dans le corps du bloc
if . 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 infinieAvertissement PVS-Studio: V3110 [CWE-674] Récursion infinie possible dans la propriété 'OnFailure'. AWSSDK.ElasticMapReduce.Net45 ResizeJobFlowStep.cs 171
OnFailure? onFailure = null; public OnFailure? OnFailure { get { return this.OnFailure; }
Un exemple classique d'une faute de frappe, qui conduit à une récursion infinie dans l'accesseur
get de la propriété
OnFailure . Au lieu de renvoyer la valeur d'un champ privé
onFailure, l'accès à la propriété
OnFailure a lieu. Variante correcte:
public OnFailure? OnFailure { get { return this.onFailure; } set { this.onFailure = value; } }
Vous pouvez demander: "Comment cela a-t-il fonctionné?" Jusqu'à présent - pas comment. La propriété n'est utilisée nulle part ailleurs, mais c'est temporaire. À un moment donné, quelqu'un commencera à l'utiliser et recevra certainement un résultat inattendu. Pour éviter de telles fautes de frappe, il est recommandé de ne pas utiliser d'identifiants qui ne diffèrent que dans le cas de la première lettre.
Un autre commentaire à cette construction est l'utilisation de l'identifiant, qui correspond complètement au nom du type
OnFailure . Du point de vue du compilateur, c'est tout à fait acceptable, mais cela complique la perception du code pour une personne.
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. Cependant, ici une récursion infinie se produira lors de l'accès à la propriété
SSES3 à la fois pour la lecture et l'attribution. Variante correcte:
public SSES3 SSES3 { get { return this.sSES3; } set { this.sSES3 = value; } }
Test sur considérationMaintenant, je voudrais citer une tâche d'un développeur, prise en utilisant la méthode Copy-Paste. Jetez un œil à l'apparence du code dans l'éditeur Visual Studio et essayez de trouver une 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 , après avoir supprimé tout ce qui n'était pas nécessaire. 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 le bogue n'est pas brutal - juste une vérification supplémentaire. Néanmoins, souvent un tel schéma peut indiquer des problèmes plus graves dans le code, lorsqu'une vérification nécessaire ne sera pas effectuée.
Dans le code, il existe plusieurs erreurs similaires.
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
Qu'est ce que c'est?Avertissement PVS-Studio: 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 : une chaîne est vérifiée si elle se contient. D'après la description de la méthode, il s'ensuit que si le nom d'attribut (clé d'
attributName ) est trouvé (dans le dictionnaire
_attributes ), la valeur d'attribut doit être retournée, sinon -
null . En fait, comme la condition
attributeName.Contains (attributeName) est toujours vraie, une tentative est faite pour renvoyer la valeur par une clé qui pourrait ne pas être trouvée dans un dictionnaire. Ensuite, au lieu de renvoyer
null, une exception
KeyNotFoundException sera levée.
Essayons de corriger ce code. Pour mieux comprendre comment procéder, vous devez envisager 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.
Encore un petit commentaire sur ce fragment de code. J'ai remarqué que les auteurs utilisent le
verrouillage lorsqu'ils travaillent avec le dictionnaire
_attributes . Il est clair que cela est nécessaire lorsque vous disposez d'un accès multithread, mais la construction de la
serrure est plutôt lente et encombrante. Au lieu d'un
dictionnaire , dans ce cas, il serait peut-être plus pratique d'utiliser la version thread-safe du dictionnaire -
ConcurrentDictionary . De cette façon, il n'y aura pas besoin de
verrou. Mais je ne connais peut-être pas les spécificités 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 était préoccupé par la
chaîne de contrôle.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. Semble suspect. Examinons de près le fragment de code ci-dessus. Je ne l'ai pas délibérément réduit pour mieux comprendre la situation. Ainsi, dans la première instruction
if (et également dans la suivante), la variable
specifiedIndexName est en quelque sorte vérifiée. En fonction des résultats des vérifications, la variable
inferredIndexName obtient une nouvelle valeur. Examinons maintenant la troisième instruction
if . Le corps de cette instruction (levée de l'exception) sera exécuté au cas où
indexNames.Count> 0, comme première partie de la condition entière, qui est
string.IsNullOrEmpty (inferredIndexName) est toujours vrai. Peut-être que les variables
specifiedIndexName et
inferredIndexName sont mélangées ou que la troisième vérification 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 pour corriger ce code. Quoi qu'il en soit, l'auteur doit le vérifier.
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)
C'est un classique. La variable
conditionValues est utilisée sans vérification préalable de
null . Plus tard dans le code, cette vérification est effectuée. Le code doit ê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) { .... } .... } }
J'ai trouvé plusieurs erreurs similaires 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 le cas est opposé à celui discuté 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 comprend la vérification de la valeur de la variable d'
état pour
null . Dans le code ci-dessous, la variable est utilisée pour se désinscrire de l'événement
PreemptExpiryTime , cependant, une vérification de
null n'est plus effectuée et le lancement de l'exception
NullReferenceException devient possible. Une version plus sécurisée du code:
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; .... }
Dans le code, il existe d'autres erreurs similaires:
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
Réalité non alternativeAvertissement 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 c'est critique pour le code appelant. J'ai vérifié les cas d'utilisation de la méthode
State19 . Il est impliqué dans le remplissage du tableau de gestionnaires
fsm_handler_table également avec d'autres méthodes similaires (il y en a 28 avec les noms, respectivement, en commençant par
State1 à
State28 ). Ici, il est important de noter qu'en plus de
State19 , pour certains autres gestionnaires, les avertissements
V3009 [CWE-393] ont également été émis. Ce sont des gestionnaires:
State23, State26, State27, State28 . Les avertissements, émis 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 ressemblent la déclaration et l'initialisation du tableau des 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 compléter l'image, voyons le code de l'un des gestionnaires pour lesquels l'analyseur n'a eu aucune revendication, par exemple,
State2 :
private static bool State2 (....) { .... if (....) { return true; } switch (....) { .... default: return false; } }
Voici comment l'appel des gestionnaires se produit:
public bool NextToken () { .... while (true) { handler = fsm_handler_table[state - 1]; if (! handler (fsm_context))
Comme nous pouvons le voir, une exception sera levée en cas de retour
faux . Dans notre cas, pour les gestionnaires
State19, State23, State26 State27 et
State28, cela ne se produira jamais. Semble suspect. D'un autre côté, cinq gestionnaires ont un comportement similaire (retourneront toujours
vrai ), alors peut-être que c'était tellement artificiel et n'est pas le résultat d'une faute de frappe.
Pourquoi vais-je si profondément dans tout cela? Cette situation est très significative dans le sens où l'analyseur statique ne peut souvent indiquer qu'une construction suspecte. Et même une personne (pas une machine), qui n'a pas suffisamment de connaissances sur le projet, n'est toujours pas en mesure de donner une réponse complète sur la présence de l'erreur, même après avoir passé du temps à apprendre le code. Un développeur doit revoir ce code.
Des contrôles sans significationAvertissement 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 la
fausse valeur, cette variable obtiendra la
vraie valeur dans tous les cas plus loin dans le code. Par conséquent, la vérification
si (doLog) est toujours vraie. Peut-être, plus tôt dans la méthode, il y avait une branche, dans laquelle la variable
doLog n'avait reçu aucune valeur. Au moment de la vérification, il pourrait contenir la
fausse valeur reçue lors de l'initialisation. Mais maintenant, il n'y a pas une telle 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
true dans toutes les conditions. 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 cherchais d'autres bogues
V3009 et l'ai enregistré pour ce cas. Ainsi, l'outil a eu raison de signaler 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 ||
Le champ
this.token est comparé deux fois avec la valeur
JsonToken.String de l'énumération
JsonToken . Probablement, l'une des comparaisons devrait contenir une autre valeur d'énumération. Si c'est le cas, une grave erreur a été commise ici.
Refactorisation + inattention?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)); } .... }
Peut-être que la chaîne de format de la méthode
string.Format contenait précédemment l'élément de format
{0}, pour lequel l'argument
AWSConfigs.AWSRegionKey a été défini. Ensuite, la chaîne a été modifiée, l'élément de format a disparu, mais un développeur a oublié de supprimer l'argument. L'exemple de code donné fonctionne sans erreur (l'exception a été levée dans le cas contraire - l'élément de format sans l'argument), mais il n'a pas l'air sympa. Le code doit être corrigé 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 courante d'un appel non sécurisé du gestionnaire d'événements. Un utilisateur peut se désinscrire entre la vérification de la variable
mOnSyncSuccess pour
null et l'appel d'un gestionnaire, de sorte que 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)); }
Dans le code, il existe d'autres erreurs similaires:
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 bruteAvertissement 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 pas mal de code, donc je ne l'ai pas donné en entier, en ne citant que sa déclaration. Cette classe ne contient vraiment pas la méthode substituée
GetHashCode, qui n'est pas sûre, car elle peut conduire à un comportement erroné lors de l'utilisation du type
JsonData pour travailler, par exemple, avec des collections. Il n'y a probablement pas de problème pour le moment, mais à l'avenir ce type de stratégie pourrait changer. Cette erreur est décrite plus en détail dans la
documentation .
ConclusionCe sont tous des bogues intéressants que j'ai pu détecter dans le code du kit AWS SDK pour .NET en utilisant l'analyseur statique PVS-Studio. Je voudrais souligner encore une fois la qualité du projet. J'ai trouvé un très petit nombre d'erreurs pour 5 millions de lignes de code. Bien qu'une analyse probablement plus approfondie des avertissements émis me permette d'ajouter quelques erreurs supplémentaires à cette liste. Néanmoins, il est également très probable que j'ai ajouté certains des avertissements aux erreurs pour rien. Dans ce cas, les conclusions non ambiguës sont toujours faites uniquement par un développeur qui se trouve dans le contexte du code vérifié.