The C programming language has many dark corners, and is frequently misused in various ways. Use it carefully.

Undefined Behavior

There are 191 undefined behaviors in C99, they tend to be unnoticed since the gcc hegemony and the fact it normally behaves as it would be naively expected. There are different compilers and even gcc would behaves surprisingly in certain architectures.

The compiler can take any unexpected behavior and be standard compliant, in practice some deleted entire seed computations, deleted safety checks, caused exploitable vulnerabilities, caused crashes, etc.

Please read this three-part series on undefined behavior in C. It is worth avoiding them all.

According to the C specification, a program with any undefined behavior in it is undefined. Luckily, no compilers are optimizing following this statement, yet.

Integer values pitfalls

Integers in C are not as obvious and intuitive as expected. This quiz shows most of the interesting and peculiar properties.

Integer promotion

Operation with operands with different size and sign cause the promotion of some of them to match.

The integer promotion rules (also in page 45 of the C99 specification) are sometimes surprising.

Here is a nice example....

#include <stdio.h>
int main (void)
{
  long a = -1; 
  unsigned b = 1; 
  printf ("%d\n", a > b); 
  return 0;
}

On x86-64 linux and gcc, it returns 0; compiled with -m32, it returns 1. Follow the link to find out why.

Signed integer overflows are undefined

Signed integer overflow is undefined behavior: you cannot assume that they obey obvious 2s-complement semantics. The compiler can optimize away the code entirely or otherwise do unwanted things. More information here.

How should you check if something is too big?

  • Subtract from the maximum value.

DO

int a = something();

if (INT_MAX - 1 < a) {
   return ERROR;
} else {
   some_processing_with(a + 1);
}

DO NOT

int a = INT_MAX;
if (a + 1) <= 0 {
   // ... stuff here that may or may not run depending on the compiler
}

Depending on the compiler, x + 1 > x can vary (if x is already the maximum value of the type), or (CORRECTLY, according to the C spec) always return true (defeating any attempt to use this as an overflow check), because x + 1 overflowing is undefined if x is in a signed variable, and the compiler is allowed to do ANYTHING when code is undefined. GCC is known to at least sometimes use the 'always true' approach; be careful.