1

Suppose I have a program like the following

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  if (argc < 2) return 1;
  long buflen = atol(argv[1]);
  char *buf = malloc(buflen);
  fread(buf, 1, buflen, stdin);

  // Do stuff with buf

  free(buf);
  return 0;
}

Programs like these typically have more complex cleanup code, often including several calls to free and sometimes labels or even cleanup functions for error handling.

My question is this: Is the free(buf) at the end actually necessary? My understanding is that the kernel will automatically clean up unfreed memory when the program exits, but if this is the case, why is putting free at the end of code such a common pattern?

BusyBox provides a compilation option to disable calling free at the end of execution. If this isn't an issue, then why would anyone disable that option? Is it purely because programs like Valgrind detect memory leaks when allocated memory isn't freed?

squirl
  • 1,636
  • 1
  • 16
  • 30
  • 4
    Necessary? In most cases no. But it is a good habit to clean after yourself. – Eugene Sh. Jan 24 '18 at 20:17
  • 2
    To add to the previous comment, imagine you use different little programs like your example together to build another bigger program / application. Or turn it somehow into a daemon that keeps running and execute your function several times. If you have not put any `free`, you could easily forgot to add it when combining the pieces together / make it run in a loop. And now your program has severe memory leak. – Pac0 Jan 24 '18 at 20:20
  • https://stackoverflow.com/questions/7543630/good-practice-to-free-mallocs-at-program-conclusion?rq=1 – Zan Lynx Jan 24 '18 at 20:20
  • https://stackoverflow.com/q/5612095/13422 – Zan Lynx Jan 24 '18 at 20:21
  • https://stackoverflow.com/questions/654754/what-really-happens-when-you-dont-free-after-malloc – Zan Lynx Jan 24 '18 at 20:23
  • also understand the program you've demonstrated is a dixie cup program,, terribly simple. What is that, 20 lines? Real software is astronomically bigger, more complex, and can run for a very long time. Think of software programs the _never_ exit.. the software running your router, internet servers, or monitoring the nuclear power plant. Memory leaks in these programs can eventually exhaust the system and cause big trouble. In your example, you don't _have_ to cleanup, but whatever software you write for a semester in school is a far cry from real systems. Cleaning up builds good habits. – yano Jan 24 '18 at 20:28
  • @yano, of course. This was a hypothetical question about a very specific edge case; namely, where memory is allocated at the start and used throughout the entire program. – squirl Jan 24 '18 at 20:30
  • if you're guaranteed a fixed number of allocations and those are used throughout runtime of the program (as in your example), then no, the OS will (probably, as noted below) cleanup after you. But this isn't how real software works. More than likely you're going to allocate in a loop, in response to stimuli/inputs your program receives, in response to events. The whole point of allocating memory during runtime is that you don't know you need it until then. If you know at compile time, it's best to use automatic storage (with a few exceptions). – yano Jan 24 '18 at 20:37
  • @yano 'But this isn't how real software works' well, my software must be unreal. Allocating strut/object pools at startup is not at all unusual, and since it's not possible to detemine at any instant which thread is reading/writing from any particualr instance, and user code cannot guarantee to stop all process threads in any state, it is essential to let the OS clean up. Trying to free such memory is user code will result in shutdown segfaults. Despite claims to the contrary, user cleanup becomes less and less safe as app complexity increases. – Martin James Jan 24 '18 at 23:56
  • @Samadi ' memory is allocated at the start and used throughout the entire program' - it's fine. Carry on. many professional apps and libraries do exactly that - it's safer than trying to do unnecessary and avoidable 'manual' user cleanup that needs continual debugging and testing. – Martin James Jan 24 '18 at 23:59
  • @MartinJames touche with initial allocation of pools,, but if the load becomes too much and pools become exhausted additional allocation is necessary (or you deny service), which is a response to stimuli. Not sure I follow the rest, thread synchronization allows for clean shutdown among multiple threads, if you are in fact shutting down. – yano Jan 25 '18 at 00:17
  • @MartinJames Additionally, if you do use a pool-of-resources approach, when you take something from the pool to use, return it when you're done,, or your pool resources become exhausted. This is tantamount to `free`ing in this case. I hardly think "clean up after yourself" is bad advice or a foolish thing to do. – yano Jan 25 '18 at 00:39
  • @yano ..but often, it is. What is totally wrong is blanket statements/laws like 'It's always a good plan to clean up everything you allocate', (from accepted, +4, 138k rep user below). It's often a very bad plan indeed, and occasionally, actually not possible. No, using a transparent user-managed pool of objects is not tantamount to freeing. Pool leaks are much more easily detected and fixed. – Martin James Jan 27 '18 at 10:18
  • @MartinJames I'll have to take your word for it. I see your rep with multithreading, so you know way more than me... I ack that. In my (limited) experience, I've never seen where it's "a very bad plan" to clean up after yourself. I've always joined on my threads and deallocated resources. Sure it's extra code (that I've had to debug!), but coding isn't easy. Relying on the OS to cleanup doesn't sound robust to me. I'd be willing to bet there are OS'es out there that don't cleanup,,, but I don't know... VxWorks comes to mind. – yano Jan 27 '18 at 10:34

1 Answers1

5

Actually, as in absolutely? On a modern operating system, no. In some environments, yes.

It's always a good plan to clean up everything you allocate as this makes it very easy to scan for memory leaks. If you have outstanding allocations just prior to your exit you have a leak. If you don't free things because the OS does it for you then you don't know if it's a mistake or intended behaviour.

You're also supposed to check for errors from any function that might return them, like fread, but you don't, so you're already firmly in the danger zone here. Is this mission critical code where if it crashes Bad Things happen? If so you'll want to do everything absolutely by the book.

As Jean-François pointed out the way this trivial code is composed is a bad example. Most programs will look more like this:

void do_stuff_with_buf(char* arg) {
  long buflen = atol(arg);
  char *buf = malloc(buflen);
  fread(buf, 1, buflen, stdin);

  // Do stuff with buf

  free(buf);
}

int main(int argc, char *argv[]) {
  if (argc < 2)
    return 1;

  do_stuff_with_buf(argv[1])

  return 0;
}

Here it should be more obvious that the do_stuff_with_buf function should clean up for itself, it can't depend on the program exiting to release resources. If that function was called multiple times you shouldn't leak memory, that's just sloppy and can cause serious problems. A run-away allocation can cause things like the infamous Linux "OOM killer" to show up and go on a murder spree to free up some memory, something that usually leads to nothing but chaos and confusion.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • 1
    Good point about checking for errors from `fread`. That was just an example though, rather than actual code. – squirl Jan 24 '18 at 20:27
  • Which environments wouldn't clean up allocations after program exit? – squirl Jan 24 '18 at 20:28
  • 2
    take AmigaOS for instance. It doesn't have resource tracking. If you don't free the memory, you don't get it until you reboot (with ctrl+A+A :)) – Jean-François Fabre Jan 24 '18 at 20:29
  • It depends on the operating system and the runtime context. If you're writing kernel code, for example, nothing is ever freed unless you do it explicitly. If your module gets unloaded without cleaning up those allocations stay around forever. Embedded systems also have this problem where there runtime can't spare resources for a proper memory manager so every process *must* clean up after itself. – tadman Jan 24 '18 at 20:29
  • 1
    Fantastic, thanks for the extra detail! – squirl Jan 24 '18 at 20:31
  • 1
    another reason: if one day you're turning your main into a service/endless loop, you'll be glad that you handled the frees properly. – Jean-François Fabre Jan 24 '18 at 20:33
  • 1
    @Jean-FrançoisFabre That's a good point. Non-trivial programs don't do allocations in the `main` function, it's always in some other function, and unless that function cleans up properly it'll leak. – tadman Jan 24 '18 at 20:35
  • 1
    that's why I make a useless loop on my program. Run it 5000 times and see if memory increases. – Jean-François Fabre Jan 24 '18 at 20:36
  • 2
    @Jean-FrançoisFabre Or use valgrind `--leak-kinds=all` if your operating system supports it. – Iharob Al Asimi Jan 24 '18 at 20:40
  • I'm using windows. I have to guess the leaks. "I don't use debuggers, I stare at the code until it confesses (Chuck Norris)" – Jean-François Fabre Jan 24 '18 at 20:44
  • 1
    You forgot to mention the downsides which, for non-trivial, (esp. multithreaded), apps, usually massively outweigh some irrational fear of 'outstanding allocations just prior to your exit you have a leak'. – Martin James Jan 27 '18 at 10:21