1//===-- FDInterposing.cpp ---------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file helps with catching double close calls on unix integer file
11// descriptors by interposing functions for all file descriptor create and
12// close operations. A stack backtrace for every create and close function is
13// maintained, and every create and close operation is logged. When a double
14// file descriptor close is encountered, it will be logged.
15//
16// To enable the interposing in a darwin program, set the DYLD_INSERT_LIBRARIES
17// environment variable as follows:
18// For sh:
19//  DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib /path/to/executable
20// For tcsh:
21//  (setenv DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib ; /path/to/executable)
22//
23// Other environment variables that can alter the default actions of this
24// interposing shared library include:
25//
26// "FileDescriptorStackLoggingNoCompact"
27//
28//      With this environment variable set, all file descriptor create and
29//      delete operations will be permanantly maintained in the event map.
30//      The default action is to compact the create/delete events by removing
31//      any previous file descriptor create events that are matched with a
32//      corresponding file descriptor delete event when the next valid file
33//      descriptor create event is detected.
34//
35// "FileDescriptorMinimalLogging"
36//
37//      By default every file descriptor create and delete operation is logged
38//      (to STDOUT by default, see the "FileDescriptorLogFile"). This can be
39//      suppressed to only show errors and warnings by setting this environment
40//      variable (the value in not important).
41//
42// "FileDescriptorLogFile=<path>"
43//
44//      By default logging goes to STDOUT_FILENO, but this can be changed by
45//      setting FileDescriptorLogFile. The value is a path to a file that
46//      will be opened and used for logging.
47//===----------------------------------------------------------------------===//
48
49#include <assert.h>
50#include <dirent.h>
51#include <errno.h>
52#include <fcntl.h>
53#include <execinfo.h>
54#include <libgen.h>
55#include <mach-o/dyld.h>
56#include <mach-o/dyld-interposing.h>
57#include <stdlib.h>
58#include <stdio.h>
59#include <string.h>
60#include <sys/event.h>
61#include <sys/mman.h>
62#include <sys/socket.h>
63#include <sys/types.h>
64#include <sys/time.h>
65#include <tr1/memory> // for std::tr1::shared_ptr
66#include <unistd.h>
67#include <string>
68#include <vector>
69#include <map>
70
71//----------------------------------------------------------------------
72/// @def DISALLOW_COPY_AND_ASSIGN(TypeName)
73///     Macro definition for easily disallowing copy constructor and
74///     assignment operators in C++ classes.
75//----------------------------------------------------------------------
76#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
77TypeName(const TypeName&); \
78const TypeName& operator=(const TypeName&)
79
80extern "C" {
81    int accept$NOCANCEL (int, struct sockaddr * __restrict, socklen_t * __restrict);
82    int close$NOCANCEL(int);
83    int open$NOCANCEL(const char *, int, ...);
84    int __open_extended(const char *, int, uid_t, gid_t, int, struct kauth_filesec *);
85}
86
87namespace fd_interposing {
88
89//----------------------------------------------------------------------
90// String class so we can get formatted strings without having to worry
91// about the memory storage since it will allocate the memory it needs.
92//----------------------------------------------------------------------
93class String
94{
95public:
96    String () :
97        m_str (NULL)
98    {}
99
100    String (const char *format, ...) :
101        m_str (NULL)
102    {
103        va_list args;
104        va_start (args, format);
105        vprintf (format, args);
106        va_end (args);
107    }
108
109    ~String()
110    {
111        reset();
112    }
113
114    void
115    reset (char *s = NULL)
116    {
117        if (m_str)
118            ::free (m_str);
119        m_str = s;
120    }
121
122    const char *
123    c_str () const
124    {
125        return m_str;
126    }
127
128    void
129    printf (const char *format, ...)
130    {
131        va_list args;
132        va_start (args, format);
133        vprintf (format, args);
134        va_end (args);
135    }
136    void
137    vprintf (const char *format, va_list args)
138    {
139        reset();
140        ::vasprintf (&m_str, format, args);
141    }
142
143    void
144    log (int log_fd)
145    {
146        if (m_str && log_fd >= 0)
147        {
148            const int len = strlen(m_str);
149            if (len > 0)
150            {
151                write (log_fd, m_str, len);
152                const char last_char = m_str[len-1];
153                if (!(last_char == '\n' || last_char == '\r'))
154                    write (log_fd, "\n", 1);
155            }
156        }
157    }
158protected:
159    char *m_str;
160
161private:
162    DISALLOW_COPY_AND_ASSIGN (String);
163};
164
165//----------------------------------------------------------------------
166// Type definitions
167//----------------------------------------------------------------------
168typedef std::vector<void *> Frames;
169class FDEvent;
170typedef std::vector<void *> Frames;
171typedef std::tr1::shared_ptr<FDEvent> FDEventSP;
172typedef std::tr1::shared_ptr<String> StringSP;
173
174
175//----------------------------------------------------------------------
176// FDEvent
177//
178// A class that describes a file desciptor event.
179//
180// File descriptor events fall into one of two categories: create events
181// and delete events.
182//----------------------------------------------------------------------
183class FDEvent
184{
185public:
186    FDEvent (int fd, int err, const StringSP &string_sp, bool is_create, const Frames& frames) :
187        m_string_sp (string_sp),
188        m_frames (frames.begin(), frames.end()),
189        m_fd (fd),
190        m_err (err),
191        m_is_create (is_create)
192    {}
193
194    ~FDEvent () {}
195
196    bool
197    IsCreateEvent() const
198    {
199        return m_is_create;
200    }
201
202    bool
203    IsDeleteEvent() const
204    {
205        return !m_is_create;
206    }
207
208    Frames &
209    GetFrames ()
210    {
211        return m_frames;
212    }
213
214    const Frames &
215    GetFrames () const
216    {
217        return m_frames;
218    }
219
220    int
221    GetFD () const
222    {
223        return m_fd;
224    }
225
226    int
227    GetError () const
228    {
229        return m_err;
230    }
231
232    void
233    Dump (int log_fd) const;
234
235    void
236    SetCreateEvent (FDEventSP &create_event_sp)
237    {
238        m_create_event_sp = create_event_sp;
239    }
240
241private:
242    // A shared pointer to a String that describes this event in
243    // detail (all args and return and error values)
244    StringSP m_string_sp;
245    // The frames for the stack backtrace for this event
246    Frames m_frames;
247    // If this is a file descriptor delete event, this might contain
248    // the correspoding file descriptor create event
249    FDEventSP m_create_event_sp;
250    // The file descriptor for this event
251    int m_fd;
252    // The error code (if any) for this event
253    int m_err;
254    // True if this event is a file descriptor create event, false
255    // if it is a file descriptor delete event
256    bool m_is_create;
257};
258
259//----------------------------------------------------------------------
260// Templatized class that will save errno only if the "value" it is
261// constructed with is equal to INVALID. When the class goes out of
262// scope, it will restore errno if it was saved.
263//----------------------------------------------------------------------
264template <int INVALID>
265class Errno
266{
267public:
268    // Save errno only if we are supposed to
269    Errno (int value) :
270        m_saved_errno ((value == INVALID) ? errno : 0),
271        m_restore (value == INVALID)
272    {
273    }
274
275    // Restore errno only if we are supposed to
276    ~Errno()
277    {
278        if (m_restore)
279            errno = m_saved_errno;
280    }
281
282    // Accessor for the saved value of errno
283    int
284    get_errno() const
285    {
286        return m_saved_errno;
287    }
288
289protected:
290    const int m_saved_errno;
291    const bool m_restore;
292};
293
294typedef Errno<-1> InvalidFDErrno;
295typedef Errno<-1> NegativeErrorErrno;
296typedef std::vector<FDEventSP> FDEventArray;
297typedef std::map<int, FDEventArray> FDEventMap;
298
299//----------------------------------------------------------------------
300// Globals
301//----------------------------------------------------------------------
302// Global event map that contains all file descriptor events. As file
303// descriptor create and close events come in, they will get filled
304// into this map (protected by g_mutex). When a file descriptor close
305// event is detected, the open event will be removed and placed into
306// the close event so if something tries to double close a file
307// descriptor we can show the previous close event and the file
308// desctiptor event that created it. When a new file descriptor create
309// event comes in, we will remove the previous one for that file
310// desctiptor unless the environment variable "FileDescriptorStackLoggingNoCompact"
311// is set. The file desctiptor history can be accessed using the
312// get_fd_history() function.
313static FDEventMap g_fd_event_map;
314// A mutex to protect access to our data structures in g_fd_event_map
315// and also our logging messages
316static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
317// Log all file descriptor create and close events by default. Only log
318// warnings and erros if the "FileDescriptorMinimalLogging" environment
319// variable is set.
320static int g_log_all_calls = 1;
321// We compact the file descriptor events by default. Set the environment
322// varible "FileDescriptorStackLoggingNoCompact" to keep a full history.
323static int g_compact = 1;
324// The current process ID
325static int g_pid = -1;
326static bool g_enabled = true;
327//----------------------------------------------------------------------
328// Mutex class that will lock a mutex when it is constructed, and unlock
329// it when is goes out of scope
330//----------------------------------------------------------------------
331class Locker
332{
333public:
334    Locker (pthread_mutex_t *mutex_ptr) :
335        m_mutex_ptr(mutex_ptr)
336    {
337        ::pthread_mutex_lock (m_mutex_ptr);
338    }
339
340    // This allows clients to test try and acquire the mutex...
341    Locker (pthread_mutex_t *mutex_ptr, bool &lock_acquired) :
342        m_mutex_ptr(NULL)
343    {
344        lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0;
345        if (lock_acquired)
346            m_mutex_ptr = mutex_ptr;
347    }
348
349    ~Locker ()
350    {
351        if (m_mutex_ptr)
352            ::pthread_mutex_unlock (m_mutex_ptr);
353    }
354protected:
355    pthread_mutex_t *m_mutex_ptr;
356};
357
358static void
359log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
360
361static void
362log (int log_fd, const FDEvent *event, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
363
364static void
365backtrace_log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
366
367static void
368backtrace_error (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
369
370static void
371log_to_fd (int log_fd, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
372
373static inline size_t
374get_backtrace (Frames &frame_buffer, size_t frames_to_remove)
375{
376    void *frames[2048];
377    int count = ::backtrace (&frames[0], sizeof(frames)/sizeof(void*));
378    if (count > frames_to_remove)
379        frame_buffer.assign (&frames[frames_to_remove], &frames[count]);
380    else
381        frame_buffer.assign (&frames[0], &frames[count]);
382    while (frame_buffer.back() < (void *)1024)
383        frame_buffer.pop_back();
384    return frame_buffer.size();
385}
386
387static int g_log_fd = STDOUT_FILENO;
388static int g_initialized = 0;
389
390const char *
391get_process_fullpath (bool force = false)
392{
393    static char g_process_fullpath[PATH_MAX] = {0};
394    if (force || g_process_fullpath[0] == '\0')
395    {
396        // If DST is NULL, then return the number of bytes needed.
397        uint32_t len = sizeof(g_process_fullpath);
398        if (_NSGetExecutablePath (g_process_fullpath, &len) != 0)
399            strncpy (g_process_fullpath, "<error>", sizeof(g_process_fullpath));
400    }
401    return g_process_fullpath;
402}
403
404// Returns the current process ID, or -1 if inserposing not enabled for
405// this process
406static int
407get_interposed_pid()
408{
409    if (!g_enabled)
410        return -1;
411
412    const pid_t pid = getpid();
413    if (g_pid != pid)
414    {
415        if (g_pid == -1)
416        {
417            g_pid = pid;
418            log ("Interposing file descriptor create and delete functions for %s (pid=%i)\n", get_process_fullpath (true), pid);
419        }
420        else
421        {
422            log ("pid=%i: disabling interposing file descriptor create and delete functions for child process %s (pid=%i)\n", g_pid, get_process_fullpath (true), pid);
423            g_enabled = false;
424            return -1;
425        }
426        // Log when our process changes
427    }
428    return g_pid;
429}
430
431static int
432get_logging_fd ()
433{
434    if (!g_enabled)
435        return -1;
436
437    if (!g_initialized)
438    {
439        g_initialized = 1;
440
441        const pid_t pid = get_interposed_pid();
442
443        if (g_enabled)
444        {
445            // Keep all stack info around for all fd create and delete calls.
446            // Otherwise we will remove the fd create call when a corresponding
447            // fd delete call is received
448            if (getenv("FileDescriptorStackLoggingNoCompact"))
449                g_compact = 0;
450
451            if (getenv("FileDescriptorMinimalLogging"))
452                g_log_all_calls = 0;
453
454            const char *log_path = getenv ("FileDescriptorLogFile");
455            if (log_path)
456                g_log_fd = ::creat (log_path, 0660);
457            else
458                g_log_fd = STDOUT_FILENO;
459
460            // Only let this interposing happen on the first time this matches
461            // and stop this from happening so any child processes don't also
462            // log their file descriptors
463            ::unsetenv ("DYLD_INSERT_LIBRARIES");
464        }
465        else
466        {
467            log ("pid=%i: logging disabled\n", getpid());
468        }
469    }
470    return g_log_fd;
471}
472
473void
474log_to_fd (int log_fd, const char *format, va_list args)
475{
476    if (format && format[0] && log_fd >= 0)
477    {
478        char buffer[PATH_MAX];
479        const int count = ::vsnprintf (buffer, sizeof(buffer), format, args);
480        if (count > 0)
481            write (log_fd, buffer, count);
482    }
483}
484
485void
486log_to_fd (int log_fd, const char *format, ...)
487{
488    if (format && format[0])
489    {
490        va_list args;
491        va_start (args, format);
492        log_to_fd (log_fd, format, args);
493        va_end (args);
494    }
495}
496
497void
498log (const char *format, va_list args)
499{
500    log_to_fd (get_logging_fd (), format, args);
501}
502
503void
504log (const char *format, ...)
505{
506    if (format && format[0])
507    {
508        va_list args;
509        va_start (args, format);
510        log (format, args);
511        va_end (args);
512    }
513}
514
515void
516log (int log_fd, const FDEvent *event, const char *format, ...)
517{
518    if (format && format[0])
519    {
520        va_list args;
521        va_start (args, format);
522        log_to_fd (log_fd, format, args);
523        va_end (args);
524    }
525    if (event)
526        event->Dump(log_fd);
527}
528
529void
530FDEvent::Dump (int log_fd) const
531{
532    if (log_fd >= 0)
533    {
534        log_to_fd (log_fd, "%s\n", m_string_sp->c_str());
535        if (!m_frames.empty())
536            ::backtrace_symbols_fd (m_frames.data(), m_frames.size(), log_fd);
537
538        if (m_create_event_sp)
539        {
540            log_to_fd (log_fd, "\nfd=%i was created with this event:\n", m_fd);
541            m_create_event_sp->Dump (log_fd);
542            log_to_fd (log_fd, "\n");
543        }
544    }
545}
546
547
548void
549backtrace_log (const char *format, ...)
550{
551    const int log_fd = get_logging_fd ();
552    if (log_fd >= 0)
553    {
554        if (format && format[0])
555        {
556            va_list args;
557            va_start (args, format);
558            log (format, args);
559            va_end (args);
560        }
561
562        Frames frames;
563        if (get_backtrace(frames, 2))
564            ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd);
565    }
566
567}
568
569void
570backtrace_error (const char *format, ...)
571{
572    const int pid = get_interposed_pid();
573    if (pid >= 0)
574    {
575        const int log_fd = get_logging_fd ();
576        if (log_fd >= 0)
577        {
578            log ("\nerror: %s (pid=%i): ", get_process_fullpath (), pid);
579
580            if (format && format[0])
581            {
582                va_list args;
583                va_start (args, format);
584                log (format, args);
585                va_end (args);
586            }
587
588            Frames frames;
589            if (get_backtrace(frames, 2))
590                ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd);
591        }
592    }
593}
594
595void
596save_backtrace (int fd, int err, const StringSP &string_sp, bool is_create)
597{
598    Frames frames;
599    get_backtrace(frames, 2);
600
601    FDEventSP fd_event_sp (new FDEvent (fd, err, string_sp, is_create, frames));
602
603    FDEventMap::iterator pos = g_fd_event_map.find (fd);
604
605    if (pos != g_fd_event_map.end())
606    {
607        // We have history for this fd...
608
609        FDEventArray &event_array = g_fd_event_map[fd];
610        if (fd_event_sp->IsCreateEvent())
611        {
612            // The current fd event is a function that creates
613            // a descriptor, check in case last event was
614            // a create event.
615            if (event_array.back()->IsCreateEvent())
616            {
617                const int log_fd = get_logging_fd();
618                // Two fd create functions in a row, we missed
619                // a function that closes a fd...
620                log (log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor create event fd=%i (we missed a file descriptor close event):\n", fd);
621            }
622            else if (g_compact)
623            {
624                // We are compacting so we remove previous create event
625                // when we get the correspinding delete event
626                event_array.pop_back();
627            }
628        }
629        else
630        {
631            // The current fd event is a function that deletes
632            // a descriptor, check in case last event for this
633            // fd was a delete event (double close!)
634            if (event_array.back()->IsDeleteEvent())
635            {
636                const int log_fd = get_logging_fd();
637                // Two fd delete functions in a row, we must
638                // have missed some function that opened a descriptor
639                log (log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor close event for fd=%d (we missed the file descriptor create event):\n", fd);
640            }
641            else if (g_compact)
642            {
643                // Since this is a close event, we want to remember the open event
644                // that this close if for...
645                fd_event_sp->SetCreateEvent(event_array.back());
646                // We are compacting so we remove previous create event
647                // when we get the correspinding delete event
648                event_array.pop_back();
649            }
650        }
651
652        event_array.push_back(fd_event_sp);
653    }
654    else
655    {
656        g_fd_event_map[fd].push_back(fd_event_sp);
657    }
658}
659
660//----------------------------------------------------------------------
661// socket() interpose function
662//----------------------------------------------------------------------
663extern "C" int
664socket$__interposed__ (int domain, int type, int protocol)
665{
666    const int pid = get_interposed_pid();
667    if (pid >= 0)
668    {
669        Locker locker (&g_mutex);
670        const int fd = ::socket (domain, type, protocol);
671        InvalidFDErrno fd_errno(fd);
672        StringSP description_sp(new String);
673        if (fd == -1)
674            description_sp->printf("pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i  errno = %i", pid, domain, type, protocol, fd, fd_errno.get_errno());
675        else
676            description_sp->printf("pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i", pid, domain, type, protocol, fd);
677        if (g_log_all_calls)
678            description_sp->log (get_logging_fd());
679        if (fd >= 0)
680            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
681        return fd;
682    }
683    else
684    {
685        return ::socket (domain, type, protocol);
686    }
687}
688
689//----------------------------------------------------------------------
690// socketpair() interpose function
691//----------------------------------------------------------------------
692extern "C" int
693socketpair$__interposed__ (int domain, int type, int protocol, int fds[2])
694{
695    const int pid = get_interposed_pid();
696    if (pid >= 0)
697    {
698        Locker locker (&g_mutex);
699        fds[0] = -1;
700        fds[1] = -1;
701        const int err = socketpair (domain, type, protocol, fds);
702        NegativeErrorErrno err_errno(err);
703        StringSP description_sp(new String ("pid=%i: socketpair (domain=%i, type=%i, protocol=%i, {fd=%i, fd=%i}) -> err=%i", pid, domain, type, protocol, fds[0], fds[1], err));
704        if (g_log_all_calls)
705            description_sp->log (get_logging_fd());
706        if (fds[0] >= 0)
707            save_backtrace (fds[0], err_errno.get_errno(), description_sp, true);
708        if (fds[1] >= 0)
709            save_backtrace (fds[1], err_errno.get_errno(), description_sp, true);
710        return err;
711    }
712    else
713    {
714        return socketpair (domain, type, protocol, fds);
715    }
716}
717
718//----------------------------------------------------------------------
719// open() interpose function
720//----------------------------------------------------------------------
721extern "C" int
722open$__interposed__ (const char *path, int oflag, int mode)
723{
724    const int pid = get_interposed_pid();
725    if (pid >= 0)
726    {
727        Locker locker (&g_mutex);
728        int fd = -2;
729        StringSP description_sp(new String);
730        if (oflag & O_CREAT)
731        {
732            fd = ::open (path, oflag, mode);
733            description_sp->printf("pid=%i: open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd);
734        }
735        else
736        {
737            fd = ::open (path, oflag);
738            description_sp->printf("pid=%i: open (path = '%s', oflag = %i) -> fd=%i", pid, path, oflag, fd);
739        }
740
741        InvalidFDErrno fd_errno(fd);
742        if (g_log_all_calls)
743            description_sp->log (get_logging_fd());
744        if (fd >= 0)
745            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
746        return fd;
747    }
748    else
749    {
750        return ::open (path, oflag, mode);
751    }
752}
753
754//----------------------------------------------------------------------
755// open$NOCANCEL() interpose function
756//----------------------------------------------------------------------
757extern "C" int
758open$NOCANCEL$__interposed__ (const char *path, int oflag, int mode)
759{
760    const int pid = get_interposed_pid();
761    if (pid >= 0)
762    {
763        Locker locker (&g_mutex);
764        const int fd = ::open$NOCANCEL (path, oflag, mode);
765        InvalidFDErrno fd_errno(fd);
766        StringSP description_sp(new String ("pid=%i: open$NOCANCEL (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd));
767        if (g_log_all_calls)
768            description_sp->log (get_logging_fd());
769        if (fd >= 0)
770            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
771        return fd;
772    }
773    else
774    {
775        return ::open$NOCANCEL (path, oflag, mode);
776    }
777}
778
779
780//----------------------------------------------------------------------
781// __open_extended() interpose function
782//----------------------------------------------------------------------
783extern "C" int
784__open_extended$__interposed__ (const char *path, int oflag, uid_t uid, gid_t gid, int mode, struct kauth_filesec *fsacl)
785{
786    const int pid = get_interposed_pid();
787    if (pid >= 0)
788    {
789        Locker locker (&g_mutex);
790        const int fd = ::__open_extended (path, oflag, uid, gid, mode, fsacl);
791        InvalidFDErrno fd_errno(fd);
792        StringSP description_sp(new String ("pid=%i: __open_extended (path='%s', oflag=%i, uid=%i, gid=%i, mode=%i, fsacl=%p) -> fd=%i", pid, path, oflag, uid, gid, mode, fsacl, fd));
793        if (g_log_all_calls)
794            description_sp->log (get_logging_fd());
795        if (fd >= 0)
796            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
797        return fd;
798    }
799    else
800    {
801        return ::__open_extended (path, oflag, uid, gid, mode, fsacl);
802    }
803}
804
805//----------------------------------------------------------------------
806// kqueue() interpose function
807//----------------------------------------------------------------------
808extern "C" int
809kqueue$__interposed__ (void)
810{
811    const int pid = get_interposed_pid();
812    if (pid >= 0)
813    {
814        Locker locker (&g_mutex);
815        const int fd = ::kqueue ();
816        InvalidFDErrno fd_errno(fd);
817        StringSP description_sp(new String ("pid=%i: kqueue () -> fd=%i", pid, fd));
818        if (g_log_all_calls)
819            description_sp->log (get_logging_fd());
820        if (fd >= 0)
821            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
822        return fd;
823    }
824    else
825    {
826        return ::kqueue ();
827    }
828}
829
830//----------------------------------------------------------------------
831// shm_open() interpose function
832//----------------------------------------------------------------------
833extern "C" int
834shm_open$__interposed__ (const char *path, int oflag, int mode)
835{
836    const int pid = get_interposed_pid();
837    if (pid >= 0)
838    {
839        Locker locker (&g_mutex);
840        const int fd = ::shm_open (path, oflag, mode);
841        InvalidFDErrno fd_errno(fd);
842        StringSP description_sp(new String ("pid=%i: shm_open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd));
843        if (g_log_all_calls)
844            description_sp->log (get_logging_fd());
845        if (fd >= 0)
846            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
847        return fd;
848    }
849    else
850    {
851        return ::shm_open (path, oflag, mode);
852    }
853}
854
855//----------------------------------------------------------------------
856// accept() interpose function
857//----------------------------------------------------------------------
858extern "C" int
859accept$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
860{
861    const int pid = get_interposed_pid();
862    if (pid >= 0)
863    {
864        Locker locker (&g_mutex);
865        const int fd = ::accept (socket, address, address_len);
866        InvalidFDErrno fd_errno(fd);
867        StringSP description_sp(new String ("pid=%i: accept (socket=%i, ...) -> fd=%i", pid, socket, fd));
868        if (g_log_all_calls)
869            description_sp->log (get_logging_fd());
870        if (fd >= 0)
871            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
872        return fd;
873    }
874    else
875    {
876        return ::accept (socket, address, address_len);
877    }
878}
879
880
881//----------------------------------------------------------------------
882// accept$NOCANCEL() interpose function
883//----------------------------------------------------------------------
884extern "C" int
885accept$NOCANCEL$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
886{
887    const int pid = get_interposed_pid();
888    if (pid >= 0)
889    {
890        Locker locker (&g_mutex);
891        const int fd = ::accept$NOCANCEL (socket, address, address_len);
892        InvalidFDErrno fd_errno(fd);
893        StringSP description_sp(new String ("pid=%i: accept$NOCANCEL (socket=%i, ...) -> fd=%i", pid, socket, fd));
894        if (g_log_all_calls)
895            description_sp->log (get_logging_fd());
896        if (fd >= 0)
897            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
898        return fd;
899    }
900    else
901    {
902        return ::accept$NOCANCEL (socket, address, address_len);
903    }
904}
905
906//----------------------------------------------------------------------
907// dup() interpose function
908//----------------------------------------------------------------------
909extern "C" int
910dup$__interposed__ (int fd2)
911{
912    const int pid = get_interposed_pid();
913    if (pid >= 0)
914    {
915        Locker locker (&g_mutex);
916        const int fd = ::dup (fd2);
917        InvalidFDErrno fd_errno(fd);
918        StringSP description_sp(new String ("pid=%i: dup (fd2=%i) -> fd=%i", pid, fd2, fd));
919        if (g_log_all_calls)
920            description_sp->log (get_logging_fd());
921        if (fd >= 0)
922            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
923        return fd;
924    }
925    else
926    {
927        return ::dup (fd2);
928    }
929}
930
931//----------------------------------------------------------------------
932// dup2() interpose function
933//----------------------------------------------------------------------
934extern "C" int
935dup2$__interposed__ (int fd1, int fd2)
936{
937    const int pid = get_interposed_pid();
938    if (pid >= 0)
939    {
940        Locker locker (&g_mutex);
941        // If "fd2" is already opened, it will be closed during the
942        // dup2 call below, so we need to see if we have fd2 in our
943        // open map and treat it as a close(fd2)
944        FDEventMap::iterator pos = g_fd_event_map.find (fd2);
945        StringSP dup2_close_description_sp(new String ("pid=%i: dup2 (fd1=%i, fd2=%i) -> will close (fd=%i)", pid, fd1, fd2, fd2));
946        if (pos != g_fd_event_map.end() && pos->second.back()->IsCreateEvent())
947            save_backtrace (fd2, 0, dup2_close_description_sp, false);
948
949        const int fd = ::dup2(fd1, fd2);
950        InvalidFDErrno fd_errno(fd);
951        StringSP description_sp(new String ("pid=%i: dup2 (fd1=%i, fd2=%i) -> fd=%i", pid, fd1, fd2, fd));
952        if (g_log_all_calls)
953            description_sp->log (get_logging_fd());
954
955        if (fd >= 0)
956            save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
957        return fd;
958    }
959    else
960    {
961        return ::dup2(fd1, fd2);
962    }
963}
964
965//----------------------------------------------------------------------
966// close() interpose function
967//----------------------------------------------------------------------
968extern "C" int
969close$__interposed__ (int fd)
970{
971    const int pid = get_interposed_pid();
972    if (pid >= 0)
973    {
974        Locker locker (&g_mutex);
975        const int err = close(fd);
976        NegativeErrorErrno err_errno(err);
977        StringSP description_sp (new String);
978        if (err == -1)
979            description_sp->printf("pid=%i: close (fd=%i) => %i errno = %i (%s))", pid, fd, err, err_errno.get_errno(), strerror(err_errno.get_errno()));
980        else
981            description_sp->printf("pid=%i: close (fd=%i) => %i", pid, fd, err);
982        if (g_log_all_calls)
983            description_sp->log (get_logging_fd());
984
985        if (err == 0)
986        {
987            if (fd >= 0)
988                save_backtrace (fd, err, description_sp, false);
989        }
990        else if (err == -1)
991        {
992            if (err_errno.get_errno() == EBADF && fd != -1)
993            {
994                backtrace_error ("close (fd=%d) resulted in EBADF:\n", fd);
995
996                FDEventMap::iterator pos = g_fd_event_map.find (fd);
997                if (pos != g_fd_event_map.end())
998                {
999                    log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously %s with this event:\n", fd, pos->second.back()->IsCreateEvent() ? "opened" : "closed");
1000                }
1001            }
1002        }
1003        return err;
1004    }
1005    else
1006    {
1007        return close (fd);
1008    }
1009}
1010
1011//----------------------------------------------------------------------
1012// close$NOCANCEL() interpose function
1013//----------------------------------------------------------------------
1014extern "C" int
1015close$NOCANCEL$__interposed__ (int fd)
1016{
1017    const int pid = get_interposed_pid();
1018    if (pid >= 0)
1019    {
1020        Locker locker (&g_mutex);
1021        const int err = close$NOCANCEL(fd);
1022        NegativeErrorErrno err_errno(err);
1023        StringSP description_sp (new String);
1024        if (err == -1)
1025            description_sp->printf("pid=%i: close$NOCANCEL (fd=%i) => %i errno = %i (%s))", pid, fd, err, err_errno.get_errno(), strerror(err_errno.get_errno()));
1026        else
1027            description_sp->printf("pid=%i: close$NOCANCEL (fd=%i) => %i", pid, fd, err);
1028        if (g_log_all_calls)
1029            description_sp->log (get_logging_fd());
1030
1031        if (err == 0)
1032        {
1033            if (fd >= 0)
1034                save_backtrace (fd, err, description_sp, false);
1035        }
1036        else if (err == -1)
1037        {
1038            if (err_errno.get_errno() == EBADF && fd != -1)
1039            {
1040                backtrace_error ("close$NOCANCEL (fd=%d) resulted in EBADF\n:", fd);
1041
1042                FDEventMap::iterator pos = g_fd_event_map.find (fd);
1043                if (pos != g_fd_event_map.end())
1044                {
1045                    log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously %s with this event:\n", fd, pos->second.back()->IsCreateEvent() ? "opened" : "closed");
1046                }
1047            }
1048        }
1049        return err;
1050    }
1051    else
1052    {
1053        return close$NOCANCEL(fd);
1054    }
1055}
1056
1057//----------------------------------------------------------------------
1058// pipe() interpose function
1059//----------------------------------------------------------------------
1060extern "C" int
1061pipe$__interposed__ (int fds[2])
1062{
1063    const int pid = get_interposed_pid();
1064    if (pid >= 0)
1065    {
1066        Locker locker (&g_mutex);
1067        fds[0] = -1;
1068        fds[1] = -1;
1069        const int err = pipe (fds);
1070        const int saved_errno = errno;
1071        StringSP description_sp(new String ("pid=%i: pipe ({fd=%i, fd=%i}) -> err=%i", pid, fds[0], fds[1], err));
1072        if (g_log_all_calls)
1073            description_sp->log (get_logging_fd());
1074        if (fds[0] >= 0)
1075            save_backtrace (fds[0], saved_errno, description_sp, true);
1076        if (fds[1] >= 0)
1077            save_backtrace (fds[1], saved_errno, description_sp, true);
1078        errno = saved_errno;
1079        return err;
1080    }
1081    else
1082    {
1083        return pipe (fds);
1084    }
1085}
1086
1087//----------------------------------------------------------------------
1088// get_fd_history()
1089//
1090// This function allows runtime access to the file descriptor history.
1091//
1092// @param[in] log_fd
1093//      The file descriptor to log to
1094//
1095// @param[in] fd
1096//      The file descriptor whose history should be dumped
1097//----------------------------------------------------------------------
1098extern "C" void
1099get_fd_history (int log_fd, int fd)
1100{
1101    // "create" below needs to be outside of the mutex locker scope
1102    if (log_fd >= 0)
1103    {
1104        bool got_lock = false;
1105        Locker locker (&g_mutex, got_lock);
1106        if (got_lock)
1107        {
1108            FDEventMap::iterator pos = g_fd_event_map.find (fd);
1109            log_to_fd (log_fd, "Dumping file descriptor history for fd=%i:\n", fd);
1110            if (pos != g_fd_event_map.end())
1111            {
1112                FDEventArray &event_array = g_fd_event_map[fd];
1113                const size_t num_events = event_array.size();
1114                for (size_t i=0; i<num_events; ++i)
1115                    event_array[i]->Dump (log_fd);
1116            }
1117            else
1118            {
1119                log_to_fd (log_fd, "error: no file descriptor events found for fd=%i\n", fd);
1120            }
1121        }
1122        else
1123        {
1124            log_to_fd (log_fd, "error: fd event mutex is locked...\n");
1125        }
1126    }
1127}
1128
1129//----------------------------------------------------------------------
1130// Interposing
1131//----------------------------------------------------------------------
1132// FD creation routines
1133DYLD_INTERPOSE(accept$__interposed__, accept);
1134DYLD_INTERPOSE(accept$NOCANCEL$__interposed__, accept$NOCANCEL);
1135DYLD_INTERPOSE(dup$__interposed__, dup);
1136DYLD_INTERPOSE(dup2$__interposed__, dup2);
1137DYLD_INTERPOSE(kqueue$__interposed__, kqueue);
1138DYLD_INTERPOSE(open$__interposed__, open);
1139DYLD_INTERPOSE(open$NOCANCEL$__interposed__, open$NOCANCEL);
1140DYLD_INTERPOSE(__open_extended$__interposed__, __open_extended);
1141DYLD_INTERPOSE(pipe$__interposed__, pipe);
1142DYLD_INTERPOSE(shm_open$__interposed__, shm_open);
1143DYLD_INTERPOSE(socket$__interposed__, socket);
1144DYLD_INTERPOSE(socketpair$__interposed__, socketpair);
1145
1146// FD deleting routines
1147DYLD_INTERPOSE(close$__interposed__, close);
1148DYLD_INTERPOSE(close$NOCANCEL$__interposed__, close$NOCANCEL);
1149
1150} // namespace fd_interposing
1151
1152
1153