CodeContracts - 误报

发布于 2024-09-14 01:13:26 字数 455 浏览 6 评论 0原文

我刚刚开始在现有的中型项目上尝试 .NET 4 中的 CodeContracts,令我惊讶的是静态检查器向我发出有关以下代码片段的编译时警告:

public class Foo
{
   private readonly List<string> strs = new List<string>();

   public void DoSomething()
   {
       // Compiler warning from the static checker:
       // "requires unproven: source != null"
       strs.Add("hello");
   }
}

Why is the CodeContracts static checker 抱怨关于 strs.Add(...) 行? strs 不可能为空,对吧?我做错了什么吗?

I've just started experimenting with CodeContracts in .NET 4 on an existing medium-sized project, and I'm surprised that the static checker is giving me compile-time warnings about the following piece of code:

public class Foo
{
   private readonly List<string> strs = new List<string>();

   public void DoSomething()
   {
       // Compiler warning from the static checker:
       // "requires unproven: source != null"
       strs.Add("hello");
   }
}

Why is the CodeContracts static checker complaining about the strs.Add(...) line? There's no possible way for strs to be null, right? Am I doing something wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

拧巴小姐 2024-09-21 01:13:26

该字段可能被标记为只读,但不幸的是静态检查器对此不够智能。因此,由于静态检查器无法自行推断 strs 永远不会为 null,因此您必须通过不变量显式地告诉它:

[ContractInvariantMethod]
private void ObjectInvariant() {
    Contract.Invariant(strs != null);
}

The field may be marked readonly, but unfortunately the static checker isn't smart enough for this. Therefore, as the static checker isn't able to infer on its own that strs is never null, you must explicitly tell it through an invariant:

[ContractInvariantMethod]
private void ObjectInvariant() {
    Contract.Invariant(strs != null);
}
最冷一天 2024-09-21 01:13:26

以下是有效的代码,我希望它会生成警告。

public class Foo 
{ 
   private readonly List<string> strs = new List<string>(); 

   public Foo()
   {
       // strs is readonly, so we can assign it here but nowhere else
       strs = ResultOfSomeFunction();
   }

   public void DoSomething() 
   { 
       // Compiler warning from the static checker: 
       // "requires unproven: source != null" 
       strs.Add("hello"); 
   } 
}

他们的分析器很可能无法确保构造函数中没有任何内容会更改 strs 的值。或者也许您正在以某种方式更改构造函数中的 strs 而您没有意识到。

The following is valid code, which I would expect to generate the warning.

public class Foo 
{ 
   private readonly List<string> strs = new List<string>(); 

   public Foo()
   {
       // strs is readonly, so we can assign it here but nowhere else
       strs = ResultOfSomeFunction();
   }

   public void DoSomething() 
   { 
       // Compiler warning from the static checker: 
       // "requires unproven: source != null" 
       strs.Add("hello"); 
   } 
}

It's quite possible that their analyzer doesn't go so far as to make sure that you have nothing in a constructor that changes the value of strs. Or maybe you are somehow changing strs in a constructor and you don't realize it.

吻风 2024-09-21 01:13:26

小修正:Pex 使用 Z3(一种 SMT 求解器),而 Clousot(静态检查器代码名称)使用抽象解释和抽象域。

Little correction: Pex uses Z3, an SMT solver while Clousot (the static checker code name) uses abstract interpretation and abstract domains.

去了角落 2024-09-21 01:13:26

我对 .NET 对象初始化语义的复杂性了解不够,无法回答您的直接问题。不过,这里有两个提示:

  1. Microsoft Research 的 Pex 可以自动生成单元测试,准确演示在什么情况下可能发生违反合同的情况。它使用与 CC 相同的定理证明器和静态分析器,所以这是一个公平的赌注,两者都会同意。
  2. 证明合约相当于解决停止问题,因此仅仅因为 CC 无法证明它永远不会为空,并不意味着它不是真的。 IOW:CC 可能是错误的,您需要使用 Contract.Assume 来帮助它(或者,如果您有信心,可以使用 Contract.Assert)。

有趣的是,如果您显式添加对象不变断言,即 strs 永远不会为 null,CC 能够证明这一点 因此,还可以证明 strs.Add() 永远不会是空引用:

[ContractInvariantMethod]
private void StrsIsNotNull()
{
    Contract.Invariant(strs != null);
}

所以,我想我的预感 #2 是正确的:CC 在这种情况下只是完全错误的。 (或者更准确地说:C# 语义到定理证明者中的编码是不完整的。)

I'm not knowledgeable enough with the intricacies of .NET's object initialization semantics to answer your direct question. However, here's two tips:

  1. Microsoft Research's Pex can automatically generate unit tests that demonstrate exactly under what conditions a contract violation might occur. It uses the same theorem prover and static analyzer as CC does, so it's a fair bet, the two will agree.
  2. Proving contracts is equivalent to solving the Halting Problem, so just because CC can't prove that it cannot ever be null, doesn't mean it isn't true. IOW: CC might just be wrong and you need to help it along with a Contract.Assume (or, if you're feeling confident, Contract.Assert).

Interestingly, if you explicitly add the Object Invariant Assertion that strs can never be null, CC is able to prove that and, consequently, can also prove that strs.Add() will never be a null reference:

[ContractInvariantMethod]
private void StrsIsNotNull()
{
    Contract.Invariant(strs != null);
}

So, I guess my hunch #2 is correct: CC is just simply wrong in this case. (Or more precisely: the encoding of the semantics of C# into the theorem prover is incomplete.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文