Beyond reformatting: More code cleanup

The OpenSSL source doesn’t look the same as it did a year ago. Matt posted about the big code reformatting. In this post I want review some of the other changes – these rarely affect features, but are more than involved than “just” whitespace.

Previously, we’d accept platform patches from just about anyone. This led to some really hard-to-follow pre-processor guards:

#if !defined(TERMIO) && !defined(TERMIOS) \
  && !defined(OPENSSL_SYS_VMS) && !defined(OPENSSL_SYS_MSDOS) \
  && !defined(OPENSSL_SYS_MACINTOSH_CLASSIC) && \
  !defined(MAC_OS_GUSI_SOURCE)

Can anyone reasonably tell when that applies? And there were many that were just plain silly:

#if 1 /* new with OpenSSL 0.9.7 */

#ifdef undef

So we did a couple of things.

Unsupported platforms

First, we’re no longer supporting every known platform; it has to be something that either someone on the team has direct access to, or we have extensive support from the vendor.

Back in the fall we kicked off a discussion on the openssl-dev mailing list about removing unsupported platforms. Based on feedback, Netware is still supported and people are contacting some vendors to get them to step up and help support their platform. But the following are now gone:

  • Sony NEWS4
  • BEOS and BEOS_R5
  • NeXT
  • SUNOS
  • MPE/iX
  • Sinix/ReliantUNIX RM400
  • DGUX
  • NCR
  • Tandem
  • Cray
  • Win16

OpenSSL never supported 16-bit (neither did SSLeay, really), and we just never made that explicit.

Live/dead code

Almost every instance of #if 0 or #if 1 had the appropriate code removed. There are a couple of places where they remain, because it could be useful documentation. For example, this block in ssl/s3_lib.c:

#if 0
  /*
   * Do not set the compare functions, because this may lead to a
   * reordering by "id". We want to keep the original ordering. We may pay
   * a price in performance during sk_SSL_CIPHER_find(), but would have to
   * pay with the price of sk_SSL_CIPHER_dup().
   */
   sk_SSL_CIPHER_set_cmp_func(clnt, ssl_cipher_ptr_id_cmp);
   sk_SSL_CIPHER_set_cmp_func(srvr, ssl_cipher_ptr_id_cmp);
#endif

The once place they do remain is in the crypto/bn component. That’s just because I’m scared to touch it. :) That directory counts for about one-third of all remaining instances. Compared to 1.0.2, which had 343 instances in 165 files, we now have 43 instances in 31 files, and I hope we can reduce that even more.

ifdef control

Over time, some feature-control #ifdef’s evolved into inconsistencies. We cleaned them up, merging OPENSSL_NO_RIPEMD160 and OPENSSL_NO_RIPEMD into OPENSSL_NO_RMD160. Similarly, OPENSSL_NO_FP_API was merged into OPENSSL_NO_STDIO. (We’ll soon make that buildable again, for embedded platforms.)

Also in this area, configuration used OPENSSSL_SYSNAME_xxx which was internally mapped to OPENSSL_SYS_xxx. Removing that mapping, in conjunction with removing some old platforms, made parts of the internal header file e_os.h much simpler, but we there is still room for much improvement there.

The biggest change was removing about one-third of the nearly 100 options that we used to support. Many of these had suffered severe bit-rot and no longer worked. The biggest part was removing the ability to build OpenSSL without other parts of the library: BIO, BUFFER, EVP, LHASH, HASH_COMP, LOCKING, OBJECT, STACK are no longer optional; OPENSSL_NO_BIO has no effect (and will hopefully generate a warning). We also removed support for the broken SHA0 and DSS0, the CBCM mode of DES (invented by IBM and not used anywhere), and the maintenance of our own free lists, OPENSSL_NO_BUF_FREELISTS. This last got us some flack erroneously sent our way, but it was clearly a holdover from when the major supported platforms did not have efficient malloc/free components.

Dynamic memory cleanup

We did a big cleanup on how we use various memory functions. For example:

a = (foo *)malloc(n * sizeof(foo))

had a needless cast, and would quietly break if the type of a changed. We now do this consistently:

a = malloc(n * sizeof(*a));

Similar sizeof changes were done for memset and memcpy calls.

We also stopped checking for NULL before calling free. That was huge, requiring over a dozen commits. It also reduced code complexity, and got us a few extra percentage points on our test coverage. :)

Summary

The OpenSSL code base has a long and storied history. With these changes, the reformatting, and others, I think we’re making good on our commitment for the future.