在Amazon Web Services SDK for .NET源代码中寻找错误

图片1


向所有批评他人代码的粉丝致以问候。 :)今天,在我们的实验室中,新的研究材料是.NET的AWS开发工具包项目的源代码。 一次,我们写了一篇关于检查适用于C ++的AWS开发工具包的文章。 然后,没有什么特别有趣的。 让我们看看AWS SDK的.NET版本如何取悦我们。 这是再次展示PVS-Studio分析仪功能以及使世界变得更加完美的好机会。

亚马逊网络服务(AWS).NET SDK是一个开发人员工具包,旨在在AWS基础设施中创建基于.NET的应用程序,并大大简化了编写代码的过程。 该SDK包含适用于各种AWS服务的.NET API套件,例如Amazon S3,Amazon EC2,DynamoDB等。 SDK的源代码托管在GitHub上

正如我所说,有一次我们撰写了一篇有关检查适用于C ++的AWS开发工具包的文章 。 文章的篇幅很小-在512万行代码中仅发现512个错误。 这次,我们要处理的代码量要大得多,其中包括约3.4万个cs文件,并且代码行的总数(不包括空行)是令人印象深刻的500万。 一小部分代码(664个cs文件中的20万行)落在测试中,我没有考虑它们。

如果SDK版本的.NET代码的质量与C ++的质量大致相同(每512 KLOC出现两个错误),那么我们应该得到的错误大约多10倍。 当然,这是一种非常不准确的计算方法,没有考虑语言功能和许多其他因素,但我认为读者现在不想钻研无聊的讨论。 相反,我建议直接得出结果。

使用PVS-Studio版本6.27进行验证。 令人难以置信的是,该分析器能够检测到适用于.NET代码的AWS开发工具包中约40个值得一提的错误。 这不仅表明SDK代码的质量很高(每512 KLOC大约有4个错误),而且表明PVS-Studio分析仪的C#工作质量与C ++相当。 好结果!

适用于.NET的AWS开发工具包的作者很棒。 从一个项目到另一个项目,它们展示了惊人的代码质量。 这可以作为其他团队的榜样。 但是,如果我没有插入5个戈比,我当然不会成为静态分析器的开发人员。 :)我们已经与Amazon Lumberyard团队合作使用PVS-Studio。 但是由于这是一家非常庞大的公司,在世界各地都有许多分支机构,因此适用于.NET的AWS开发工具包很可能根本没有听说过PVS-Studio。 无论如何,在SDK代码中我都没有发现使用分析仪的任何迹象,尽管这并不意味着任何事情。 但是,团队至少要使用 Visual Studio内置分析器。 这很好,但是可以增强代码检查:)。

结果,我仍然设法在SDK代码中找到了一些错误,最后是时候分享这些错误了。

逻辑错误

PVS-Studio警告: V3008 [CWE-563]连续两次为'this.linker.s3.region'变量分配值。 也许这是一个错误。 检查行: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; } } 

分析器警告重新分配相同变量的值。 从代码中可以清楚地看出,这是由于违反操作逻辑的错误引起的: this.linker.s3.region变量的值始终等于value ,而不管if条件(String.IsNullOrEmpty(value))如何 。 在if块的主体中​​, return被跳过。 该代码需要固定如下:

 public string Region { get { .... } set { if (String.IsNullOrEmpty(value)) { this.linker.s3.region = "us-east-1"; return; } this.linker.s3.region = value; } } 

无限递归

PVS-Studio警告: V3110 [CWE-674]'OnFailure'属性内可能无限递归。 AWSSDK.ElasticMapReduce.Net45 ResizeJobFlowStep.cs 171

 OnFailure? onFailure = null; public OnFailure? OnFailure { get { return this.OnFailure; } // <= set { this.onFailure = value; } } 

一个经典的错字示例,该示例在OnFailure属性的get 访问器中导致无限递归。 代替返回私有字段的值, onFailure引用OnFailure属性。 更正的选项:

 public OnFailure? OnFailure { get { return this.onFailure; } set { this.onFailure = value; } } 

您问:“它是如何工作的?” 到目前为止,没有办法。 该属性未在任何地方使用,但它是临时的。 某个时候,有人会开始使用它,肯定会得到意想不到的结果。 为避免出现此类拼写错误,建议不要使用仅在首字母大写不同的标识符。

此设计的另一个注意事项是使用与OnFailure类型的名称完全匹配的标识符。 从编译器的角度来看,这是完全可以接受的,但是它使人们对代码的理解更加困难。

另一个类似的错误:

PVS-Studio警告: V3110 [CWE-674]'SSES3'属性内可能存在无限递归。 AWSSDK.S3.Net45 InventoryEncryption.cs 37

 private SSES3 sSES3; public SSES3 SSES3 { get { return this.SSES3; } set { this.SSES3 = value; } } 

这种情况与上述情况相同。 仅在这里,访问SSES3属性进行读取和写入时将发生无限递归。 更正的选项:

 public SSES3 SSES3 { get { return this.sSES3; } set { this.sSES3 = value; } } 

正念测试

以下是热衷于使用“复制粘贴”技术的程序员的任务。 查看代码在Visual Studio编辑器中的外观,然后尝试查找错误。

图片3


PVS-Studio警告: V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:91,95。AWSSDK.AppSync.Net45 CreateApiKeyResponseUnmarshaller.cs 91

我减少了UnmarshallException方法的主体,删除了所有不必要的部分。 现在您可以看到相同的检查接连进行:

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

似乎该错误不是严重的-只是一个额外的检查。 但是,当不执行某些必要的检查时,这种模式通常可以指示代码中更严重的问题。

代码中还有更多类似的错误。

PVS-Studio警告:

  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:75、79。AWSSDK.CloudDirectory.Net45 CreateSchemaResponseUnmarshaller.cs 75
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:105、109。AWSSDK.CloudDirectory.Net45 GetSchemaAsJsonResponseUnmarshaller.cs 105
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:201、205。AWSSDK.CodeCommit.Net45 PostCommentForPullRequestResponseUnmarshaller.cs 201
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:101,105。AWSSDK.CognitoIdentityProvider.Net45 VerifySoftwareTokenResponseUnmarshaller.cs 101
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:72,76。AWSSDK.Glue.Net45 UpdateConnectionResponseUnmarshaller.cs 72
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:123、127。AWSSDK.Neptune.Net45 RestoreDBClusterFromSnapshotResponseUnmarshaller.cs 123
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:167、171。AWSSDK.Neptune.Net45 RestoreDBClusterFromSnapshotResponseUnmarshaller.cs 167
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:127,131。AWSSDK.RDS.Net45 RestoreDBClusterFromSnapshotResponseUnmarshaller.cs 127
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:171、175。AWSSDK.RDS.Net45 RestoreDBClusterFromSnapshotResponseUnmarshaller.cs 171
  • V3029彼此并排放置的'if'语句的条件表达式相同。 检查行:99、103。AWSSDK.Rekognition.Net45 RecognizeCelebritiesResponseUnmarshaller.cs 99

你是什​​么

PVS-Studio警告: V3062对象“ attributeName”用作其自身方法的参数。 考虑检查“包含”方法的第一个实际参数。 AWSSDK.MobileAnalytics.Net45 CustomEvent.cs 261

 /// <summary> /// Dictionary that stores attribute for this event only. /// </summary> private Dictionary<string,string> _attributes = new Dictionary<string,string>(); /// <summary> /// Gets the attribute. /// </summary> /// <param name="attributeName">Attribute name.</param> /// <returns>The attribute. Return null of attribute doesn't /// exist.</returns> public string GetAttribute(string attributeName) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } string ret = null; lock(_lock) { if(attributeName.Contains(attributeName)) // <= ret = _attributes[attributeName]; } return ret; } 

分析器在GetAttribute方法中检测到错误:检查字符串是否包含字符串本身。 从方法的描述中可以得出结论,如果(在_attributes字典中)找到了属性名称( attributeName键),则应返回属性值,否则返回null 。 实际上,由于条件attributeName.Contains(attributeName)始终为true,因此尝试通过可能在字典中找不到的键返回值。 然后,将抛出KeyNotFoundException而不是返回null

让我们尝试修复此代码。 为了更好地了解如何执行此操作,请查看另一种方法:

 /// <summary> /// Determines whether this instance has attribute the specified /// attributeName. /// </summary> /// <param name="attributeName">Attribute name.</param> /// <returns>Return true if the event has the attribute, else /// false.</returns> public bool HasAttribute(string attributeName) { if(string.IsNullOrEmpty(attributeName)) { throw new ArgumentNullException("attributeName"); } bool ret = false; lock(_lock) { ret = _attributes.ContainsKey(attributeName); } return ret; } 

此方法检查_attributes词典中是否存在属性名称( attributeName键)。 让我们回到GetAttribute方法并修复错误:

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

现在,该方法完全可以执行描述中所述的操作。

并对此代码片段再做一个小小的评论。 我注意到作者在使用_attributes字典时会使用 。 显然,这对于多线程访问是必需的,但是构造相当缓慢且麻烦。 在这种情况下,可以使用字典的线程安全版本-ConcurrentDictionary代替字典 ,这样更方便。 然后,对的需求就消失了。 虽然,也许我不知道该项目的任何功能。

可疑行为

PVS-Studio警告: V3063 [CWE-571]如果对条件表达式进行评估,则该条件表达式的一部分始终为true: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) && // <= indexNames.Count > 0) throw new InvalidOperationException("Local Secondary Index range key conditions are used but no index could be inferred from model. Specified index name = " + specifiedIndexName); .... } 

分析器警告了该字符串。IsNullOrEmpty(inferredIndexName)检查。 确实,为字符串inferredIndexName分配了null ,然后此变量的值未在任何地方更改,然后出于某种原因检查了它是否为null或空字符串。 看起来可疑。 让我们仔细看一下给定的代码片段。 我故意没有减少它以更好地了解情况。 因此,在第一个if语句中 (以及在下一个if语句中),以某种方式检查了namedIndexName变量。 根据检查结果,变量inferredIndexName会收到一个新值。 现在让我们注意第三个if语句 。 如果indexNames.Count> 0 ,则将执行该语句的主体(引发异常),因为条件的第一部分是string.IsNullOrEmpty( inferredIndexName 始终为true。 也许对变量namedIndexNameinferredIndexName只是简单地混淆了。 或第三次检查应该没有其他内容 ,代表独立的if语句

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

在这种情况下,很难给出关于修复此代码的选项的明确答案。 但是作者肯定有必要对其进行检查。

NullReferenceException

PVS-Studio警告: V3095 [CWE-476]在对空值进行验证之前使用了“ conditionValues”对象。 检查行:228、238。AWSSDK.Core.Net45 JsonPolicyWriter.cs 228

 private static void writeConditions(....) { .... foreach (....) { IList<string> conditionValues = keyEntry.Value; if (conditionValues.Count == 0) // <= continue; .... if (conditionValues != null && conditionValues.Count != 0) { .... } .... } } 

该流派的经典作品。 使用变量conditionValues时,无需先检查null 。 而且,在代码中进一步执行了这种验证,但是为时已晚。 :)

该代码可以固定如下:

 private static void writeConditions(....) { .... foreach (....) { IList<string> conditionValues = keyEntry.Value; if (conditionValues != null && conditionValues.Count == 0) continue; .... if (conditionValues != null && conditionValues.Count != 0) { .... } .... } } 

在代码中发现了更多类似的错误。

PVS-Studio警告:

  • V3095 [CWE-476]在验证是否为null之前使用了“ ts.Listeners”对象。 检查行:140,143。AWSSDK.Core.Net45 Logger.Diagnostic.cs 140
  • V3095 [CWE-476]在验证是否为null之前,已使用'obj'对象。 检查行:743、745。AWSSDK.Core.Net45 JsonMapper.cs 743
  • V3095 [CWE-476]在对null进行验证之前,已使用'multipartUploadMultipartUploadpartsList'对象。 检查行:65,67。AWSSDK.S3.Net45 CompleteMultipartUploadRequestMarshaller.cs 65

以下警告的含义非常相似,但情况与上述警告相反。

PVS-Studio警告: V3125 [CWE-476]在验证为空后使用了“状态”对象。 检查行: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; // <= .... } 

其中一个代码段包含一个检查状态变量值是否等于null的检查 。 此外,根据代码, 状态变量用于退订PreemptExpiryTime事件,并且不再检查null是否相等,并且NullReferenceException是可能的 。 更安全的代码选项:

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

代码中还有其他类似的错误。

PVS-Studio警告:

  • V3125 [CWE-476]在针对null验证了'wrappedRequest.Content'对象之后,使用了该对象。 检查行:395、383。AWSSDK.Core.Net45 HttpHandler.cs 395
  • V3125 [CWE-476]在对null进行验证之后,使用了“ datasetUpdates”对象。 检查行:477、437。AWSSDK.CognitoSync.Net45 Dataset.cs 477
  • V3125 [CWE-476]在对null进行验证之后,使用了'cORSConfigurationCORSConfigurationcORSRulesListValue'对象。 检查行:125、111。AWSSDK.S3.Net45 PutCORSConfigurationRequestMarshaller.cs 125
  • V3125 [CWE-476]在对null进行验证之后,使用了'lifecycleConfigurationLifecycleConfigurationrulesListValue'对象。 检查行:157,68。AWSSDK.S3.Net45 PutLifecycleConfigurationRequestMarshaller.cs 157
  • V3125 [CWE-476]在验证了null之后使用了“ this.Key”对象。 检查行:199、183。AWSSDK.S3.Net45 S3PostUploadRequest.cs 199

无可争议的现实

PVS-Studio警告: V3009 [CWE-393]奇怪的是,此方法始终返回一个相同的'true'值。 AWSSDK.Core.Net45 Lexer.cs 651

 private static bool State19 (....) { while (....) { switch (....) { case '"': .... return true; case '\\': .... return true; default: .... continue; } } return true; } 

该方法始终返回true 。 让我们看看这对于调用代码有多重要。 我跟踪了State19方法的使用。 他参与填充fsm_handler_table处理程序数组以及其他类似方法(从State1State28分别有28个其名称)。 在此必须注意,除了State19之外 ,还向其他一些处理程序发出了警告V3009 [CWE-393]。 这些是处理程序: State23,State26,State27,State28 。 分析仪为其发出的警报:

  • V3009 [CWE-393]奇怪的是,此方法始终返回一个相同的“ true”值。 AWSSDK.Core.Net45 Lexer.cs 752
  • V3009 [CWE-393]奇怪的是,此方法始终返回一个相同的“ true”值。 AWSSDK.Core.Net45 Lexer.cs 810
  • V3009 [CWE-393]奇怪的是,此方法始终返回一个相同的“ true”值。 AWSSDK.Core.Net45 Lexer.cs 822
  • V3009 [CWE-393]奇怪的是,此方法始终返回一个相同的“ true”值。 AWSSDK.Core.Net45 Lexer.cs 834

处理程序数组的声明和初始化如下所示:

 private static StateHandler[] fsm_handler_table; .... private static void PopulateFsmTables () { fsm_handler_table = new StateHandler[28] { State1, State2, .... State19, .... State23, .... State26, State27, State28 }; 

为了完整起见,让我们看一下其中一个处理程序的代码,分析器对此没有任何抱怨,例如State2

 private static bool State2 (....) { .... if (....) { return true; } switch (....) { .... default: return false; } } 

这就是处理程序的调用方式:

 public bool NextToken () { .... while (true) { handler = fsm_handler_table[state - 1]; if (! handler (fsm_context)) // <= throw new JsonException (input_char); .... } .... } 

如您所见,如果返回false ,则将引发异常。 在我们的案例中,对于处理程序State19,State23,State26,State27State28,这将永远不会发生。 看起来可疑。 另一方面,多达五个处理程序具有相似的行为(总是返回true ),所以这可能是有意的,而不是拼写错误的结果。

为什么我要详细介绍所有这些内容? 从静态分析仪通常只能指示可疑设计的意义上说,这种情况非常有用。 即使是对项目没有足够知识的人(不是机器),花了很多时间研究代码,也仍然无法给出有关错误存在的详尽解答。 该代码必须由开发人员研究。

毫无意义的检查

PVS-Studio警告: V3022 [CWE-571]表达式'doLog'始终为true。 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) // <= { .... } .... } 

注意doLog变量。 在使用false初始化之后,在代码中,此变量在所有情况下都将变为true 。 因此, if(doLog)检查始终为true。 也许在此方法的较早分支中,没有为doLog变量分配任何值,然后在验证时它可能包含初始化期间获得的错误值。 但是现在没有这样的分支。

另一个类似的错误:

PVS-Studio 警告 V3022表达式“!结果”始终为false。 353 AWSSDK.CognitoSync.PCL SQLiteLocalStorage.cs

 public void PutValue(....) { .... bool result = PutValueHelper(....); if (!result) <= { _logger.DebugFormat("{0}", @"Cognito Sync - SQLiteStorage - Put Value Failed"); } else { UpdateLastModifiedTimestamp(....); } .... } 

分析器声称结果变量的值始终为true 。 仅当PutValueHelper方法始终返回true时,才有可能。 看一下这个方法:

 private bool PutValueHelper(....) { .... if (....)) { return true; } if (record == null) { .... return true; } else { .... return true; } } 

实际上,该方法在任何情况下都将返回true 。 此外,分析仪对此方法发出警告。 PVS-Studio警告: V3009 [CWE-393]奇怪的是,此方法始终返回一个相同的'true'值。 SQLiteLocalStorage.cs 1016

在考虑V3009的其他错误时,我特意不提早发出此警告,但我将其保存为这种情况。 因此,分析仪正确地在调用代码中指示错误V3022

复制粘贴。 再来一次

PVS-Studio警告: V3001在'||'的左侧和右侧有相同的子表达式'this.token == JsonToken.String' 操作员。 AWSSDK.Core.Net45 JsonReader.cs 343

 public bool Read() { .... if ( (this.token == JsonToken.ObjectEnd || this.token == JsonToken.ArrayEnd || this.token == JsonToken.String || // <= this.token == JsonToken.Boolean || this.token == JsonToken.Double || this.token == JsonToken.Int || this.token == JsonToken.UInt || this.token == JsonToken.Long || this.token == JsonToken.ULong || this.token == JsonToken.Null || this.token == JsonToken.String // <= )) { .... } .... } 

this.token字段与JsonToken枚举的JsonToken.String值进行双重比较。 比较之一可能包含不同的枚举值。 如果是这样,那么就犯了一个严重的错误。

重构+粗心?

PVS-Studio警告: V3025 [CWE-685]格式错误。 调用“格式”功能时,期望格式项目的数量不同。 未使用的参数: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)); } .... } 

可能是string.Format方法的格式字符串先前包含输出说明符{0} ,已为其设置参数AWSConfigs.AWSRegionKey 。 然后更改了该行,指定符消失了,但是他们忘了删除该参数。 上面的代码片段可以正常工作,没有错误(相反的情况下会引发异常-没有参数的说明符),但是看起来很丑。 该代码应固定如下:

 if (region == null) { throw new InvalidOperationException( "EC2 instance metadata was not available or did not contain region information."); } 

不安全

PVS-Studio警告: V3083 [CWE-367]事件'mOnSyncSuccess'的不安全调用,可能会发生NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.CognitoSync.PCL Dataset.cs 827

 protected void FireSyncSuccessEvent(List<Record> records) { if (mOnSyncSuccess != null) { mOnSyncSuccess(this, new SyncSuccessEventArgs(records)); } } 

对事件处理程序进行不安全调用的一种相当常见的情况。 在检查mOnSyncSuccess变量为null到调用处理程序之间,可以取消订阅事件,其值将变为零。 发生这种情况的可能性很小,但最好使代码更安全:

 protected void FireSyncSuccessEvent(List<Record> records) { mOnSyncSuccess?.Invoke(this, new SyncSuccessEventArgs(records)); } 

代码中还有其他类似的错误。

PVS-Studio警告:

  • V3083 [CWE-367]事件'mOnSyncFailure'的不安全调用,可能会导致NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.CognitoSync.PCL Dataset.cs 839
  • V3083 [CWE-367]事件的不安全调用,可能是NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.Core.PCL AmazonServiceClient.cs 332
  • V3083 [CWE-367]事件的不安全调用,可能是NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.Core.PCL AmazonServiceClient.cs 344
  • V3083 [CWE-367]事件的不安全调用,可能是NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.Core.PCL AmazonServiceClient.cs 357
  • V3083 [CWE-367]事件'mExceptionEvent'的不安全调用,可能为NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 366AWSSDK.Core.PCL AmazonServiceClient.cs
  • V3083 [CWE-367]事件的不安全调用,可能是NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.Core.PCL AmazonWebServiceRequest.cs 78
  • V3083 [CWE-367]事件'OnRead'的不安全调用,可能会发生NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.Core.PCL EventStream.cs 97
  • V3083 [CWE-367]事件的不安全调用,可能是NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.Core.Android NetworkReachability.cs 57
  • V3083 [CWE-367]事件的不安全调用,可能是NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.Core.Android NetworkReachability.cs 94
  • V3083 [CWE-367]事件的不安全调用,可能是NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 AWSSDK.Core.iOS NetworkReachability.cs 54

未完成的课程

PVS-Studio 警告 实现IEquatable <T>接口的V3126类型“ JsonData”不会覆盖“ GetHashCode”方法。 AWSSDK.Core.Net45 JsonData.cs 26

 public class JsonData : IJsonWrapper, IEquatable<JsonData> { .... } 

JsonData类包含许多代码,因此我没有完整介绍它,仅将自己限于声明。 此类确实不包含重写的GetHashCode方法,这是不安全的,因为在使用JsonData类型(例如,与集合一起使用)时,它可能导致错误的行为。 目前可能没有问题,但是使用这种类型的策略将来可能会改变。 该错误在文档中有更详细的描述

结论

这就是我使用PVS-Studio静态分析器设法在适用于.NET的AWS开发工具包代码中检测到的所有有趣的错误。我再次强调项目的质量。我发现500万行代码中的错误很少。尽管可能更全面地分析发出的警告,使我可以在此列表中添加更多错误。但是我也很可能白白地将所描述的某些警告归因于错误。在这种情况下,只有在检查代码上下文中的开发人员始终得出明确的结论。



如果您想与说英语的读者分享这篇文章,请使用以下链接:Sergey Khrenov。在.NET的Amazon Web Services SDK源代码中搜索错误

Source: https://habr.com/ru/post/zh-CN437516/


All Articles