1. 29
  1. 5

    What a weird argument. Part of writing solid C code is testing it. As far as I know, nobody writes bug free code in any language.

    1. 13

      I gave the author the benefit of the doubt and assumed they were talking about working with tests. I think the point still stands.

      1. 6

        It’s not. Different languages have different classes of bugs. Those in C/C++ tend to have disastrous consequences.

        1. 9

          Such statements would be less hyperbolic if people recognized that only a small subset of C bugs belong in that class of potentially-disasterous and exclusive to C, and that only a small subset of such bugs make it through code review and testing, and that a small subset of these bugs are actually exploitable in the real world.

          Bugs in C programs get publicized really often because there’s a crapton of such code out there in active use. But that kind of publicity doesn’t give people any sense of scale, and the issue is blown completely out of proportion. If that weren’t enough, the discussion will derail into UB and people assume a deliberately adversial compiler that literally tries to turn every instance of UB into an exploitable bug. It almost sounds as if the standard somewhere said that compilers are not permitted to let the code behave in any reasonable manner in the face of UB…

          1. 17

            if people recognized that only a small subset of C bugs

            That mostly don’t exist when using a type-safe, memory-safe language in most of your code. It’s impossible to write idiomatic code in them with the same errors resulting in something more than an exception. Most hackers aiming for code injection in such languages try to hit the runtimes or libraries that are written in C or C++. Says a lot.

            Meanwhile, there were operating systems written in SPARK Ada, Modula-3, Java, and Rust whose unsafe portions were kept to a much lower percentage with rest immune to entire classes of vulnerabilities. Microsoft’s VerveOS made those parts safe with proven assembly the rest of the OS (in C#) interfaced to. I bring these up to preempt the common counter of the lower parts having to be written in C/C++ because they’re the only thing that can handle low-level stuff. I get that false claim a lot in these discussions.

            1. 4

              Just as a simple example, the very common failures to properly parse input strings and firewall them from e.g. SQL databases are language independent.

              1. 7

                We’re talking about whether using a different language improves security by removing an entire class of bugs. The status quo Im countering are C and C++ bugs leading to code injection that controls the machine. You side-step that evidencw to counter that people building web or database apps can have an extra problem.

                So what. That average programmers are producing things immune to many forms of code injection by default is already better than C/C++ situation where even veterans get hit by those bugs periodically. And if you’re concerned about SQL injection, there’s similarly methods to immunize against it in apps. Ur/Web, Opa, and Spectre are examples of languages or platforms foing stuff like that.

                So, the empirical evidence shows these other languages and preventative methods knock out lots of peoblems. That’s a net gain as secure coding is rare skill. From there, there’s still stuff to watch for.

            2. 1

              a small subset of C bugs belong in that class of potentially-disasterous and exclusive to C

              Could you elaborate on this class? What are the typical disastrous gotchas exclusive to C? Is there a list on a paper or somewhere?

              1. 4

                Buffer overflow (including those induced by C’s strange string semantics) and use-after-free are the big common ones; also integer overflow can immediately be a security bug in C. Switch fall-through is not quite unique to C but close. I’m sure there are more that we’d notice if we fixed those.

            3. 1

              That argument would require some specifics and data - not the “I can’t write C/C++ without testing” presented in the article.

          2. 5

            There’s a comical disparity between the number of people bitching about C and C++ and the number of people actually rewriting infrastructure in a higher level language.

            If you can’t write C or C++ safely, use something else.

            The web’s cargo cult hate on C and C++ gets tiring.

            1. 5

              One thing you miss there is that there’s tools that help in analyzing, refactoring, parallelizing, speedy iterating, and certifying compilation of these non-C/C++ languages that are high-level. The literature shows even professionals benefit from these things.

              That C++ in particular is enormously complex means those commiting to it are always going to get lower cost-benefit analysis than those using languages with great tooling.

              1. 5

                One thing you miss there is that there’s tools that help in analyzing, refactoring, parallelizing, speedy iterating, and certifying compilation of these non-C/C++ languages that are high-level. The literature shows even professionals benefit from these things.

                The same types of tools are available for C++ and C. I would even go so far as to say a person isn’t a professional if they’re not using those tools to improve their code.

                That C++ in particular is enormously complex means those commiting to it are always going to get lower cost-benefit analysis than those using languages with great tooling.

                With the exception of Java, I would say that C++ actually has better tooling than most languages. There are tons of open source (valgrind, etc.) and proprietary (Coverity, etc.) tool for doing static analysis, finding buffer overflows, etc.

                On top of that, (IME) C++ devs are more likely to use static analysis tools, precisely because everybody knows how easy it is to introduce vulnerabilities in C++.

                1. 5

                  C has better tooling than C++ because it’s a simpler language. As one example, there is verified C compiler, and no verified C++ compiler.

                  1. 2

                    C has these tools but hurts you even as it helps. C++ has nowhere near what Java has in tooling for analysis. That’s because most CompSci effort went into Java. It and C have most open tooling with Java, Ada/SPARK, and Rust currently the easiest to get low vulnerabilities in system software.

                2. 5

                  I feel like this comment is a parody of itself. There is at least as much people bitching about people that bitch about C and C++. Don’t you think that’s just as cargo culty and tiring?

                  1. 1

                    One of those groups builds and maintains a much larger share of working software than the other.

                    1. 5

                      Indeed. Most C++ programmers I know do complain about C++ quite a bit! Of course, that is not relevant to my point. What’s your point, exactly?

                3. 4

                  If you want to get rid of C, you have to upgrade the C runtime. The common virtual machine is specified in C, kernels are written in C, libraries export C symbols, and so people keep using C.

                  If there was a richer ABI, writing in a richer language would have a bigger payoff, libraries could express programmer intent and still feel “native”, etc.

                  As it is, every module/library/ffi boundary drops you right back to C land.

                  1. 4

                    I’m not really convinced that there’s a substantially better inter-language minimum interface that all other platforms would agree on and be able to use.

                    1. 2

                      The JVM and the CLR offer multi-language interfaces that are much richer than those in C, and avoid huge classes of bugs - at least on the JVM, the library base is big enough that you really don’t have to FFI into C. Honestly most stuff that’s written in C++ should be written on one of those instead, but people always think they need more performance and less safety than they do.

                      On the server side the ABI is becoming the likes of AMIs rather than processes, and you can produce those just as well using a safe language that builds to a unikernel (i.e. OCaml). With the rise of things like Qubes that may yet become the way things work on the desktop too.

                    2. 2

                      Now add threading to that….. and I suspect there are very very few competent C/C++/Python/Ruby/…. programmers.

                      I have hear tell their may be some competent Rust programmers that can do threading…. I’m not convinced yet.

                      Threading is fundamentally borken paradigm.

                      1. 17

                        I have hear tell their may be some competent Rust programmers that can do threading…. I’m not convinced yet.

                        Well, Rust is one of the rare language out there in production with type-level support for shared-nothing, shared-immutable and mutably shared systems (through the Send + Sync markers). All this happens without overhead at runtime. That means: a Mutex is still a Mutex and will incur its necessary runtime cost, but all other checking of its valid use is fully static. They are certainly not silver bullets, but can help a surprising lot.

                        Now, this seems simple at first, until you get behind a couple of things:

                        • Knowing the sharing properties of structures allows us to write safe generic execution systems, such as rayon, which provides drop-in parallel iterators.
                        • Knowing the sharing properties of structures and the global enforcement of them allows you to prove when synchronization is not necessary. Many multi-threaded systems suffer from a pessimistic approach to locking, as this is very hard to prove manually.
                        • My running theory is that many simple bugs in concurrent code are introduced when refactoring a non-concurrent implementation to a concurrent one. Type system support guides you through the process.

                        It is literally one of the magic pieces behind Servo and Stylo (its styling engine): allowing to draw non-trivial conclusions about the threading properties of the program easily.