1. 21
  1.  

  2. 9

    What would be really interesting would be to see them take a look at OpenBSD. No matter the result, there would be a lot of crowing going on from some direction. =)

    1. 1

      I’ve been running cppcheck for the past few days on OpenBSD src, sys and xenocara.

      The results are worrying, in my opinion, but I suck at programming.

      When I have some time I’ll try to address the issues at the tech mailing list.

    2. 4

      And yet, even when correcting such “silly” errors, it’s still easy to make more. Observe the proposed “correct” version for the second instance of V579:

      bzero(dst, sizeof(*dst));
      

      This looks fine on its own, but in the context of the original code, we see that dst is in fact a void*, so unless they really intended to zero a single byte by leveraging the GNU sizeof(void) == 1 extension, it’s still wrong. I strongly suspect the actual correct version would be:

      bzero(dst, size);
      

      (size here is an additional argument to the function in question elided from the abridged version in the viva64.com post; see http://sources.freebsd.org/HEAD/src/sys/dev/acpica/acpi_package.c)

      1. 3

        Interesting, a bunch of silly looking mistakes. I’m not sure how severe any of them are. Any FreeBSD devs have any thoughts on the output? For several of them it feels like the two conditional paths actually did different things and eventually got changed to do the same thing and the author of the change either didn’t check or didn’t know what to do.

        1. 4

          Perhaps interestingly, some of these bugs would also be present with stricter statically typed languages, as they represent perfectly valid code. But, to be fair, some may have been avoided because those languages often are more strict syntactically.

          What does a typo proof programming language look like?

          1. 3

            What you need for typo-proofing is to do these same sorts of analysis, but interactively. That’s not really a property of the programming language.

            You could make some of these typos less likely with language changes, such as always requiring { … } after an if(), but that particular one reliably gets requests to relax it, and most language designers aren’t thinking from this perspective and don’t feel strongly about the issue. It really is easy to convince oneself that syntactic resilience isn’t that important, especially in a language that doesn’t have legacy code yet.

            I was tempted to talk about structure editors, until I read the article and realized that they solve an orthogonal problem.

            1. 5

              What you need for typo-proofing is to do these same sorts of analysis, but interactively.

              Yes, for sure. But, I’m think that there are other semantics and rules that languages can define. $a > $a is always false for integers, though in the presence of operator overloading, perhaps we can’t be sure, generally. Other possibilities:

              1. explicitly ignore unused variables (with _ or _thing [erlang, go])
              2. bail out of compilation on discovery of unused import [go].
              3. Strict formatting of source code [go] (also discussed by your comment)
              4. Fail to compile on things that would introduce undefined behavior based on lang’s operational semantics.

              Edit: Rust’s memory model, and Linear types and things like that are also semantics that would reduce typo errors. Though, they also reduce logical errors as well.

              1. 1

                Those sound like good heuristics, I like all of them.

                A lot of things are caught by striving for warning-free compilation, but the perennial problem there is that differences of opinion eventually cause warnings to slip in, at which point new ones get lost in the noise and the approach is useless. An approach I’ve seen used to good effect is to require individual instances of warnings to be whitelisted, and otherwise to treat them as fatal.

                I’m very much in favor of linear types. I suppose we could go back and forth on whether they’d help with typos and other simple oversights, and whether what they do counts as the same thing - but it’s a good thing, regardless.

            2. 3

              Some of these I’m surprised compilers don’t already catch. Doesn’t a C compiler tell you when an expression can never be false or true? For other ones of these, I wonder if they are actually bugs. For example, doing the same thing in the then block as the else block, is that a bug, in that it expresses the wrong behavior at run-time, or is the conditional vestigial?

              1. 2

                Doesn’t a C compiler tell you when an expression can never be false or true?

                It is probably a warning… and not included in -Wall.

                In addition to static types, maybe we need static intention checks. If you really want the same block in 2 conditional branches, you must conjoin the conditions, which shows intention, for instance.

                “Are you sure about this? Your intention would be clearer if you wrote it this other way,” is the type of thing I am after. Of course maybe it is too subjective.

                1. 1

                  It is probably a warning… and not included in -Wall.

                  Experimentally, that appears to be the case for GCC (tested version 5.3.0) – clang, however (at least as of version 3.5), includes -Wtautological-compare in -Wall, and hence warns about this.

              2. 2

                There’s obviously some give and take here, but I think that a strong reliance on macros and higher-order functions to avoid code duplication would play a really big role.

                Almost all of these errors are some version of copy paste or patterns—and, as you note, static typing doesn’t inherently help with that. But the trivial ability to programmatically generate code can encourage you not to have patterns you get used to staring at might: since each piece of code would be significantly more unique, you’d be less likely to fall into the trap of glossing over a pattern you’d seen before, only to realize there was some subtle difference.

                That’s just a guess, though. Anecdotally, I’m not sure that I see fewer of these errors in, say, Lisp versus C# (or some other language that’s got higher-level constructs than C). And as I’m sure tedu would be quick to point out, most of the errors in this post are trivially possible in Rust/Common Lisp/etc. anyway.

                1. 2

                  That’s just a guess, though. Anecdotally, I’m not sure that I see fewer of these errors in, say, Lisp versus C# (or some other language that’s got higher-level constructs than C).

                  Exactly. Which still begs the question: “What does a typo proof programming language look like?”

                  As a lisper at heart, I asked myself could I still make these errors there? And, the answer is undoubtedly yes. It might, though, be the case that I could write safer, semantically macros such that silly errors such as (> 1 1) aren’t possible. Imagine (using a pseudo-lisp):

                  (defmacro (safe> x y)
                      (if (= x y) ;; compare the var, not the value.
                          (error "this can never be true")
                          `(> ,x ,y)))
                  

                  But, there’s nothing forcing me to use this, and given higher order functions, I can’t in all places. That said, failing to compile (> a a) is only valid when you’ve explicitly typed (> a a) and not for all places such that you are asking (> x y) where x happens to be equal to y, so there’s that.