2022-11-22

c memory management

part of c programming

stack

  • stack memory is automatically (pre-)allocated memory of your process, which is also used when declaring local variables
  • with local variables, it is bound to the scope of the function, and can be used by callees, but when the declaring function ends, the memory is freed
  • valid pointers can therefore not be returned from a 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 because there is not enough space or other reasons
  • only automatically deallocated/unreserved when the process ends

ownership

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

memory leaks

  • continuously allocating new space and not freeing it when it is not needed anymore is called a memory leak
  • the available memory 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 usually be created by setting a pointer to zero
  • it is not necessarily specified what bits a compiler will actually use to represent null pointers
  • 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 because there is nothing to free anymore at that address
  • memory corruption can occur when the program haphazardly wrote into the memory outside of an allocated range. this can mess up other currently allocated data structures, and it can also mess up the management structures of the allocator itself

security

  • a common tactic for security exploits is to abuse pointers to write to arbitrary memory areas

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);
}