Search code examples
cdebuggingmemory-managementgslraylib

How do special libraries in C cause memory allocation to fail or interact improperly?


Specifically the libraries of GSL and Raylib have special memory allocation functions that include allocs() and free() based on their respective structures and implementations. However, these are just specific examples, there are times when C memory allocations being used by different components interact and cause segmentation faults even when they are being used properly by the program running them. What is this problem called, why does it occur, and what are the best practices to keep memory allocations from interfering with each other?


Solution

  • there are times when C memory allocations being used by different components interact and cause segmentation faults even when they are being used properly by the program running them. What is this problem called, why does it occur, and what are the best practices to keep memory allocations from interfering with each other?

    That's usually not the case. Memory allocations do not "interfere with each other" apart from heap memory fragmentation over time, which isn't an error state but can lead to slower access or memory waste.

    More commonly there are bugs in the application using the library:

    • "Out of bounds" bugs, when the application is accessing arrays/pointers out of bounds. Usually leading to "seg fault" on *nix-based systems.

    • "Heap corruption" bugs, which is just another flavour of the above, since out of bounds access could cause corrupted data on the heap rather than a seg fault. But this error is also often caused by the application incorrectly assigning the pointer returned from the allocation function to some other memory location, then trying to use/free the invalid pointer.

    • "Memory leak" bugs, when the application is not calling the corresponding free() function after it is done using the object.

    • "Dangling pointer" bugs, when the application is accessing an object after calling the corresponding free() function in the library.

    • "Double free" bugs, where the corresponding free() function of the library is called twice, first on a valid object, next on an invalid object.

    Best practices to avoid the mentioned bugs:

    • "Clean up your own mess". The code module allocating a resource/opening a file etc is also responsible for cleaning it up. In case of library code, this means that a clean-up function needs to be provided by the library API and what is should be used on should be documented.
    • Never assume that "the OS is going to free the resources anyway so I don't need to do that". Yes, it is true that the OS will clean up most such things, but if your program does not attempt to free resources, you will not notice a whole lot of the above mentioned bugs either. If you free resources manually then you will spot bugs early on in the development phase and not very late after product release.
    • Use bounds-checking if you are unsure if some index variable is within the allocated range.
    • Perform input sanitation at the point where your program is taking input.
    • Initialize all pointers that are to be used for dynamic allocation to NULL, if they aren't assigned to dynamic memory shortly after the point where they are declared.
    • After freeing something, set the pointer to NULL.
    • free(null_pointer) is a safe no-op - it is guaranteed by C that nothing will happen if you try this.
    • Always check the result of malloc (and friends). Or in case of a library allocating the resources, always check the status/error codes returned from it.
    • Don't use dynamic allocation just for the heck of it, or in order to micro-manage heap memory consumption. Small amounts of data (<100 bytes or so) typically shouldn't get heap allocated at all, if a fixed max size buffer could as well solve the problem.