Missing Braces in Conditionals

Every programmer eventually encounters an error like this and spends hours trying to figure out why it wasn’t working.

  1. const bool result = fetch_files();
  2. if (result) {
  3. process_files()
  4. }
  5. else
  6. print_error()
  7. return false;
  8. // Now cleanup and return success
  9. cleanup_files();
  10. return true;

The reason of course was the else statement wasn’t enclosed in braces so the wrong code was executed. The compiler might spot dead code in this instance but that may not always be the case. Even if it did, it might only issue a warning instead of an error.

The problem can be especially annoying in deeply nested conditions where a misplaced brace can attach to the wrong level.
This problem has lead real-world security issues. For example here is the infamous “goto fail” bug that occured in some Apple products. This (intentional?) bug occured during an SSL handshake and was exploitable. :

  1. static OSStatus
  2. SSLVerifySignedServerKeyExchange(
  3. SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
  4. uint8_t *signature, UInt16 signatureLen)
  5. {
  6. OSStatus err;
  7. //...
  8. if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
  9. goto fail;
  10. if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
  11. goto fail;
  12. goto fail;
  13. if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
  14. goto fail;
  15. //...
  16. fail:
  17. SSLFreeBuffer(&signedHashes);
  18. SSLFreeBuffer(&hashCtx);
  19. return err;
  20. }

Note how the “goto fail” is repeated twice and not bound to the condition but is indented as if it was. The code would jump straight into the fail label and return with an err indicating success (since the prior SHA1 update had succeeded). If conditionals

How Rust helps

Rust requires if-else expressions and loops to be associated with blocks.

So this code won’t compile:

  1. let mut x: i32 = do_something();
  2. if x == 200 {
  3. // ...
  4. }
  5. else
  6. println!("Error");

If you try you will get an error like this.

  1. rustc 1.13.0-beta.1 (cbbeba430 2016-09-28)
  2. error: expected `{`, found `println`
  3. |
  4. 8 | println!("Error");
  5. | ^^^^^^^
  6. |
  7. help: try placing this code inside a block
  8. |
  9. 8 | println!("Error");
  10. | ^^^^^^^^^^^^^^^^^^
  11. error[E0425]: unresolved name `do_something`
  12. |
  13. 3 | let mut x: i32 = do_something();
  14. | ^^^^^^^^^^^^ unresolved name