CodeContracts - 误报

时间:2010-08-14 19:00:28

标签: c# code-contracts

我刚开始在一个现有的中型项目上尝试.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");
   }
}

为什么CodeContracts静态检查器抱怨strs.Add(...)行? strs没有可能成为null的方法,对吗?我做错了吗?

4 个答案:

答案 0 :(得分:8)

该字段可能标记为readonly,但遗憾的是静态检查程序对此不够智能。因此,由于静态检查器无法自己推断strs永远不为null,因此必须通过不变量明确告知它:

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

答案 1 :(得分:3)

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

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并且你没有意识到它。

答案 2 :(得分:1)

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

答案 3 :(得分:0)

我不熟悉.NET的对象初始化语义的复杂性来回答你的直接问题。但是,这里有两个提示:

  1. Microsoft Research's Pex可以自动生成单元测试,以准确证明合同违规可能发生的条件。它使用与CC相同的定理证明器和静态分析器,所以这是公平的赌注,两人会同意。
  2. 证明合同等同于解决停机问题,因为CC不能证明它不能null,并不意味着它不是真的。 IOW:CC可能只是错误,您需要帮助它Contract.Assume(或者,如果您有信心,Contract.Assert)。
  3. 有趣的是,如果您明确添加strs永远不会null的对象不变声明,则CC 能够证明 和因此,也可以证明strs.Add()永远不会是空引用:

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

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