7

Is there anyway in Linux (or more generally in a POSIX OS) to guarantee that during the execution of a program, no file descriptors will be reused, even if a file is closed and another opened? My understanding is that this situation would usually lead to the file descriptor for the closed file being reassigned to the newly opened file.

I'm working on an I/O tracing project and it would make life simpler if I could assume that after an open()/fopen() call, all subsequent I/O to that file descriptor is to the same file.

I'll take either a compile-time or run-time solution.

If it is not possible, I could do my own accounting when I process the trace file (noting the location of all open and close calls), but I'd prefer to squash the problem during execution of the traced program.

mhowison
  • 650
  • 1
  • 7
  • 12
  • I think you should take the second approach (doing your own accounting). Changing the behavior of file descriptor assignment (which is strictly specified by POSIX) to something non-conformant will break programs in subtle (and possibly dangerous) ways. – R.. GitHub STOP HELPING ICE May 20 '12 at 03:58

3 Answers3

10

Note that POSIX requires:

The open() function shall return a file descriptor for the named file that is the lowest file descriptor not currently open for that process.

So in the strictest sense, your request will change the program's environment to be no longer POSIX compliant.

That said, I think your best bet is to use the LD_PRELOAD trick to intercept calls to close and ignore them.

Community
  • 1
  • 1
Nemo
  • 70,042
  • 10
  • 116
  • 153
1

You'd have to write a SO that contains a close(2) that opens /dev/null on old FDs, and then use $LD_PRELOAD to load it into process space before starting the application.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
  • Actually, I already have a __wrap_close() call for implementing the tracing routines, so it sounds like I could just insert the open("/dev/null") inside that routine after I call __real_close() on the FD. Will this always work? I.e. am I guaranteed to get back the same FD on the open("/dev/null") call as I closed with the __real_close() call? – mhowison May 20 '12 at 00:34
  • 1
    No. Which is why you open once and use `dup2(2)` to copy the FD. – Ignacio Vazquez-Abrams May 20 '12 at 00:35
  • `__wrap_close` is *nowhere* near sufficient for tracing purposes. Think `syscall(SYS_open, ...)`. – Employed Russian May 20 '12 at 00:36
  • Well, __wrap_close is sufficient for the scenarios I will be tracing, which are parallel HPC apps that almost always use the MPI-IO layer for collective I/O. – mhowison May 20 '12 at 00:39
  • @mhowison In that case, you can trivially do things to prevent re-use in your close wrapper, but see my answer for other gotcha's. – Employed Russian May 20 '12 at 00:42
1

You must already be ptraceing the application to intercept its file opening and closing operations.

It would appear trivial to prevent FD re-use by "injecting" dup2(X, Y); close(X); calls into the application, and adjusting Y to be anything you want.

However, the application itself could be using dup2 to force a re-use of previously closed FD, and may not work if you prevent that, so I think you'll just have to deal with this in post-processing step.

Also, it's quite easy to write an app that will run out of FDs if you disallow re-use.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362