开发者

CodeContracts - false positives

I've just started experimenting with CodeContracts in .NET 4 on an exi开发者_C百科sting 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?


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


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.


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


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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜