2020-10-30

c memory management

stack

  • stack memory is automatically (pre-)allocated memory of your process, requested with variable declaration
  • with local variables it is bound to the scope of the function, can be used by callees, but when the function ends, the memory is freed
  • it can therefore not be returned from the function that declared it

heap

  • heap memory is additional memory for your process
  • think of allocating heap memory as requesting an access token for using reserved storage in a database
  • the request can fail
  • only automatically deallocated when the process ends

ownership

  • it might be helpful to think in terms of ownership for allocated memory
  • the current owner is the function that is responsible for eventual deallocation
  • ownership can be given, received and lend

memory leaks

  • not freeing unneded memory is called a memory leak
  • the available space will eventually be filled, preventing new memory from being allocated
  • it prevents programs from running for an indefinite amount of time
  • tools like valgrind can help to trace and find memory leaks

null pointers

  • a pointer is a variable that stores a memory address
  • a null pointer can be created by setting a pointer to zero
  • trying to free a null pointer is usually allowed, but trying to dereference such a pointer leads to an error

double free and corruption

  • calling free on a pointer whose address has previously been freed is an error
  • memory corruption can occur when the program haphazardly wrote into the memory outside of the allocated range. this can mess up management structures of the allocator and is a common attack area for security exploits

life time

  • the c compiler has no indication of when memory is not needed anymore. how long a memory area is needed may depend on various application conditions. references to memory areas can be passed between and persist between routine calls. memory stays allocated even if no variable has a reference to it
  • at allocation, decide when the memory is going to be freed. in the successful execution flow as well as when errors occur

freeing all memory allocations up to point

  • when multiple memory areas are allocated and errors occur inbetween, the memory allocated up to point might have to be freed
  • this can be achieved by tracking allocated addresses locally

example

  • this example uses sph-sc-lib memreg

    • sph-sc-lib also contains a version for multiple named registers and a heap allocated register that can be passed between function calls
  • memreg_init(4) creates an address register on the stack for at most four pointers
  • memreg_register is the variable and memreg_index is the current index
  • memreg_add(address) adds a pointer to the register
  • memreg_free frees all pointers added so far
#include "sph/memreg.c"
int main() {
  memreg_init(2);
  int* data_a = malloc(12 * sizeof(int));
  if(!data_a) goto exit;  // have to free nothing
  memreg_add(data_a);
  // more code ...
  char* data_b = malloc(20 * sizeof(char));
  if(!data_b) goto exit;  // have to free "data_a"
  memreg_add(data_b);
  // ...
  if (is_error) goto exit;  // have to free "data_a" and "data_b"
  // ...
exit:
  memreg_free;
  return(0);
}