Skip to content

Comment on The Heartbleed Bugparent

Comments

The problem with C is that a lot of people don't write it well.

Including people responsible for one of the most important security-related library in the world. No matter how good and careful a programmer is, they are still human and prone to errors. Why not put every chance on our side and use languages (e.g. Rust, Ada, ATS, etc.) that make entire classes of errors impossible? They won't fix all problems, and definitely not those associated with having a bad code base, but it'd still be many times better than hoping people don't screw up with pointers lifetime.

Why not put every chance on our side and use languages (e.g. Rust, Ada, ATS, etc.) that make entire classes of errors impossible?

I don't think intentionally preventing the programmer from doing certain things the computer is capable of doing on the theory it makes errors impossible makes sense.

As I've said several times in this thread, somebody has to deal with the pointers and raw memory because that's the way computers work. Using a language where the language runtime itself handles such things only serves to abstract away potential errors from the programmer, and prevents the programmer from doing things in more efficient ways when she wants to. It can also be less performant, since the runtime has to do things in more generic ways than the programmer would.

Including people responsible for one of the most important security-related library in the world.

I think you've hit on a crucial part of the problem: practically every software company on Earth uses OpenSSL, but not many of them pay people to work on it.

  calvinow@Mozart ~/git/openssl $ git log --format='%aE' | grep -Po "@.*" | sort -u - 
  @baggins.org
  @benl-macbookpro3.local
  @chromium.org
  @cloudflare.com
  @comodo.com
  @cryptsoft.com
  @esperi.org.uk
  @fh-muenster.de
  @fifthhorseman.net
  @fsmat.at
  @gmail.com
  @google.com
  @igalia.com
  @infradead.org
  @innominate.com
  @leeds.pl
  @linaro.org
  @links.org
  @neurodiverse.org
  @openssl.org
  @opensslfoundation.com
  @pobox.com
  @roeckx.be
  @secondstryke.com
  @torproject.org
  @trevp.net
  @v3.sk
  @velox.ch
I was very surprised how short that list is. There are a lot of big names that make heavy use of this software that are not on that list.
  > I don't think intentionally preventing the programmer 
  > from doing certain things the computer is capable of 
  > doing on the theory it makes errors impossible makes 
  > sense.
With arguments like this, we'd all be back in the days of non-structured programming languages (enjoy writing all your crypto in MUMPS). Every modern language, including C, restricts itself in some way in order to make programs more predictable and errors less likely. Some simply impose more restrictions than others, though these restrictions can actually make programs more efficient (see, for instance, alias analysis in Fortran vs. alias analysis in C).
  > somebody has to deal with the pointers and raw memory 
  > because that's the way computers work
All three of the languages listed previously (Rust, Ada, ATS) are systems programming languages with the capability of manipulating pointers and raw memory (though I don't personally have any experience with the latter two). What they have in common is that they provide compile-time guarantees that certain aspects of your code are correct: for example, the guarantee that you never attempt to access freed memory. These are static checks that require no runtime to perform, and impose no overhead on running code.
With arguments like this, we'd all be back in the days of non-structured programming languages

You're confusing the difference between syntactical restrictions and actual restrictions on what one can make the computer do.

I define "things the computer is capable of" as "arbitrary valid object code executable on the CPU". (Valid here meaning "not an illegal instruction".) Any language that prevents me from producing any arbitrary valid object code is inherently restrictive. C allows me to do this. I can even write functionless programs in C, although it's often non-portable and requires mucking with the linker. If the CPU has some special instruction I want to use, I can use inline assembly.

Any language that prevents me from doing arbitrary pointer arithmetic and memory accesses prevents me from doing a lot of useful things I can do in C. See my other comment about linked lists with 16-bit pointers on a 64-bit CPU.

My understanding of Rust is that its pointers have similar semantics to the "safe_pointers" in C++. If that's the case, my understanding is that it would prevent me from doing things like the 16-bit linked list (please, correct me if I'm wrong).

Quoting your other post:

  > in C, I can make the computer do absolutely anything I 
  > want it to in exactly the way I want it to. Maybe I 
  > don't like 8-byte pointers on my 64-bit CPU, and I want 
  > to implement a linked list allocating nodes from a 
  > sparse memory-mapped pool with a known base address 
  > using 16-bit indexes which I add to the base to get the 
  > actual addresses when manipulating the list? That could 
  > be a big win depending on what you're doing, and 
  > (correct me if I'm wrong) there is no way to do that in 
  > Java or Haskell.
This is possible in Rust, you'll just need to drop into an "unsafe" block when you want to do the pointer arithmetic. In the meantime, everywhere that isn't in an "unsafe" block is guaranteed to be as safe as normal Rust code. Furthermore, even Rust's "unsafe" blocks are safer than normal C code. Rust is a systems programming language, so we know that you need to do this stuff. We have inline assembly too! Our goal is to isolate the unsafety and thereby make it easier to audit.

Interesting. Clearly I need to explore this more. :)

Rust forces you to draw safety boundaries between safe and unsafe code, but you can do almost strictly more than C in unsafe Rust. It has support for inline assembly, SIMD, packed structs, and well-defined signed integer overflow. None of these is part of standard C or C++, and is only available through compiler-specific dialects. There wasn't even a well-defined memory model with support for atomics before C11/C++11.

Why not put every chance on our side and use languages (e.g. Rust, Ada, ATS, etc.) that make entire classes of errors impossible?

Bugs will still occur, just in a different way: Java is advocated as being a much "safer" language, but how many exploits have we seen in the JRE? Going to more restrictive, more complex languages in an attempt to fix these problems will only lead to a neverending cycle of increasing ignorance and negligence, combined with even more restrictive languages and complexity. I believe the solution is in better education and diligence, and not technological.

Java is advocated as being a much "safer" language, but how many exploits have we seen in the JRE?

Very few. I don't think I can remember ever seeing an advisory for Java's SSL implementation.

Yes, bugs are possible in all languages, but that doesn't mean there's no difference between languages. I'm reminded of Asimov: "When people thought the earth was flat, they were wrong. When people thought the earth was spherical, they were wrong. But if you think that thinking the earth is spherical is just as wrong as thinking the earth is flat, then your view is wronger than both of them put together."

(There are a large number of bugs in the browser plugin used for java applets, but they have no relation to the JRE itself)

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.