Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad practice to hide memory allocations in functions?

Tags:

c

malloc

Should I expect the user to provide a memory chunk of sufficient size, say, for copying a file into a buffer? Or should I allocate the memory myself, and expect the user to free it when they're done? For example, the function strdup() allocates memory itself, but the function fread() expects only a buffer of sufficient size.

like image 811
dav Avatar asked Sep 05 '17 21:09

dav


People also ask

What is memory allocation and why is it important?

Memory allocation:To gain proper memory utilization, memory allocation must be allocated efficient manner. One of the simplest methods for allocating memory is to divide memory into several fixed-sized partitions and each partition contains exactly one process.

Which function can be used to deal with memory allocation?

The C malloc() function stands for memory allocation. It is a function which is used to allocate a block of memory dynamically. It reserves memory space of specified size and returns the null pointer pointing to the memory location. The pointer returned is usually of type void.

What happens if I dont free allocated memory?

In these cases, even small chunks of storage add up and create a problem. Thus our usable space decreases. This is also called “memory leak”. It may also happen that our system goes out of memory if the de-allocation of memory does not take place at the right time.

Why is malloc bad?

Why is malloc() harmful in embedded systems. Using malloc() or any other dynamic memory allocation is harmful inembedded systems because: The memory is limited in embedded systems. (it is important that you do not suddenly find yourself out of memory).


2 Answers

It depends - I've seen C APIs use all kind of patterns for this, such as:

  • functions that require the buffer and buffer size to be provided, and return the required size (so that you can adjust the buffer size if it was truncated); many of these allow passing NULL as a buffer if you are just asking how big the buffer should be; this allows the caller to use an existing buffer or to allocate an appropriately sized one, although with two calls;
  • separate functions to obtain needed size and to fill the buffer; same as above, but with a clearer interface;
  • functions that require buffer and buffer size, but can allocate the buffer themselves if NULL is passed as buffer; maximum flexibility and terseness, but the function signature can get confusing;
  • functions that just return a newly allocated string; simple to use and avoids bugs arising from unguarded truncation, but inflexible if performance is a concern; also, requires the caller to remember to free the returned value, which is avoided in the cases above if using a stack-allocated buffer;
  • functions that return a pointer to a static buffer, and then the caller is responsible to do whatever with it; extremely easy to use, extremely easy to misuse; requires care in case of multithreading (needs thread local storage) and if reentrancy is a concern.

The last one is generally a bad idea - it poses problems with reentrancy and thread safety; the one before it can be used but may pose efficiency problems - I generally don't want to waste time in allocations if I have already a buffer big enough. All the others are generally pretty much OK.

But besides the specifics of the interface, the most important point if you allocate stuff and/or return pointers is to clearly document who owns the pointed memory - is it a static object in your library? Is it a pointer to some internal of an object provided by the caller? Is it dynamically allocated stuff? Is the caller responsible for freeing it? Is it just the buffer that was provided as argument?

Most importantly, in case you allocated stuff, always specify how to deallocate it; notice that, if you are building a library that may be compiled as a dll/so, it's a good idea to provide your own deallocation function (even if it's just a wrapper around free) to avoid mismatches between different versions of the C runtime running in the same process. Also, it avoids tying your code to the C library allocator - today it may be fine, tomorrow it may turn out that using a custom allocator may be a better idea.

like image 95
Matteo Italia Avatar answered Sep 25 '22 19:09

Matteo Italia


Is it bad practice to hide memory allocations in functions?

Sometimes.

An answer to show when code can be abused to detail one of the pitfalls of allowing a function total freedom in memory allocation.


A classic case occurs when the function itself determines the size needed, so the calling code lacks the information needed to to provide the memory buffer beforehand.

This is the case with getline() where the stream content throttles the size of the allocation. The problem with this, especially when the stream is stdin, is that the control over memory allocation is given to external sources and not limited by the calling code - the program. External input may overwhelm memory space - a hack.

With a modified function, such as ssize_t getline_limit(char **lineptr, size_t *n, FILE *stream, size_t limit);, the function could still provide a right-size allocation, yet still prevent a hacker abuse.

#define LIMIT 1000000
char *line = NULL;
size_t len = 0;
ssize_t nread;

while ((nread = getline_limit(&line, &len, stdin, LIMIT)) != -1) {

An example where this is not an issue would be an allocation with a well bounded use.

// Convert `double` to its decimal character representation allocating a right-size buffer
// At worst a few thousand characters
char *double_to_string_exact_alloc(int x)

Functions that perform memory allocation need some level of control to prevent unlimited memory allocation either with a specific parameter or by nature of the task.

like image 34
chux - Reinstate Monica Avatar answered Sep 25 '22 19:09

chux - Reinstate Monica