/Teaching/System Level Progamming/Assignments/Pitfalls

Pitfalls

Memory allocation

Suppose that we want to allocate an array of integer pointers. This is done via:

int** lookupTable = (int**)malloc(n * sizeof(int*));

We frequently encountered the following statement:

int** lookupTable = (int**)malloc(n * sizeof(int));

Though not correct, it works on platforms, where sizeof(int) == sizeof(int*) (e.g. x86). On x64 platforms, however, we have sizeof(int) == 4 and sizeof(int*) == 8. In this case the amount of allocated memory is too small, which results in a segmentation violation as soon as memory beyond the allocated range gets accessed.

Operator Precedence

Consider the following code snippet:

void deallocate(int*** lookupTable) {
  int i = 0;
  
  for(; i < MAX; i++) {
    free(*lookupTable[i]);
  }
  free(*lookupTable);
  *lookupTable = NULL;
}

Note that the []-operator has lower precedence level than the dereference-operator. This is why, Line 5 reads as *(lookupTable[i]), even though (*lookupTable)[i] was intended and is necessary to free the allocated memory correctly.

Deadlocks

Consider the following code snippet:

  Basin* basin = 0;
  Soap* soap = 0;
  while(!basin || !soap)
  {
    if (!basin)
      basin = cloakroom_.acquireBasin(this, false); // acquires a lock
    if (!soap)
      soap = cloakroom_.acquireSoap(this, false); // acquires a lock
  }

A common mistake in SNP A9 was to write something like the code above. This causes a problem if two threads simultaneously run through this loop and one gets the only (remaining) basin and the other the only (remaining) soap. Both threads will loop forever because they can never acquire each others resource.

READ the POSIX standard

Before you use or implement a POSIX compatible function read the POSIX standard to this function. Wrong signatures, wrong usage, wrong behavior are very common mistakes!