SARIF SDK及其错误

Picture 2

SARIF originated at Microsoft and is now a standard developed by OASIS (a non-profit consortium that deals with open standards). SARIF is meant to pass not only the results of the analyzer, but also metadata about the tool, as well as data on how it was launched, time tags, and so on. For more information, visit the OASIS website. The source code of SARIF SDK can be downloaded from the repository on GiHub. The project's homepage is available by link.

SARIF起源于Microsoft,现在是OASIS(处理开放标准的非营利性联盟)开发的标准。 SARIF不仅要传递分析器的结果,而且还要传递有关该工具的元数据,以及有关其启动方式,时间标签等的数据。 有关更多信息,请访问OASIS网站。 可以从GiHub上的存储库下载SARIF SDK的源代码。 通过链接可访问该项目的主页。

关于该项目 (About the project)

The SARIF SDK project turned out to be small: 799 .cs files (approximately 98,000 non-empty lines of code). The project contains tests that I always exclude from the check. Thus, the part of the code we were interested in was 642 .cs files (approximately 79,000 non-empty lines of code). It's certainly not enough. On the plus side, the check and analysis were easy and fast, between this and then, which I tried to reflect on the picture at the beginning. Nonetheless, I managed to track down some uncanny cases. Let's have a look at them.

SARIF SDK项目原来很小:799个.cs文件(大约98,000个非空代码行)。 该项目包含我总是从检查中排除的测试。 因此,我们感兴趣的部分代码是642个.cs文件(大约79,000个非空代码行)。 当然还不够。 从好的方面来说,从那时开始到那时,检查和分析都非常简单快捷,我一开始就试图在图片上反映出来。 尽管如此,我还是设法找到了一些不可思议的案件。 让我们看看它们。

失误 (Errors)

V3070 [CWE-457] Uninitialized variable 'Binary' is used when initializing the 'Default' variable. MimeType.cs 90 V3070 [CWE-457]初始化“默认”变量时,使用未初始化的变量“二进制”。 MimeType.cs 90
public static class MimeType
{
  ....
  /// <summary>The MIME type to use when no better MIME type is known.</summary>
  public static readonly string Default = Binary;
  ....
  /// <summary>The MIME type for binaries.</summary>
  public static readonly string Binary = "application/octet-stream";
  ....
}

The field is initialized by the value of another field, which hasn't received a value yet. As a result, Default will receive the null value by default for the string type. Most likely, the error remained unnoticed, as the Default field isn't used anywhere. But things can change, and then the developer will face an undue result or the program crash.

该字段由另一个尚未接收到值的字段初始化。 结果, 默认情况下, 默认将为字符串类型接收空值。 由于“ 默认”字段未在任何地方使用,因此该错误很可能未被注意到。 但是事情可能会改变,然后开发人员将面临不适当的结果或程序崩溃。

V3061 Parameter 'logicalLocationToIndexMap' is always rewritten in method body before being used. PrereleaseCompatibilityTransformer.cs 1963 V3061参数'logicalLocationToIndexMap'始终在使用前在方法主体中重写。 PrereleaseCompatibilityTransformer.cs 1963
private static JArray ConvertLogicalLocationsDictionaryToArray(
  ....
  Dictionary<LogicalLocation, int> logicalLocationToIndexMap,
  ....)
{
  ....
  logicalLocationToIndexMap =
    new Dictionary<LogicalLocation, int>(LogicalLocation.ValueComparer);
  ....
}

The code author doesn't use the logicalLocationToIndexMap parameter in any way, but writes a different value in it. Curiously enough, the previous value is exactly the same empty dictionary, created in the caller code:

代码作者不以任何方式使用logicalLocationToIndexMap参数,而是在其中写入一个不同的值。 奇怪的是,先前的值与在调用者代码中创建的空字典完全相同:

private static bool ApplyChangesFromTC25ThroughTC30(....)
{
  ....
  Dictionary<LogicalLocation, int> logicalLocationToIndexMap = null;
  ....
  logicalLocationToIndexMap =
    new Dictionary<LogicalLocation, int>(LogicalLocation.ValueComparer);

  run["logicalLocations"] =
    ConvertLogicalLocationsDictionaryToArray(
      ....,
      logicalLocationToIndexMap,
      ....);
}

Weird and suspicious code.

奇怪而可疑的代码。

V3008 [CWE-563] The 'run.Tool' variable is assigned values twice successively. Perhaps this is a mistake. Check lines: 116, 114. ExportRulesMetadataCommandBase.cs 116 V3008 [CWE-563]连续两次给'run.Tool'变量赋值两次。 也许这是一个错误。 检查行:116,114。ExportRulesMetadataCommandBase.cs 116
public partial class Run
{
  ....
  public Tool Tool { get; set; }
  ....
}

public partial class Tool : ....
{
  ....
  public Tool()
  {
  }
  ....
}

private void OutputSarifRulesMetada(....)
{
  ....
  var run = new Run();
  run.Tool = new Tool();

  run.Tool = Tool.CreateFromAssemblyData(....);  // <=
  ....
}

The run.Tool property is assigned a value twice. Both when creating the Tool object and when writing a value in the Tool property, no additional work is required. Therefore, reassigning smells fishy.

run.Tool属性分配了两次值。 在创建Tool对象和在Tool属性中写入值时,都不需要其他工作。 因此,重新分配闻起来很腥。

V3042 [CWE-476] Possible NullReferenceException. The '?.' and '.' operators are used for accessing members of the 'loc' object WhereComparer.cs 152 V3042 [CWE-476]可能为NullReferenceException。 '?。' 和“。” 运算符用于访问“ loc”对象的成员WhereComparer.cs 152
private static Uri ArtifactUri(ArtifactLocation loc, Run run)
{
  return loc?.Uri ?? loc.Resolve(run)?.Uri;
}

If the value of the loc variable is null, an attempt will be made to return the value from the right part of the ?? operator, resulting in the access by null reference.

如果loc变量的值为null ,则将尝试从??的右侧返回该值。 运算符,导致通过空引用进行访问。

V3042 [CWE-476] Possible NullReferenceException. The '?.' and '.' operators are used for accessing members of the 'formatString' object InsertOptionalDataVisitor.cs 194 V3042 [CWE-476]可能为NullReferenceException。 '?。' 和“。” 运算符用于访问'formatString'对象的成员InsertOptionalDataVisitor.cs 194
public override Message VisitMessage(Message node)
{
  ....
  node.Text = node.Arguments?.Count > 0
    ? string.Format(...., formatString.Text, ....)
    : formatString?.Text;
  ....
}

Developers use unsecure and secure access variants by a potentially null formatString reference in two parallel branches of the conditional ?: operator.

开发人员通过条件?:运算符的两个并行分支中可能为空的formatString引用来使用不安全和安全的访问变体。

V3042 [CWE-476] Possible NullReferenceException. The '?.' and '.' operators are used for accessing members of the 'messageText' object FortifyFprConverter.cs 1210 V3042 [CWE-476]可能为NullReferenceException。 '?。' 和“。” 运算符用于访问“ messageText”对象FortifyFprConverter.cs 1210的成员 V3042 [CWE-476] Possible NullReferenceException. The '?.' and '.' operators are used for accessing members of the 'messageText' object FortifyFprConverter.cs 1216 V3042 [CWE-476]可能为NullReferenceException。 '?。' 和“。” 运算符用于访问“ messageText”对象FortifyFprConverter.cs 1216的成员
private void AddMessagesToResult(Result result)
{
  ....
  string messageText = (rule.ShortDescription ?? rule.FullDescription)?.Text;
  ....
  if (....)
  {
      // Replace the token with an embedded hyperlink.
      messageText = messageText.Replace(....);
  }
  else
  {
      // Replace the token with plain text.
      messageText = messageText.Replace(....);
  }
  ....
}

Here the analyzer issued already two warnings about possible access by the null messageText reference. It looks rather nonthreatening, but it's still an error.

在此,分析器已经发出了两个有关通过null messageText引用进行可能访问的警告。 它看起来没有威胁,但仍然是一个错误。

V3080 [CWE-476] Possible null dereference. Consider inspecting 'fileDataVersionOne.Uri'. SarifCurrentToVersionOneVisitor.cs 1030 V3080 [CWE-476]可能的空解除引用。 考虑检查“ fileDataVersionOne.Uri”。 SarifCurrentToVersionOneVisitor.cs 1030
private IDictionary<string, FileDataVersionOne>
  CreateFileDataVersionOneDictionary()
{
  ....
  FileDataVersionOne fileDataVersionOne = CreateFileDataVersionOne(v2File);

  if (fileDataVersionOne.Uri.OriginalString.Equals(key))
  {
    ....
  }
  ....
}

The analyzer suspected that NullReferenceException is possible when working with the fileDataVersionOne.Uri reference. Let's see where this variable comes from and find out if the analyzer is right. To do this, let's take a close look at the body of the CreateFileDataVersionOne method:

分析器怀疑使用fileDataVersionOne.Uri引用时可能会出现NullReferenceException 。 让我们看看该变量来自何处,并找出分析仪是否正确。 为此,让我们仔细看一下CreateFileDataVersionOne方法的主体:

private FileDataVersionOne CreateFileDataVersionOne(Artifact v2FileData)
{  
  FileDataVersionOne fileData = null;

  if (v2FileData != null)
  {
    ....
    fileData = new FileDataVersionOne
    {
      ....
      Uri = v2FileData.Location?.Uri,
      ....
    };
    ....
  }

  return fileData;
}

public partial class FileDataVersionOne
{
  ....
  public Uri Uri { get; set; }
  ....
}

Indeed, when creating the object of the FileDataVersionOne class, the Uri property might receive the null value. This is a great example data flow analysis and interprocedural analysis mechanisms working together.

确实,当创建FileDataVersionOne类的对象时, Uri属性可能会收到值。 这是数据流分析和过程间分析机制协同工作的一个很好的例子。

V3080 [CWE-476] Possible null dereference. Consider inspecting '_jsonTextWriter'. SarifLogger.cs 242 V3080 [CWE-476]可能的空解除引用。 考虑检查“ _jsonTextWriter”。 SarifLogger.cs 242
public virtual void Dispose()
{
  ....
  if (_closeWriterOnDispose)
  {
    if (_textWriter != null) { _textWriter.Dispose(); }
    if (_jsonTextWriter == null) { _jsonTextWriter.Close(); }  // <=
  }
  ....
}

There's a typo in this fragment. It's clear that _jsonTextWriter != null has to be in the condition of the second block. This piece of code is jeopardizing as, most likely, it doesn't crash, due to _jsonTextWriter being nonnull. Besides, the stream remains open.

这个片段中有错别字。 显然_jsonTextWriter!= null必须处于第二个块的条件下。 这段代码被破坏的,最有可能的,它不会崩溃,因为_jsonTextWriter成为非空 。 此外,流保持开放。

V3083 [CWE-367] Unsafe invocation of event 'RuleRead', NullReferenceException is possible. Consider assigning event to a local variable before invoking it. FxCopConverter.cs 897 V3083 [CWE-367]事件'RuleRead'的不安全调用,可能会发生NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 FxCopConverter.cs 897
private void ReadRule(....)
{
  ....
  if (RuleRead != null)
  {
    RuleRead(....);
  }
  ....
}

Events are handled unsafely. It's an uncritical bug that can be easily fixed, for example, by following the Visual Studio tip. Here's the replacement suggested by the IDE:

事件处理不安全。 这是一个非关键错误,可以通过例如Visual Studio技巧轻松修复。 这是IDE建议的替代品:

private void ReadRule(....)
{
  ....
  RuleRead?.Invoke(....);
  ....
}

It takes only a few seconds to fix it, but the analyzer will no longer complain about it and the IDE won't highlight the code. Another similar error.

只需几秒钟即可修复它,但分析器将不再抱怨它,并且IDE不会突出显示该代码。 另一个类似的错误。

  • V3083 [CWE-367] Unsafe invocation of event 'ResultRead', NullReferenceException is possible. Consider assigning event to a local variable before invoking it. FxCopConverter.cs 813

    V3083 [CWE-367]事件'ResultRead'的不安全调用,可能会发生NullReferenceException。 请考虑在调用事件之前将事件分配给局部变量。 FxCopConverter.cs 813
V3095 [CWE-476] The 'v1Location' object was used before it was verified against null. Check lines: 333, 335. SarifVersionOneToCurrentVisitor.cs 333 V3095 [CWE-476]在验证是否为null之前使用了“ v1Location”对象。 检查行:333、335。SarifVersionOneToCurrentVisitor.cs 333
internal Location CreateLocation(LocationVersionOne v1Location)
{
  ....
  string key = v1Location.LogicalLocationKey ??
                v1Location.FullyQualifiedLogicalName;

  if (v1Location != null)
  {
    ....
  }
  ....
}

The author thought that the v1Location reference may be null and added an appropriate check. Whereas above we can see that this reference is handled without any checks. Inattentive refactoring? Well, you never know.

作者认为v1Location引用可能为空,并添加了适当的检查。 鉴于以上内容,我们可以看到此引用未经任何检查即可处理。 细心的重构? 好吧,你永远不会知道。

V3125 [CWE-476] The 'v1StackFrame' object was used after it was verified against null. Check lines: 1182, 1171. SarifVersionOneToCurrentVisitor.cs 1182 V3125 [CWE-476]在验证了null之后使用了“ v1StackFrame”对象。 检查行:1182,1171。SarifVersionOneToCurrentVisitor.cs 1182
internal StackFrame CreateStackFrame(StackFrameVersionOne v1StackFrame)
{
  StackFrame stackFrame = null;

  if (v1StackFrame != null)
  {
    stackFrame = new StackFrame
    {
      ....
    };
  }

  stackFrame.Location =
    CreateLocation(v1StackFrame.FullyQualifiedLogicalName,
                   v1StackFrame.LogicalLocationKey,
                   ....);

  return stackFrame;
}

As always, here comes a reverse case. First the v1StackFrame reference is checked for null, and then the check is gone astray. But this case has an important caveat: v1StackFrame and stackFrame variables are logically related. See, if v1StackFrame is null, the StackFrame object won't be created, whereas stackFrame will remain null. Followed by the program crash due to a call of stackFrame.Location, as there are no checks here. So it won't even come to the dangerous v1StackFrame usage, indicated by the analyzer. This code only works if you pass nonnull v1StackFrame values to the CreateStackFrame method. I suspected that the caller code somehow controls it. CreateStackFrame callslook like this:

与往常一样,情况相反。 首先,检查v1StackFrame引用是否为null ,然后将该检查误入歧途。 但是这种情况有一个重要的警告: v1StackFramestackFrame变量在逻辑上是相关的。 请参阅,如果v1StackFramenull ,则不会创建StackFrame对象,而stackFrame将保持为null。 随后由于调用stackFrame.Location而导致程序崩溃,因为此处没有检查。 因此,它甚至不会涉及分析器指出的危险的v1StackFrame使用情况。 仅当将非空v1StackFrame值传递给CreateStackFrame方法时,此代码才有效。 我怀疑调用者代码以某种方式控制了它。 CreateStackFrame调用看起来像这样:

Frames = v1Stack.Frames?.Select(CreateStackFrame).ToList()
CreateStackFrame is used as a selector. Passed references aren't checked for CreateStackFrame用作选择器。 此处不检查传递的引用是否为 null here. Perhaps, when filling the null 。 也许,在填充 Frames collection it (writing of null references) is controlled, but I didn't go for digging too deep. The conclusion is already obvious — the code requires authors' attention. Frames集合时,它(写空引用)受到控制,但是我并没有进行过深入的研究。 结论已经很明显了-该代码需要作者的注意。

结论 (Conclusion)

As you see, the article isn't long but I hope you enjoyed this light reading :) Just in case, that you can always download our analyzer to search for errors in your or someone's projects yourself.

如您所见,这篇文章并不长,但是我希望您喜欢这篇轻松的读物:)以防万一,您可以随时下载我们的分析器来自己或他人的项目中搜索错误。

And finally, a small announcement: my next article will be about the most interesting errors that my colleagues and I found in projects in 2019. Follow our blog. See you!

最后,小宣布:我的下一篇文章将有约最有趣的错误,我和我的同事在项目发现,在2019年按照我们的博客 。 再见!

To learn more about new blog posts, you are welcome to subscribe to the following channels:

要了解有关新博客文章的更多信息,欢迎您订阅以下频道:

翻译自: https://habr.com/en/company/pvs-studio/blog/479480/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值