Slashdot Mirror


Is Code Verification Finally Good Enough?

Jonathan asks: "As someone who has been following the development of software verification technology, a recent trend has intrigued me. It seems that the formal method people have finally come down off their high horse and are offering code verification as just another tool. This approach shows up in recent Java and C# based code verification tools that aren't aimed at 'proving correctness' so much as finding potential errors. Now it seems that such an approach is beginning to find its way into XP methods[pdf] as another verification tool to supplement unit tests. Given the current speed and effectiveness of tools like the Spec# verifier, is code verification via automated theorem proving finally going to make its way into the mainstream?"

87 comments

  1. For what? by Control+Group · · Score: 2, Interesting

    What does "good enough" mean? Good enough for it to be included as a general-use software development tool?Good enough to guarantee that released code is bug-free? Good enough to guarantee that released code has no glaring security-affecting errors?

    It makes a difference which "good enough" you're asking for.

    (The answers to those questions, to channel one Urban Chronotis, are yes, no, and maybe. Not necessarily in that order)

    --

    Reality has a conservative bias: it conserves mass, energy, momentum...
    1. Re:For what? by Peter+La+Casse · · Score: 1

      In my experience, the "good enough" that matters is "good enough to catch errors without forcing a developer to have to think." When it's click and drool, and yet still useful, it will be "good enough" for widespread adoption.

  2. Slowly work their way into the mainstream by pdovy · · Score: 1

    I think it's legitimate to expect verification tools to make their way into mainstream software development, but not as any sort of "catch all".

    Developers will have to analyze the specific tools and decide if it is a good supplement to current verification efforts or if it can replace some steps. I think though once it worms its way into mainstream (if only light) use, the tools will continue to improve and give us more options, and become a more integral part of verification.

    I know from work I've done, that the next revision of the FAA's safety standard for software (software for commercial aviation) may include new provisions to allow formal methods tools to replace some steps of the old verification process.

  3. "No" by quiberon2 · · Score: 1

    Mankind's ability to write software is far in advance of mankind's ability to figure out what it does or does not do.

    If Microsoft ship 100 million copies of Windows Vista to 100 million people on public Internet, where the people have mutually-incompatible agendas, then at least some of the people will end up unhappy.

  4. a chain of crutches by fred+fleenblat · · Score: 1, Insightful

    I dunno, as more tools to verify code become available, businesses will hire cheaper and sloppier programmers and just force all the code through the verifiers and hope for the best.

    These aren't tools to make the best code better, they are tools to make the worst code okay.

    1. Re:a chain of crutches by chroot_james · · Score: 4, Funny
      they already do! I came across this the other day:
      private getThis() { return this; }
      --
      Reality is nothing but a collective hunch.
    2. Re:a chain of crutches by kirun · · Score: 3, Funny

      Seems like sensible future-proofing to me. Sure, the variable this is called this right now, but who knows what tomorrow will bring?

      --
      I'm scared of numbers that can't be written as a fraction. It's an irrational fear.
    3. Re:a chain of crutches by Anonymous Coward · · Score: 0
      they already do! I came across this the other day:
      private getThis() { return this; }
      ...or it's use just went over your head, let's see what MJD has to say about the identity function: http://perl.plover.com/yak/identity/
    4. Re:a chain of crutches by neutralstone · · Score: 4, Informative

      Regardless of the poor decisions of some recruiters, I've found this to be true: the most competent and disciplined engineers tend to use as many checking techniques as possible (e.g., regression tests, unit tests, multiple static analysis tools, etc.). They use these techniques not as a substitute for a disciplined approach to design or to implementation (that would be foolish), but as a sanity check on a finished product. They use multiple checking techniques because they know they're human, and humans -- even the most skilled, most experienced, most disciplined ones -- make mistakes, and they want to do everything they reasonably can to catch mistakes before a product ships.

      So to that end, model checkers (and other forms of checking) are Good Things(TM). The possibility that some will misconstrue checking facilities as a substitute for competent and disciplined engineers is a separate issue, and it's not the fault of the checking scheme. The *organizational* problem of poor recruiting cannot be solved by getting rid of model-checking systems, and if your recruiters think that talent can be replaced by a "verification" system, you've got bigger problems than merely the shoddy designs that will come down the pike.

      (Please note that I prefer to use the term "check" rather than "verify", because the latter term, when used to describe a program, too easily connotes the notion that a "verified" program is free of any bugs (which is, needless to say, always a dubious claim). "Check" on the other had usually connotes the idea that there is a specific bug (or set of specific bugs) that is tested for. Of course, TFA mentions they don't want to imply that (verification == no bugs). But IMHO too many people make that mistake.)

    5. Re:a chain of crutches by DragonWriter · · Score: 1

      Tell me that's a joke, and no one actually wrote that in a serious program.

      Or at least, if they did, its in a language that just happens to look like Java, but where "this" isn't a reference to the object the object the private method is in. Because that makes my brain hurt.

    6. Re:a chain of crutches by dgatwood · · Score: 1

      It got funnier the more times I read it. The first time, I read it as a private accessor function that returned a private class member. That alone would be funny, since the only reason to make such a function would be to allow read-only exposure of a private member to non-class code, and by making it private, that eliminated the usefulness altogether. Then, I realized precisely which member was being returned. When I realized that it wasn't returning an explicit class member, but rather, a pointer to the instance itself, I just about fell out of my chair....

      The nice thing, though, is that a smart compiler should be able to inline foo->returnThis() or foo.returnThis(), replacing it with foo or &foo, so while it's pretty funny, at least it probably doesn't hurt performance.... :-)

      --

      Check out my sci-fi/humor trilogy at PatriotsBooks.

    7. Re:a chain of crutches by MightyYar · · Score: 1

      I've never seen anything quite that bad, but I do see this a lot in older code:

      private getThis() { return get_value(foo,bar); }

      The explanation for that is often that someone will create a function to go fetch a single piece of data, getHeight(). Then the next programmer comes along, and adds the ability to getWidth(). The next guy starts to add getDepth(), but then thinks that this is a bad path to go down, so writes a new function called get_value() that serves the more general purpose of fetching data. He then guts the code out of getHeight() and getWidth() and replaces it with the call to his new generic function so that he doesn't have to change all of the existing code.

      --
      W..w..W - Willy Waterloo washes Warren Wiggins who is washing Waldo Woo.
    8. Re:a chain of crutches by Anonymous Coward · · Score: 0

      There is no need to introduce a term like "check" to replace "verify". Code verification requires a specification to verify the program against. If you want precise guarantees, you will need to verify against a formal specification. However, verification doesn't not provide any guarantees about the correctness or completeness of the specification (that is a separate process called validation), and thus with a poor specification, you can verify your code and still produce a buggy program. Those that are familiar with any formal process are well aware that verification does not guarantee bug free code. Furthermore, check already has a slightly different meaning in formal methods (i.e. you can check for bad states in a subset of a huge state space). So check is a bad candidate for replacing verify.

    9. Re:a chain of crutches by aminorex · · Score: 1

      that wouldn't compile anyhow, so it's not surprising that we don't know what it is for.

      --
      -I like my women like I like my tea: green-
    10. Re:a chain of crutches by mindriot · · Score: 1

      This brings up a somewhat interesting point. I can see the point of using stuff like getFoo() just to access an attribute foo. I think it has its purpose (read-only access), but I can also see that it is rather ugly. Further, in C++ code you sometimes see the use of friend just to provide full access to certain attributes and methods otherwise kept hidden or read-only (through getFoo()) to certain privileged classes and such.

      I think sometimes it might be more useful to provide proper access control for attributes and methods, beyond public/private/protected. Maybe more along the lines of POSIX rwx-style access, or even whole ACLs. It might be overkill in most situations, but at least it is flexible and easily documented, with a clear purpose. The getFoo() approach, on the other hand, may work as well, but its real reason and purpose (mosty it is just a type of access control) tend to be unclear.

    11. Re:a chain of crutches by Anonymous Coward · · Score: 0

      think sometimes it might be more useful to provide proper access control for attributes and methods, beyond public/private/protected.

      The public getX() and setX() methods to get and set private attribute X are essentially the same as making X public, but hiding it's implementation as an attempt at future-proofing.

      eg. Consider getArea() and getLength() for a square -- the area could be what's stored, or the length of one side could be stored instead, and that implementation detail could change, based upon, say, which method is used most frequently.

      That said, I'm not sure that such attempts to future proof are very useful. At some point, changing the interface is less work than trying to imagine all the possible changes that might be made at some point. The code can't be virtual on all levels, after all.

    12. Re:a chain of crutches by lokedhs · · Score: 1
      The method could be overridden in a subclass. That would make it useful.

      Or perhaps the .getThis() method was specificed by an interface as a way of retrieving some functionality, but the functionality was implemented by the class itself. This design is used in table cell renderers in Java for example.

    13. Re:a chain of crutches by palantir0 · · Score: 1

      I've found the complete opposite to be true. Rarely do I find tons of checking tools. Mostly it is design review the arch, implementation, and code. Perform unit testing. The good engineers do better unit testing, thinking about the interactions, wake up at night realizing something is screwed up, and fix their problems proactively.

      Everyone 'wants' to use tools but the reality is the overhead is pretty significant so they are avoided. Only in large companies do I see this methodology and even that is fairly rare. If a software failure can kill or hurt someone, I would guess these practices would be used to eek out some better software. For everyone else, there isn't much motivation.

      Cheers

  5. No by Gemini_25_RB · · Score: 1

    Finding errors /= Proving correctness. Part of proving a program, imho, should include making sure the program only does what it claims to do. No more. (Say goodbye to tag-a-long malware!) Of course, this is a pretty idealistic outlook. We could all just program in ML, instead.

  6. Yes and No. by Anonymous Coward · · Score: 0

    Good enough to yield some benefits in chasing down certain classes of bugs on large application bases? Sure. See coverity, and their open source static analysis project. See Microsoft's reports on the effectivity of such tools in their work, at this year's FLOC, for example. Spec# is a great concept, and fast enough in execution for small demos, at least. I'd love to be able to program that way in a C-ish language, and have my IDE tell me I'm about to screw up some invariant if I don't fix some newly added code. But I've got my doubts how well that would scale to good old messy C code.

    Good enough for practical use? Not yet. Questionable if it will ever be: on a psychological level many developers hate being told their code is a pile of crap by other people, nevermind being told that by buggy/incomplete tools spitting out pages of warnings. See mini-msft's blog for Microsoft employees ranting about the PREfast fetish on management levels, the buggy static verification tools causing more work to everyone, etc. Heck, see most build logs of C/C++ projects on Debian buildds and ask yourself who's ever going to bother fixing those ever mounting numbers of gcc compiler warnings, and who's going to pay for that work, and, most importantly, who's going to pay to fix the bugs consequently introduced by fixing those warnings.

    On the other hand, if one can manage to strike a balance between usefulness of the tools, and their usability, they can be very nice. See FindBugs, and see PMD, for example. But that's all for Java, and static analysis of Java is somewhat nicer task than dealing with the many fun issues of C or C++.

    cheers,
    dalibor topic

  7. Not possible by Intron · · Score: 2, Insightful

    The problem with any verification tool is that it can't know what you expect the program to do unless you tell it. Why should this be any more correct than the program itself? In other words, if you can write a description of what the program should do that is more accurate than the program, then that description should replace the source code.

    --
    Intron: the portion of DNA which expresses nothing useful.
    1. Re:Not possible by Anonymous Coward · · Score: 0

      That's an old argment, and it seems plausible at first look - and when you look a bit furter, you'll find that there are a lot of interesting cases where it isn't true. Let me give an example: void foo(char *bar) { *bar = 'a'; } foo(NULL); is always wrong. Another example would be a quicksort implementation: It's easier to write a routine that check if something is sorted than to write a good quicksort routine, and that can be used to check that the quicksort routine isn't horribly wrong. A more subtle point here is that the invariant checks you write are different than the code - so you can catch bugs in either one by running them against each other. Yes, it's more to debug, but it's usually much simpler faults. )

    2. Re:Not possible by Anonymous Coward · · Score: 1, Funny

      Exactly right. How can a program know what another program is *supposed* to do unless the first program has available to it an exact description of what the program it is checking is supposed to do? And if that exact description is available, there should be an automatic code generator which turns the description into code.

      In other words, writting the exact description of what you want should be your last step in development, after which a code generator creates the program. This turns coding into the problem of writing the exact description. But can the exact description be analyzed? For contradictions and potentially missing parts I suppose, but it can never tell you if that is what you wanted.

      This is perfectly illustrated by a Dilbert cartoon hanging in my cube in which Alice is trying to get program requirements from a user:

      Alice: "I'll need to know your requirements before I start to design the software. First of all, what are you trying to accomplish?"

      User: "I am trying to make you design my software"

      Alica: "I mean what are you trying to accomplish with the software?"

      User: "I won't know what I can accomplish until you tell me what the software can do"

      Alice: "Try to get this concept through your thick skull: the software can do whatever I design it to do"

      (pause)

      user: "Can you design it to tell you my requirements?"

    3. Re:Not possible by Intron · · Score: 1

      Your example 1 - if the verifier checks to make sure the passed argument is an l-value, then the compiler should be able to make the same check, which is what I said.

      Your example 2 - of course it's easy to check if the result is sorted. That's called QA, not verification. Verification would be proving that the quicksort routine sorts the array for all possible inputs. Proving that it implements quicksort and not a sort that has slightly worse performance is an even harder problem.

      So no, you did not disprove what I said.

      --
      Intron: the portion of DNA which expresses nothing useful.
    4. Re:Not possible by rblum · · Score: 3, Interesting

      That - in an other discipline - is called "double bookkeeping". You specify things twice, independently. Once in the actual source code, once in the description.

      That way, you'll know when the two disagree. It doesn't prove that it does what you *intend* to do, but it proves that spec and source say the same thing. If they're written by different people, you can now have a fairly high degree of confidence.

      Does it make your program bug-free? Only if you can write a bug-free spec. But it's a useful concept to reduce the likelihood of problems.

    5. Re:Not possible by Coryoth · · Score: 3, Informative
      The problem with any verification tool is that it can't know what you expect the program to do unless you tell it. Why should this be any more correct than the program itself? In other words, if you can write a description of what the program should do that is more accurate than the program, then that description should replace the source code.

      It is often easier to describe what a program has to do than it is to describe exactly how to do it. I can describe what a square root finding algorithm has to do: given x it has to find y such that y*y =x; without coming close to writing something that actaully finds the square root. All the prover then has to do is ensure that the code instructions really do produce a result that satisfies the stated constraint - which is potentially entirely possible. Writing contracts for code can be as easy (or easier) than writing unit tests for code. If you write a contract instead of a unit test then that potentially gives the prover all it needs to verify that the code will work for all possible test cases instead of your predefined unit test cases. If the prover can't manage that then just feed in some test data and if the contract fails you've found an error (that is, at worst you've got a unit test already). Working this way can be remarkably efficient at weeding out errors - you verify code when it works, and essentially do unit testing for the code that can't be verified. Perhaps if you actually tried it you'd see.
    6. Re:Not possible by tricorn · · Score: 1

      There are many simple things that a program verifier can check for. I can see a program figuring out that your foo(NULL) call is always going to be wrong (e.g. by having the verifier notice that you are dereferencing it without checking if it is NULL and adding an assertion to the exported definition of the function; in this case the assertion will be a constant so it can be a compile-time error).

      A lot of the "variable may be uninitialized" errors that a good compiler will spit out are along those lines. They could be much better, though:

      a = 0;

      while (a < n)
      {
      if (a == 0)
      b = 1;
      else
      b += a;

      if (b <= n)
      c = a + b;

      a += b + c;
      }

      ("n" is a passed parameter in the above). Some compilers will require a spurious initialization of b in the above to avoid getting a warning the assignment "b += a". They're smart enough to know that b is initialized after the if-else, so the "a += b" line isn't flagged, but the "b += a" line will be. Note, gcc isn't one of those, it has no problem with that line.

      However, even gcc complains about c being possibly uninitialized, even though we can tell from looking at the code that n MUST be greater than 0, so on the first pass through the code, the second if clause must be true, thus c will always have a valid value.

      If you extend this to code that has to figure out relationships between inputs to and outputs from a function, and thus what values might or might not be legal to pass in, you've passed well beyond what a program verifier can currently do.

      Take, for instance, a common code sequence:

      n = int(x/b);
      r = x - (n * b);

      If I put an assertion that (((x >= 0) && (b > 0)) implies ((r >= 0) && (r

    7. Re:Not possible by l33td00d42 · · Score: 2, Funny
      Alice: "Try to get this concept through your thick skull: the software can do whatever I design it to do"
      (pause)
      user: "Can you design it to tell you my requirements?"
      boy, that's easy:

      print "This software is required to print this statement.";
    8. Re:Not possible by MarkusQ · · Score: 1
      However, even gcc complains about c being possibly uninitialized, even though we can tell from looking at the code that n MUST be greater than 0, so on the first pass through the code, the second if clause must be true, thus c will always have a valid value.

      This is a good example of why code verification is a hard problem. You may be able to tell from the given code fragment that c is always initialized, but I can't. Specifically, when "float n = 0.5;" it seems to me pretty clear that c isn't initialized.

      Now, you may well cry fowl, that I was "supposed to know" that n was int and not float, but that sort of reliance on information that isn't derivable from the code in question always crops up in automated code verification. And it doesn't matter if it was "obvious" or that the system was "supposed to know it."

      --MarkusQ

    9. Re:Not possible by tricorn · · Score: 1

      You make a good point, but since I was only giving code fragments, you didn't see that this was C code and n was declared as an int parameter...but, let's say it's a dynamically-typed language, should it flag this code fragment as the error, or the location where I call it with a value that it can't prove is = 1? You can go a long way with assertions, and a program verifier can use assertions to guide it in it's proofs (although the assertions have to verifiable from the code, which means you have to lay out a proof-by-assertion for the verifier). However, at some point it isn't going to be able to show that the program really does what you want it to do. You can probably prove a lot about the parts of it, though.

    10. Re:Not possible by Peaker · · Score: 1
      The problem with any verification tool is that it can't know what you expect the program to do unless you tell it. Why should this be any more correct than the program itself?

      Many aspects of the program can be described, and not all of them must be proven.

      A program can be roughly divided to its requirements specification and the implementation. The requirements leave a lot of "freedom" to the implementation, and the choices in this area are not important to prove.

      As a simple example, a "sort" algorithm has a requirement specification:
      • The input set of elements must contain the exact same elements as the output set of elements.
      • Every element in the output set of elements, except the first one, is larger or equal to the element before it.

      There are also some implicit "requirements" that can and depending on method, must be proven:
      • The algorithm is deterministic.
      • The algorithm will halt with a result.
      • The algorithm will not perform invalid operations (crashes/etc).

      There are many possible sort implementations, but any of them can be proven to answer the requirements. The above requirements' specification are not an equivalent description of sort as the implementation.

      The basic key behind program proof is that there is a gap and a difference between requirements and implementation and describing requirements is usually much easier. Also, the many implicit requirements (halting, no crashes) derive many provable requirements (even automatically) and themselves don't require manual and potentially error-prone specification.

      In other words, if you can write a description of what the program should do that is more accurate than the program, then that description should replace the source code.

      You must be writing prolog :-) A requirement specification is not a program implementation. There is no way to automatically deduce a working implementation from the requirements, other than brute force search all of the possible outputs for the input - which is not practical for any non-trivial algorithm with non-trivial input.
    11. Re:Not possible by Anonymous Coward · · Score: 0

      Double entry bookkeeping is not about writing things down twice, it's about balancing a debit with a credit. Money always goes from one place to another, so you keep track on both ends that way. Well-written preconditions and postconditions are a bit like that. Writing code twice, even if it's in different forms, is just pointless double-work.

    12. Re:Not possible by Anonymous Coward · · Score: 0

      You are correct, though in a very large number of useful cases theorem proving is computationally intractable. The problem is that theorem provers trivially can't know how to prove an arbitrary thing about code in any useful langauge in the general case (See the halting problem), leaving them too brute force proof search. These searches can be graetly improved via heuristic approaches for a large portion of common cases, but to date I do not believe that we have good enough heuristics to really be useful for real world programming.

      It's important here to keep terms straight. Theorem Proving is entirely different from theorem checking. Theorem checkers are really quite easy to write, because they don't need heuristics. The difference is that a human writes down the proof, and the computer only checks it. A compiler for a language like ML or HASKELL can be seen as a thereom checker. Your program is then a proof that there exists something of that programs type. Type inference in ML can be seen as a piece of a theorem prover in that it allows the programmer to skip some steps in the formal proof, which the compiler can figure out easilly enough for itself in a formalized way. The important feature here though is that the proofs are constrained only to type system, which must be proven to halt. This means, by deffinition, that such a system is not complete enough to express a touring machine. This means that we're left in a fairly constrained domain.

      This restricted domain, is extremely useful for catching stupid bugs, but obviously not useful for proving more useful generalized semantics. The complexity of your type system decides the complexity of theorems you can prove, but a more complex type system is general more difficult to write, more difficult to prove correct, more difficult to code, and if it's too expressive then the compiler can no longer check it (I.E. it becomes halting complete). The question is how far out can we push theorem proving, and how far is still useful. Some new type systems invented recently allow the programmer to add annotations requested the compiler to prove certain statically checkable semantics. Hopefully these will prove useful, but whether they are or not is yet unknown.

      Currently the state of the art in C and Java style programming are model checkers. While, as the article says the designers of these checkers have "come off of their high horse", in the process they've given up on their methods being guaranteed to work. This is a fair trade by all means, but one that people should realize has been made. These methods will always say "no" when the programs are bad, but are often forced to say "I don't know" even if the program is good, and when they will say one or the other is often ill defined, because they are based on heuristics. This is not the fault of the theorist who design such methods, rather it is due to the complex nature of the languages themselves, they lack of any formal specification of their operation, and the difficulty in understanding pointer aliasing and object typing. Basically fundamentally good programming practices in C make the program hard for a theorem prover or checker to understand, simply due to the design of the language.

      Even just dumb checking which can completly fail and say "yes" when the code is bad and "no" when it's not can be horribly useful. Back in highschool I wrote a small pascal program that just searched pascal programs for semicolons at the end of an if, and used a few other similar stupidity checks, you'd be amazed how helpful just that was. Admitadly such algorythms really just shrink your language to a subset of the original, and are not really directly comparable to formal varifaction. Formal verification is certainly useful, but I hope one day we will surpass the need to "come off our high horse" and that we can use formal languages where verification can be done in a more formal, and just plain simpler fashion.

    13. Re:Not possible by Eivind+Eklund · · Score: 1
      For some reason, you took this in the spirit of "something you should argue against" instead of something you should learn. Now, I'm perfectly willing to argue and show that you've been behaving as an ass, if that's what it takes for you to LEARN, NOW. So, to make you LEARN NOW, I'll do the shouting and behaving in your spirit, increasing the magnitude a bit so you can GET IT.

      You see, you totally missed the point of my comment. (A) "The compiler could do it" is the same as saying the compiler is a verifier. It is. There are other verifiers that do more. And that doesn't matter: It still disprove your statement that there are no interesting invariants provable without adding to the code. There are, and you will accept that now, and from now on stop arguing and instead LEARN.

      And (B) - it is possible to prove that the invariant holds true for every case for many invariants. This, however, is irrelevant to what we were discussion: You were claiming that the size of any interesting invariant would be the same as the entire program, and would be used instead of the program. This is trivially false, so UNDERSTAND THIS NOW.

      As for proving that a particular implementation is quicksort: Yes, non-trivial. That's irrelevant for the point, which you can accept now, and accept that you are behaving as an ass, instead of actually chosing to LEARN NOW. I understand that you're pissed at yourself for being wrong; take it out in energy to LEARN NOW, and let the phase where you argued against new knowledge fall behind you.

      Eivind.

      --
      Doubting the existence of evolution is like doubting the existence of China: It just shows that you're uninformed.
    14. Re:Not possible by Anonymous Coward · · Score: 0

      Shouting and insults are not very convincing.

      In (A) maybe I misworded it. My point is that if there is an error of syntax, like use of a constant where an lvalue is required, then it should be detected by the compiler. Checking syntax is not usually what is meant by program verification.

      In (B), if the invariant for quicksort is "the output is sorted" then you have suggested no mechanism for specifying this to the verifier, nor for a verifier to prove or disprove that the code is correct, so I have no way of LEARNing from you whether the invariant description will be smaller or separate from than the source. I do know that creating a series of assertions in the code that prove it's correctness has been shown to be a difficult problem and does not scale well to large programs. Dijkstra admitted that in 1969; perhaps you know better.

    15. Re:Not possible by dctoastman · · Score: 1

      What if n is less than 0? You say that by looking at the code that n must be greater than 0, but that is nowhere in there. There is no check on the value of n so you can't assume the value.
      Then c and b will both be uninitialized.

      You can't trust initialization in conditional statements unless you cover all conditions or if you declare your variables within the conditional code block.

    16. Re:Not possible by tricorn · · Score: 1

      b and c will be uninitialized outside the loop, true, but they aren't used outside the loop. Note that I don't declare the variables, inside or outside the loop, and it isn't even necessarily C code. Even if b or c are used later, it could well be that they are used in a context where n is known to be >= 1. You can't read more into code fragments than what is presented.

      If I were to use b or c after the end of the loop (with no other initializations or conditions), then a program verifier might add in, or require me to add in, an assertion that n >=1, and anything that called that code would be flagged in error if it couldn't be proven that was true. Granted, that isn't necessarily the best way to handle such code, but assuming that the code was intended to handle non-integer values, or any values

      Remember, this was just an example of the type of code analysis that current compilers don't do. It isn't really a problem there, it isn't designed nor required to catch every place that you DON'T need to initialize something, and a spurious initialization isn't exactly a huge performance hit. The real question would then be if there are any program verifiers that are even smart enough to figure out this example on their own. How much analysis can a program verifier do in similar situations? Do you have to lead it by the hand to prove your program doesn't have errors, or can it figure out a bunch of it on its own? The more you have to do, the less useful a program verifier is. Of course, even that type of verification just proves that you never reference uninitialized variables, dereference NULL pointers, get array subscripts out of bounds, or have memory leaks, etc.

      At some level the verification that the program actually accomplishes what you want boils down to re-writing the way you specify what it is supposed to do, and if there is an error in those specifications (which, after all, will just be another programming language), then the verifier will happily verify that your program does the wrong thing. At least there's a good chance that if the specifications are wrong, the implementation won't match, and you can then look more closely at both to determine which one is incorrect. It should also be pretty good at pointing out code that can never work as intended.

    17. Re:Not possible by dctoastman · · Score: 1
      So your only defense is that it is a fragment. By that logic, since it is a fragment, you can't assume that b and c won't be used after the loop either. You are reading outside the code fragment if you assume they won't be used. And if you want us to assume anything about the code that isn't explicit, make it explicit. If your code fragment was instead wrapped around this:
      void function(int n)
      {
      //Your fragment
      }

      Then your arguement would hold water, but as it is hope for the best, but plan for the worst.

      Also, I like how you say that even if they are used outside the loop, they could be used in "the proper context".

      In this instance I would have to say that the verifier would be correct, this is code that is highly suspicious and that relying on proper execution of conditionals and magic numbers aren't good substitutes for defensive programming.
    18. Re:Not possible by FrostedChaos · · Score: 1

      A very informative comment. I especially like your description of type systems as theorem provers.

      I agree that it would be nice to see some simpler, cleaner languages, but I'm not sure if that's going to happen any time soon. For example... suppose the people who design model checkers for SML only have to do only X man-years of work, while the people who do model checkers for C# have to do 100X. So what-- the model checkers for C# are still going to be cheap and widely available, because there is a market for it. And since people have existing infrastructure dependent on C#, they don't want to switch unless there's a reason.

      On the other hand, there is probably a way to integrate more model checking into the programming language itself, and make it more friendly to model checkers. Type systems are really just one example of this. Another example is assertions, such as the pre- and post- conditions that Djikstra tried so hard to popularize. Another example is data encapsulation in object oriented languages.

      --
      "Any connection between your reality and mine is purely coincidental." -Slashdot
    19. Re:Not possible by tricorn · · Score: 1

      I don't need a defense, I was giving an example of code that current compilers don't analyze as completely as possible, as an example of the type of thing that a code verifier would have to be able to analyze in order to find obscure problems. It wasn't being held up as an example of fine programming.

      I don't need to assume anything about b and c outside the loop, as I didn't give any code outside the loop. You're the one assuming for some reason that b and/or c would be needed after the loop. I was saying ONLY that if b and c were not initialized at the beginning of the loop, some compilers would complain about b being possibly uninitialized, and some would not but still complain about c being possibly uninitialized, in the code that was given.

      And yes, they COULD be used in the "proper context", i.e. code which is only executed if n >= 1 (or >0 for using only b).

  8. Excuse me, did any of you graduate yet? by Anonymous Coward · · Score: 1, Interesting

    Since when did this move from the realm of undecidable problems into solvable with a Turing Machine?

    1. Re:Excuse me, did any of you graduate yet? by Fahrenheit+450 · · Score: 3, Informative

      Well, it's quite possible to do things like restrict the problem to a decidable subset of the original problem and only let your solution work on those subsets. Or you can work on problems that are undecidable in general, but in most typical cases are not only decidable, but efficiently solvable. For example, most type systems work in one of these two ways.

      You see, you should have learned before you graduated that just because a problem is hard (or impossible) in general, that doesn't mean the average case is hard at all.

      --
      -30-
    2. Re:Excuse me, did any of you graduate yet? by UncleFluffy · · Score: 1

      Since when did this move from the realm of undecidable problems into solvable with a Turing Machine?

      About as long as we've being using finite state machines as approximations to a Turing Machine.

      --

      What would Lemmy do?

  9. No :) by Monkelectric · · Score: 0, Troll
    The thing you have to remember about methodologies is they are all bullshit. In my experience, the people who cling to methodologies are generally not clue-full.

    The paper you linked to -- I just finished reading it. The "methodology" they provide has more comedic value than anything else. The steps in his methodology are counter-intuitive and therefore stupid. He wants us to iterate over each requirement, re-writing a function as the most simple program which passes the tests? What possible reason for this would we have other than an exercise in futility? Writing code we *KNOW* has no value with the intent of re-writing it later? Futile.

    Perhaps you could accept this premise if the methodology scaled for larger problems -- but clearly it does not and can not. At this point I suspect you are the author of this paper.

    --

    Religion is a gateway psychosis. -- Dave Foley

    1. Re:No :) by Anonymous Coward · · Score: 0

      The problem he's solving is not one of "How do I write this?" but "How do I write this, be able to change it, and know that it still works the same?"

      Eg, you write an application for a client, then the client asks you to add features X, Y, Z, and fix bugs/misfeatures A, B, C, but not break the rest of the program.

      It's very nice to be able to write tests that, when run on the system, tell you "It's still ok, I'm working as requested"

      Once you're to that point, formal specifications allow you to define not just specific test cases (when x = 1, y = 10), but generalized logical principles that it follows. (y is always ten times larger than x)

      Granted, it's a lot of work, but if you're going to be working on a piece of software for two years, and you're at the beginning of the project now, it makes sense to build the infrastructure right, so that last-minute changes won't break everything.

    2. Re:No :) by Peter+La+Casse · · Score: 1
      The thing you have to remember about methodologies is they are all bullshit.

      Not every methodology sucks all the time. A methodology is just a named collection of practices.

      In my experience, the people who cling to methodologies are generally not clue-full.

      Humans inherently crave religion. Convince someone that something works and they're likely to cling to it to the bitter end, be it Code Verification, atheism, voting Republican or whatever.

    3. Re:No :) by Control+Group · · Score: 4, Insightful

      The steps in his methodology are counter-intuitive and therefore stupid

      I agree with your general statement, but this isn't good evidence. Plenty of things are counterintuitive, yet correct and useful.

      I present exhibit A: the whole of statistics. It is counterintuitive that after the tenth straight "heads" result, the eleventh flip still has even odds of coming up heads - despite the fact that the odds of eleven straight flips coming up heads are 2048:1. It is counterintuitive that you should always switch doors in the Monty Hall problem.

      Or, if you're scientifically minded, I give you relativity. It is counterintuitive that no matter how fast you're moving relative to a light source, the speed of the light from your point of view will never change.

      It is counterintuitive that gravity causes hot air balloons to rise, or that the way to escape Earth orbit is to accelerate along it, not away from Earth.

      Counterintuitive doesn't necessarily mean that something's incorrect.

      --

      Reality has a conservative bias: it conserves mass, energy, momentum...
    4. Re:No :) by Anonymous Coward · · Score: 0

      the way to escape Earth orbit is to accelerate along it, not away from Earth.

      That's not true. If you continue to accelerate directly away from the Earth, you will eventually reach escape velocity and leave Earth's orbit. Now, it might be easier to escape Earth's orbit by accelerating on the tangent, but that's a different question.

    5. Re:No :) by Monkelectric · · Score: 1
      The problem he's solving is not one of "How do I write this?" but "How do I write this, be able to change it, and know that it still works the same?"

      I *REALLY* think you miss-interpreted the problem. The author clearly states the task is to build a function which gives all prime numbers smaller than n. Furthermore, what you've described is unit testing, which sadly is not a new concept.

      --

      Religion is a gateway psychosis. -- Dave Foley

    6. Re:No :) by tricorn · · Score: 1

      "The way to write software is to design it, not have a random number generator spit out text, wait until a given chunk compiles, then test it to see if it does what you want."

      And you say "that's not true, it will eventually produce a correct program! It might be easier to write a program by designing it, but that's a different question."

      Anyway, if you are in orbit and you continually accelerate directly away from Earth (which means that you are continually changing your thrust vector as you continue to orbit), I think it depends on how much thrust you have whether you can reach escape velocity, whereas you can eventually achieve escape velocity with minimal thrust if you are always accelerating along your orbital path (which, again, means you're constantly changing your thrust vector). Not that I'm a rocket scientist or anything.

    7. Re:No :) by Anonymous Coward · · Score: 0

      If you have enough thrust you don't need to worry about your orbital trajectory. However, no one has infinite power.

    8. Re:No :) by Anonymous Coward · · Score: 0

      "The way to write software is to design it, not have a random number generator spit out text, wait until a given chunk compiles, then test it to see if it does what you want." And you say "that's not true, it will eventually produce a correct program! It might be easier to write a program by designing it, but that's a different question."

      That's not a fair analogy - here's an equivalent analogy. There is a function to determine the sum of a series of integers, 1+2+3+4+5...n = n*(n+1)/2. That is the simple, elegant, quick solution.

      If you don't know that function, you could just brute-force the problem and count all the numbers in the series. You will get the same correct answer, but it will take much longer.

      But since computers are so fast these days, unless you have very large values of n, the brute-force calculation will be fast enough for many applications.

      Yes, I'm being picky - long day marking papers :)

    9. Re:No :) by aminorex · · Score: 1

      "The way to write software" smell like a method to me. Methodology is simply the study of method, or more broadly, any discourse on the topic. A statement beginning as quoted is a methodological claim.

      A lot of good code has been written using genetic programming and genetic algorithms, so I find it to be an erroneous or at least over-broad claim.

      --
      -I like my women like I like my tea: green-
    10. Re:No :) by Profound · · Score: 1

      >> It is counterintuitive that gravity causes hot air balloons to rise

      That's buoyancy.

  10. What should be verified by derek_farn · · Score: 1

    Before tools can check the code (eg, static analysis) we need to know what constructs they need to flag. The formal verification people will claim that checking a program's source against its specification is the solution. However, that is a very expensive and time consuming process. There is an ISO group looking at vulnerabilities in programming languages.

  11. For Guaranteeing Correct Requirements? by billstewart · · Score: 1
    • Do theorem provers prove that what the user told you they wanted made sense?
    • ... that what they wanted would solve the problem they were trying to solve?
    • ... that the problem they thought they were trying to solve was really the problem they *needed* to have solved?
    • ... that what they wanted when you started was still what they wanted when you were done?
    Uh... no.

    But they can probably be considered to be a newer and better version of lint, and that's a good thing.

    --

    Bill Stewart
    New Fast-Compression-only CPR http://preview.tinyurl.com/dy575ks
    1. Re:For Guaranteeing Correct Requirements? by tom's+a-cold · · Score: 1

      Mod parent way up.

      Code-checking is a good thing, and provably correct code is especially good, though what's provable is still narrower than the range of behaviors of any interesting system I've seen.

      But the most difficult part of any complex system development project is getting valid requirements and then implementing a process of systematically and iteratively confirming that the delivered system is what the users need, not what some bunch of managers or analysts asked for on their behalf. This is not to minimize the value of technical correctness, just to remember that the systems are for a purpose, and that's a big determinant of project success. It's the old systems engineering cliche: you not only have to build the system right, you have to build the right system.

      So yeah... lint but better. Another useful tool that will doubtless be over-hyped by bonehead IT managers and be wrongly dragged into disrepute.

      --
      Get your teeth into a small slice: the cake of liberty
  12. Yes, it works, but it's not easy by Animats · · Score: 5, Interesting

    The main reason program verification didn't catch on was that it was hopeless for C and C++. The semantics of those languages were so messy that formalizing them was nearly hopeless.

    Java and C#, however, are good enough. (So were Pascal, Modula, and Ada.)

    Here's the manual for the Pascal-F verifier, a system written by a team I headed back in the early 1980s. This was a proprietary system done internally for Ford Motor Company. Take a look at the example real time engine control program beginning on page 155. It was painfully slow back then; it took 45 minutes of VAX 11/780 time (1 MIPS) to verify that program from a cold start. Today, it would take about a second.

    What's being proved in that example? First, that there are no subscripts out of range or arithmetic overflows. Second, that all loops terminate. (Yes, you can prove that for most useful programs; the halting problem applies only to pathological programs.) Third, that the following constraints hold:

    • fuelpumpon implies (tickssincespark < (1000*ms)); if fuel pump is on, spark must occur within 1 sec.
    • (enginespeed < rpm(1)) implies (not fuelpumpon); fuel pump must be disabled if the engine is not rotating
    • cylssincespark <= 1; a spark must be issued for each cylinder pulse

    Useful stuff, the conditions needed to keep the engine running.

    This is "design by contract" with teeth. Each function is checked to insure that it always satisfies its exit conditions if its entry conditions are satisfied by the caller, and that the function doesn't overflow, subscript out of range, or fail to terminate. Each call is checked to insure that its entry conditions are always satisfied. The end result is a guarantee that those properties hold for the whole program.

    This is a very valuable check. It insures that caller and callee are in agreement on how to call each function. That's the cause of a huge number of software bugs - the caller made some incorrect assumption about the function being called, or the function didn't check for something which it needed to check. Both of those can be statically machine checked.

    It's not easy to get a program through formal verification with a verifier like that one. The verifier does almost all the work on easy sections of code, but where correctness depends on anything non-trivial, you have to work with the theorem prover to get the proofs through. This isn't easy. The DEC Java checker and Microsoft's Spec# checker aren't as hard-line.

    1. Re:Yes, it works, but it's not easy by Peaker · · Score: 1
      The main reason program verification didn't catch on was that it was hopeless for C and C++.

      Java and C#, however, are good enough. (So were Pascal, Modula, and Ada.)


      What is the semantic difference between C and Pascal?

      As far as I can remember, the only real semantic difference was Pascal's lack of casting.
      Is this difference really the breaking point of C's provability?

      I would expect pointer arithmetic to be the source of problems, but if I recall correctly, Pascal's pointers have arithmetic as well.
    2. Re:Yes, it works, but it's not easy by Animats · · Score: 3, Insightful

      What is the semantic difference between C and Pascal?

      The big problems with C/C++ from a formal methods standpoint:

      • void* (You lose all the type information)
      • Too much casting. (Again, you lose all the type information)
      • Array size information isn't carried along with arrays or passed through function calls. (Biggest design mistake in C).
      • The "array is a pointer to the first element" convention. (Is this an array or a single object?)
      • Pointer arithmetic semantics are ill defined. (Long story.)
      • C++ iterators don't have an explicit tie to the collection, so detecting iterator invalidation statically is hard.
      • Hard to detect aliasing. (A consequence of the free use of pointers.)
      • Too much "undefined behavior" that isn't prohibited.

      I would expect pointer arithmetic to be the source of problems, but if I recall correctly, Pascal's pointers have arithmetic as well.

      No, they don't.

      Pointer arithmetic really is obsolete. Compilers have been generating code for subscripting that's as good or better than pointer arithmetic code for well over a decade now.

    3. Re:Yes, it works, but it's not easy by krischik · · Score: 1

      Others answered the question but I can add practical experience here. For A while I tied splint [1] and after after a while it became clear that the greatest problem whas the lack of array bound.

      I tried hard, realy hard to get splints bound checking to work - but in the end it did not work out.

      The project is not stalled since 2004 [2] and for me it is now clear that the "Secure Programming Lint" was a hopeless endeavor.

      As for casting: Ada has about 3 different ways of type convertions and is still provable. The difference here is implicid type conversing. My favorite example:

      unsigned i = -1;

      The result depends on the compiler in particular if it is a 16 bit, 32 bit or 64 bit compiler.

      And last not least: C has been patched to many times. The first C is from about around 1973 and did not feature unsigned (the reason why Unix file I/O features a 2 and not 4 GB limit), struct and arrays. Yep, the [] syntax was patched on later.

      Now speaking of patching the C language: C99 does have propper arrays with bounds attached to them. But there is allmost no compiler which implements this C99 feature. M$ and Borland have no plans for variant arrary, GNU C has it on the bug list for years now (depite the fact that GNU Ada has variant arrarys since the first release from ruffly 1998).

      Martin

      PS: I have programmed in Ada, C, C++, Java and Pascal and my favorite language is now Ada.

      [1] http://www.splint.org/
      [2] http://sourceforge.net/projects/splint

    4. Re:Yes, it works, but it's not easy by Peaker · · Score: 1

      PS: I have programmed in Ada, C, C++, Java and Pascal and my favorite language is now Ada.

      I have programmed in Assembly, Python, C, C++, Pascal, some Lisp and a tiny bit of Java, Haskell and Ada.

      I dislike Ada because I believe there are far too many primitives that should be libraries (semaphores and other concurrency features).

      I now love the other edge of the spectrum: Python. The "eww whitespace" barrier seems to block/filter a lot of closed-minded programmers, but don't let it prevent you from learning this wonderful language :)

    5. Re:Yes, it works, but it's not easy by Anonymous Coward · · Score: 0

      If you like ada, you try a few newer languages.
      Sml, OCaml, and Haskel are pretty shiny and provable.
      I've done fairly serious programming in Basic, Pascal, C, C++, Java, Python, SML, OCaml, sh, VB, a couple of assemblies, and a few other languages (not including ADA, Perl, or Fortran, sorry).
      Of all of these my favorites are OCaml and C/Assembly (C and Assembly, IMHO, are basically the same language, in that they require near full understanding of the underlying system).
      Basically, I want either the horrifically broken bare metal (C/Assembly), or an abstraction which is internally consistant and logical (SML), allowing me to forget about the metal. I like having error checking for most things, and only use Python for programs a little to long, complex, or slow for sh.
      OCaml is a slight softening on the SML hardline, and as a result has many many libraries written for it. OCaml also has an extremely good (by which I mean fast) implementation supporting compilation, byte code, and pure interpretation. So I use OCaml for my application type programming, and C for the bare metal hacking (I.E. kernel code stuff). I dream of the day a language exists allowing me full control of the system in a consistant elegant package, but there is no such thing yet... ::sigh::... C# just scares the hell out of me, like java on steroids.

    6. Re:Yes, it works, but it's not easy by StrawberryFrog · · Score: 1


      I would expect pointer arithmetic to be the source of problems, but if I recall correctly, Pascal's pointers have arithmetic as well.

      No, they don't.


      That depends entirely on what you mean by "pascal". The pascal language as spec'd doesn't. But nobody uses that, so this not a very useful definition to adhere to.

      Most users of "pascal" use/used Borland Turbo Pascal or Delphi. In those languages you *can* do pointer arithmetic. Sure you have to jump through more hoops and casts than with C (it can be considered a good thing that you have to go out of your way in order to write dodgy code) but you can do it. Trust me on this, I've done it myself.

      --

      My Karma: ran over your Dogma
      StrawberryFrog

  13. To quote Knuth by dargaud · · Score: 2, Funny
    "Beware of bugs in the above code; I have only proved it correct, not tried it." —Donald E. Knuth.
    --
    Non-Linux Penguins ?
  14. logic bug by hey · · Score: 2, Funny

    How could a program ever find this bug:

    if (vote == "democrat")
    {
            republican++;
    }

    1. Re:logic bug by vidnet · · Score: 1

      Simple, it would see that "democrat" was a literal and thus it would be highly unlikely that 'vote' would happen to have that same pointer value, and it would suggest if(strcmp(vote,"democrat")==0) instead.

      (haha)

    2. Re:logic bug by Brown · · Score: 1

      It's not a bug, it's a feature!

    3. Re:logic bug by Anonymous Coward · · Score: 0

      Actually, some static analysis tools such as SPARK would find this error as you specify a "derives" annotation before writing the code (e.g
      --# derives DemocratCount from DemocratCount, DemocratVote ). This would catch your mistake provided you wrote the semantics before writing the code.

  15. Use a language with build in prooving. by krischik · · Score: 1

    There some programming lanugages (Ada, SPARK and Eiffel spring to my mind) which have the verification build in (to some degree). Just in case you wonder how that works here my favorite Ada example:

    type Day_Of_Month is range 1 .. 31;

    Neither Java nor C# allow that kind of controll over integer types. Mind you there is A# (Ada for CLI).

    Martin

    1. Re:Use a language with build in prooving. by bodan · · Score: 1
      There some programming lanugages (Ada, SPARK and Eiffel spring to my mind) which have the verification build in (to some degree). Just in case you wonder how that works here my favorite Ada example: type Day_Of_Month is range 1 .. 31; Neither Java nor C# allow that kind of controll over integer types. Mind you there is A# (Ada for CLI).
      Well, they don't quite allow this control on integer types. But you don't need to use integer types, you can use an enum in Java (with methods for operations), and I _think_ C# allows you to redefine operators to make a type that works just like the integers in your example. But there's another issue that's bothering me: range 1 .. 31 is not a valid type for the day of the month, because half of the months don't have 31 days. So you actually need a full Date class that can figure out how many days each month has. (Which is hard; you have leap years, and exceptions to that, and for very long time periods (thousands or millions of years) the formulas is hard to get right. If you want a Time class that follows leap seconds and stuff, you're fracked...)
      --
      "I think I am a fallen star. I should wish on myself."
    2. Re:Use a language with build in prooving. by krischik · · Score: 1

      Well, you are right - you need a Date class. It is all about refined. As long as you don't know the month you can't check the date further the 1..31. It's kind of a first step.

      Once you know the month inside a Date class you can do more checks. But you won't need to check for the date to be >0 or 32 any more - theese cases have allready been handled.

      Martin

  16. Re: (So were Pascal, Modula, and Ada.) by krischik · · Score: 1

    Well at least Ada still is: http://www.praxis-his.com/sparkada and very successfull as well.

    And Ada isn't dead, it just got another rejuvenation in the form of Ada 2005: http://www.adaic.com/standards/ada05.html.

    So the use of past tense was not appropiate.

    Martin

  17. Re: (So were Pascal, Modula, and Ada.) by hritcu · · Score: 1
    --
    If you don't fail at least 90 percent of the time, you're not aiming high enough. (Alan Kay)
  18. Verification gets a boost from managed langs by icepick72 · · Score: 2, Interesting

    Verification is speeding along because of managed languages. Verification for managed languages like Java and C# is easier to implement. Not so much for C/C++ where pointers are raw. (Note: C# allows unmanaged code but by default it's managed and I assume most developers work in C# in managed mode, except where performance or interopability is required)

  19. Re: (So were Pascal, Modula, and Ada.) by krischik · · Score: 1

    http://www.adacore.com/home/ada_answers/lookwho

    I work for one of the named companies ;-) and for our "mission critical" applications we have no intention to change.

  20. Semaphores in Ada by krischik · · Score: 1

    But Ada does not expose the use of Semaphores - The task model of Ada is based around Rendezvous.

    There are some attempts of Rendezvous based threading for other languages but it proves difficult since you need some inter-task parameter passing mechanism. Remember that a Rendezvous is a bit like a function/procedure call only the parameters are passed from one task to another.

    And parameter passing is a language feature and quite difficult to implement as a library. I know because I tried using by using Observer/Notifier pattern and adding the parameters to the message. But it was never as elegant or worked as flawless an Ada Rendezvous.

    Martin

  21. Please verify: by RAMMS+EIN · · Score: 1

    ``Is Code Verification Finally Good Enough?''

    Please verify that

    (define (foo n)
            (cond
                    ((= n 1) 1)
                    ((even? n) (foo (/ n 2)))
                    (else (foo (+ (* n 3) 1)))))

    returns 1 for any positive integer n.

    --
    Please correct me if I got my facts wrong.
  22. Well typed-ness matters, not the halting problem. by DamnStupidElf · · Score: 1

    Anyone can come up with a list of algorithms for which the answer to all inputs is unknown, of which the 3n+1 problem is one (so far). Even though we can't prove that the algorithm halts we can still prove that it's well typed, which in practical terms is much more important because it prevents buffer overflows and any number of other programming errors. In addition, we can also prove that the algorithm actually does solve the 3n+1 problem and not some similar but slightly different one. For instance, if you weren't using a LISP variant the algorithm would have to handle numbers larger than machine integers appropriately, especially because inputs within the machine integer range can easily grow much larger over the course of the algorithm.

    Most software today only uses algorithms that halt with known time and space complexity, which makes software verification tractible in practice. The problem is that most programmers do not have the necessary training and experience to write proofs for complex programs, and are unable to simplify their programs into small provable functions and modules. Modern operating systems also impose a lower bound on the usefulness of correctness proofs because they have not been proved correct. Even if an operating system was proved correct, all the underlying hardware would need formal verification, and even then there would only be a statistical guarantee of correctness due to random uncorrectable hardware errors. At least it's always possible to increase the reliability of hardware with redundancy and error correcting techniques, but software needs to be formally verified at some point.

  23. Re:Well typed-ness matters, not the halting proble by RAMMS+EIN · · Score: 1

    ``Even though we can't prove that the algorithm halts we can still prove that it's well typed, which in practical terms is much more important because it prevents buffer overflows and any number of other programming errors.''

    For preventing buffer overflows, you will have to prove that some value being used as an array index is an integer in the range from 0 to the size of the buffer minus 1. In this case, the problem is to prove that the result is an integer in the range 1 to 1. Most type systems aren't expressive enough for these kinds of proofs, and those that are suffer from the halting problem. Either way, type checking doesn't cut it.

    --
    Please correct me if I got my facts wrong.
  24. Re:Well typed-ness matters, not the halting proble by DamnStupidElf · · Score: 1

    For preventing buffer overflows, you will have to prove that some value being used as an array index is an integer in the range from 0 to the size of the buffer minus 1. In this case, the problem is to prove that the result is an integer in the range 1 to 1.

    Generally, proofs for this are expressed as loop invariants inside of functions, and as predicates on the entry and exits of functions. If a function takes an array index as a parameter, there is a predicate that 0<=i<n, and it is the responsibility of the caller to prove this condition. If an array index is returned, the function must prove 0<=i<n before it returns. This can usually be done at compile/proof time, but if necessary dynamic runtime checks can be added to simplify the proofs. Proving that the 3n+1 problem halts or not is quite different from proving memory-safe array access.

    Most type systems aren't expressive enough for these kinds of proofs, and those that are suffer from the halting problem. Either way, type checking doesn't cut it.

    That depends on the proof system, I suppose. Proofs in LF for instance are always decidable via typechecking of the proof itself, so if a proof can be represented in a logic using LF, the halting problem will not hinder proof checking. LF can encode second order logic just fine, so I don't think there are any big limitations on what algorithms can be proved. Generating a proof may prove difficult or impossible for certain algorithms, but that is strictly due to our limited knowledge, not a limit in the logical framework.

  25. Re:Well typed-ness matters, not the halting proble by FrostedChaos · · Score: 1

    Ok, I have a program that, if it halts, causes a buffer overflow.
    Otherwise, it doesn't.

    Can your type system prove that there is no buffer overflow?

    --
    "Any connection between your reality and mine is purely coincidental." -Slashdot
  26. Coming from the hardware side... by netchipguy · · Score: 1

    Formal Verification has become a staple of hardware design. It basically comes in two forms: equivalence checking (used a LOT to compare two similar designs) and model checking (which is slowly making inroads; used to compare a design against a set of rules, another model, etc).

    I have often wondered why more formal techniques aren't deployed in the software world.

    As has been mentioned here, the thing about formal is that you will often "stump it" and so you may need to "help it" in complex, real world designs. But it does find many silly mistakes, not necessarily (or even usually) design mistakes, but version mismatches, tool bugs/config errors, etc.

    Equivalence Checking is VERY useful for checking last minute changes. For example, when adding an option to the design, it is quick and easy to prove that the design is unchanged when the option is not enabled. We also use it to check compiled (gates) versus source (RTL) versions of designs.

    I could imagine both models being useful for software developers. For example, formal equivalency tools could help prove that the "golden version" of a function is functionally equivalent to the "performance tuned" version (hand-tuning the code, compiling it, etc.)

    Formal Model Checking is harder because writing formal rules is a painstaking process. You'll never realize how incomplete "human" specifications are until you try to constrain a formal model checker. It will find a boatload of failure cases that are "obviously not going to happen" (so obvious that they weren't included, and need to be added, usually iteratively).

    Model checking has seen an uptick lately through shipping tools with lots of default rules included (making it a form of "super LINT"). At which point adding your own rules/specifications is something you do at your leisure.

    It's these kinds of point uses, versus a theoretical complete verification framework, that formal methods can deliver today.

    -netchipguy

  27. Re:why more formal techniques aren't deployed by lwriemen · · Score: 1

    Because too many software "craftsmen" think "methodologies ... are all bullshit". They believe they are artists, not scientists, and reject rigor as untried academic exercises that stifle creativity.