81

Firstly, I'm aware that opening a file with fopen() and not closing it is horribly irresponsible, and bad form. This is just sheer curiosity, so please humour me :)

I know that if a C program opens a bunch of files and never closes any of them, eventually fopen() will start failing. Are there any other side effects that could cause problems outside the code itself? For instance, if I have a program that opens one file, and then exits without closing it, could that cause a problem for the person running the program? Would such a program leak anything (memory, file handles)? Could there be problems accessing that file again once the program had finished? What would happen if the program was run many times in succession?

electrodruid
  • 1,083
  • 2
  • 9
  • 13
  • 4
    No need for all the disclaimers. There's nothing terribly bad about exiting without calling `fclose`, at least not any moreso than using `goto`. It all depends on the situation. – R.. GitHub STOP HELPING ICE Nov 18 '11 at 02:31

4 Answers4

110

As long as your program is running, if you keep opening files without closing them, the most likely result is that you will run out of file descriptors/handles available for your process, and attempting to open more files will fail eventually. On Windows, this can also prevent other processes from opening or deleting the files you have open, since by default, files are opened in an exclusive sharing mode that prevents other processes from opening them.

Once your program exits, the operating system will clean up after you. It will close any files you left open when it terminates your process, and perform any other cleanup that is necessary (e.g. if a file was marked delete-on-close, it will delete the file then; note that that sort of thing is platform-specific).

However, another issue to be careful of is buffered data. Most file streams buffer data in memory before writing it out to disk. If you're using FILE* streams from the stdio library, then there are two possibilities:

  1. Your program exited normally, either by calling the exit(3) function, or by returning from main (which implicitly calls exit(3)).
  2. Your program exited abnormally; this can be via calling abort(3) or _Exit(3), dying from a signal/exception, etc.

If your program exited normally, the C runtime will take care of flushing any buffered streams that were open. So, if you had buffered data written to a FILE* that wasn't flushed, it will be flushed on normal exit.

Conversely, if your program exited abnormally, any buffered data will not be flushed. The OS just says "oh dear me, you left a file descriptor open, I better close that for you" when the process terminates; it has no idea there's some random data lying somewhere in memory that the program intended to write to disk but did not. So be careful about that.

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • 1
    Any guesses on how long would that left over buffer exist before being regained by the OS? – user10607 Dec 15 '14 at 12:46
  • 2
    I'd guess as quick as possible, since that buffer isn't magical - your program allocated memory for it, and OS should free that memory when your program crashes as a part of the normal cleanup. – Xupicor Oct 07 '16 at 23:07
  • 1
    "[T]he operating system will clean up after you"... Well that really depends on the operating system. The main desktop operating systems will do that, but it's not guaranteed. – Some programmer dude Sep 17 '19 at 06:18
13

The C standard says that calling exit (or, equivalently, returning from main) causes all open FILE objects to be closed as-if by fclose. So this is perfectly fine, except that you forfeit the opportunity to detect write errors.

EDIT: There is no such guarantee for abnormal termination (abort, a failed assert, receipt of a signal whose default behavior is to abnormally terminate the program -- note that there aren't necessarily any such signals -- and other implementation-defined means). As others have said, modern operating systems will clean up all externally visible resources, such as open OS-level file handles, regardless; however, FILEs are likely not to be flushed in that case.

There certainly have been OSes that did not clean up externally visible resources on abnormal termination; it tends to go along with not enforcing hard privilege boundaries between "kernel" and "user" code and/or between distinct user space "processes", simply because if you don't have those boundaries it may not be possible to do so safely in all cases. (Consider, for instance, what happens if you write garbage over the open-file table in MS-DOS, as you are perfectly able to do.)

zwol
  • 135,547
  • 38
  • 252
  • 361
  • 1
    Could you provide a reference, why wouldn't this be OS specific? – Peter Nov 17 '11 at 23:46
  • 5
    @Peter: C99, §7.20.4.3, ¶ 4: "Next, all open streams with unwritten buffered data are flushed, all open streams are closed, and all files created by the tmpfile function are removed." Note that this applies only to regular (`exit`, `return` from `main`) termination, what happens with `_Exit` & co. is implementation-defined. – Matteo Italia Nov 17 '11 at 23:48
  • @MatteoItalia, thanks, but it's also true that if the process terminates unexpectedly for some other reason, then most modern OS's will clean up the handles and memory anyway. – Peter Nov 17 '11 at 23:57
  • 1
    @Peter: sure thing, but, since you wanted an OS-agnostic reference of this fact, I provided *only* the guarantees given by the standard. :) – Matteo Italia Nov 17 '11 at 23:59
5

Assuming you exit under control, using the exit() system call or returning from main(), then the open file streams are closed after flushing. The C Standard (and POSIX) mandate this.

If you exit out of control (core dump, SIGKILL) etc, or if you use _exit() or _Exit(), then the open file streams are not flushed (but the file descriptors end up closed, assuming a POSIX-like system with file descriptors - Standard C does not mandate file descriptors). Note that _Exit() is mandated by the C99 standard, but _exit() is mandated by POSIX (but they behave the same on POSIX systems). Note that file descriptors are separate from file streams. See the discussion of 'Consequences of Program Termination' on the POSIX page for _exit() to see what happens when a program terminates under Unix.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • "but the file descriptors end up closed" - are you sure? The standard says that "Whether open streams with unwritten buffered data are flushed, open streams are closed, or temporary files are removed is implementation-defined." (C99 §7.20.4.4 ¶2) – Matteo Italia Nov 17 '11 at 23:47
  • The streams are not closed; the file descriptors are. There's a (big) difference. All the file descriptors are closed when a program terminates - see 'Consequences of Program Termination' on the `_Exit()` page referenceI am making the assumption that the system provides POSIX-like semantics; in pure standard C, there are no file descriptors. The behaviour for non-POSIX systems may be a bit different. – Jonathan Leffler Nov 17 '11 at 23:48
  • That's what I'm saying: as far as the C standard is concerned, what happens on `_Exit()` is implementation-defined (and one of these possible behaviors is the one mandated by the POSIX standard). – Matteo Italia Nov 17 '11 at 23:52
0

When the process dies, most modern operating systems (the kernel specifically) will free all of your handles and allocated memory.

Peter
  • 3,998
  • 24
  • 33
  • 2
    A typical modern operating system will do that, at least. My understanding is that back in the day, Windows 3.1 and what-not would leak handles if the application didn't exit correctly. And there may be some other very minimal OS's these days (embedded systems, perhaps) that don't handle that for you. – Ken Smith Nov 17 '11 at 23:30
  • @KenSmith: that would apply to OS-specific file handles, tough, because the standard (as @Zack said) guarantees that on termination all the CRT `FILE *` are closed in case of regular exit. – Matteo Italia Nov 17 '11 at 23:46
  • 1
    Good point; though as you say above, the *CRT* doesn't guarantee that handles will be closed if the application exits *abnormally*. It's typically the OS that does that - and it's my understanding that there are some very old or very specialized operating systems that don't make that guarantee. – Ken Smith Nov 18 '11 at 00:24