1 //===-- FDInterposing.cpp ---------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
16 // To enable the interposing in a darwin program, set the DYLD_INSERT_LIBRARIES
17 // environment variable as follows:
19 // DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib /path/to/executable
21 // (setenv DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib ; /path/to/executable)
23 // Other environment variables that can alter the default actions of this
24 // interposing shared library include:
26 // "FileDescriptorStackLoggingNoCompact"
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.
35 // "FileDescriptorMinimalLogging"
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).
42 // "FileDescriptorLogFile=<path>"
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 //===----------------------------------------------------------------------===//
55 #include <mach-o/dyld.h>
56 #include <mach-o/dyld-interposing.h>
60 #include <sys/event.h>
62 #include <sys/socket.h>
63 #include <sys/types.h>
65 #include <tr1/memory> // for std::tr1::shared_ptr
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) \
77 TypeName(const TypeName&); \
78 const TypeName& operator=(const TypeName&)
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 *);
87 namespace fd_interposing {
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 //----------------------------------------------------------------------
100 String (const char *format, ...) :
104 va_start (args, format);
105 vprintf (format, args);
115 reset (char *s = NULL)
129 printf (const char *format, ...)
132 va_start (args, format);
133 vprintf (format, args);
137 vprintf (const char *format, va_list args)
140 ::vasprintf (&m_str, format, args);
146 if (m_str && log_fd >= 0)
148 const int len = strlen(m_str);
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);
162 DISALLOW_COPY_AND_ASSIGN (String);
165 //----------------------------------------------------------------------
167 //----------------------------------------------------------------------
168 typedef std::vector<void *> Frames;
170 typedef std::vector<void *> Frames;
171 typedef std::tr1::shared_ptr<FDEvent> FDEventSP;
172 typedef std::tr1::shared_ptr<String> StringSP;
175 //----------------------------------------------------------------------
178 // A class that describes a file desciptor event.
180 // File descriptor events fall into one of two categories: create events
181 // and delete events.
182 //----------------------------------------------------------------------
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()),
191 m_is_create (is_create)
197 IsCreateEvent() const
203 IsDeleteEvent() const
233 Dump (int log_fd) const;
236 SetCreateEvent (FDEventSP &create_event_sp)
238 m_create_event_sp = create_event_sp;
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
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
252 // The error code (if any) for this event
254 // True if this event is a file descriptor create event, false
255 // if it is a file descriptor delete event
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 //----------------------------------------------------------------------
264 template <int INVALID>
268 // Save errno only if we are supposed to
270 m_saved_errno ((value == INVALID) ? errno : 0),
271 m_restore (value == INVALID)
275 // Restore errno only if we are supposed to
279 errno = m_saved_errno;
282 // Accessor for the saved value of errno
286 return m_saved_errno;
290 const int m_saved_errno;
291 const bool m_restore;
294 typedef Errno<-1> InvalidFDErrno;
295 typedef Errno<-1> NegativeErrorErrno;
296 typedef std::vector<FDEventSP> FDEventArray;
297 typedef std::map<int, FDEventArray> FDEventMap;
299 //----------------------------------------------------------------------
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.
313 static 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
316 static 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
320 static 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.
323 static int g_compact = 1;
324 // The current process ID
325 static int g_pid = -1;
326 static 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 //----------------------------------------------------------------------
334 Locker (pthread_mutex_t *mutex_ptr) :
335 m_mutex_ptr(mutex_ptr)
337 ::pthread_mutex_lock (m_mutex_ptr);
340 // This allows clients to test try and acquire the mutex...
341 Locker (pthread_mutex_t *mutex_ptr, bool &lock_acquired) :
344 lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0;
346 m_mutex_ptr = mutex_ptr;
352 ::pthread_mutex_unlock (m_mutex_ptr);
355 pthread_mutex_t *m_mutex_ptr;
359 log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
362 log (int log_fd, const FDEvent *event, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
365 backtrace_log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
368 backtrace_error (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
371 log_to_fd (int log_fd, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
374 get_backtrace (Frames &frame_buffer, size_t frames_to_remove)
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]);
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();
387 static int g_log_fd = STDOUT_FILENO;
388 static int g_initialized = 0;
391 get_process_fullpath (bool force = false)
393 static char g_process_fullpath[PATH_MAX] = {0};
394 if (force || g_process_fullpath[0] == '\0')
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));
401 return g_process_fullpath;
404 // Returns the current process ID, or -1 if inserposing not enabled for
412 const pid_t pid = getpid();
418 log ("Interposing file descriptor create and delete functions for %s (pid=%i)\n", get_process_fullpath (true), pid);
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);
426 // Log when our process changes
441 const pid_t pid = get_interposed_pid();
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"))
451 if (getenv("FileDescriptorMinimalLogging"))
454 const char *log_path = getenv ("FileDescriptorLogFile");
456 g_log_fd = ::creat (log_path, 0660);
458 g_log_fd = STDOUT_FILENO;
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");
467 log ("pid=%i: logging disabled\n", getpid());
474 log_to_fd (int log_fd, const char *format, va_list args)
476 if (format && format[0] && log_fd >= 0)
478 char buffer[PATH_MAX];
479 const int count = ::vsnprintf (buffer, sizeof(buffer), format, args);
481 write (log_fd, buffer, count);
486 log_to_fd (int log_fd, const char *format, ...)
488 if (format && format[0])
491 va_start (args, format);
492 log_to_fd (log_fd, format, args);
498 log (const char *format, va_list args)
500 log_to_fd (get_logging_fd (), format, args);
504 log (const char *format, ...)
506 if (format && format[0])
509 va_start (args, format);
516 log (int log_fd, const FDEvent *event, const char *format, ...)
518 if (format && format[0])
521 va_start (args, format);
522 log_to_fd (log_fd, format, args);
530 FDEvent::Dump (int log_fd) const
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);
538 if (m_create_event_sp)
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");
549 backtrace_log (const char *format, ...)
551 const int log_fd = get_logging_fd ();
554 if (format && format[0])
557 va_start (args, format);
563 if (get_backtrace(frames, 2))
564 ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd);
570 backtrace_error (const char *format, ...)
572 const int pid = get_interposed_pid();
575 const int log_fd = get_logging_fd ();
578 log ("\nerror: %s (pid=%i): ", get_process_fullpath (), pid);
580 if (format && format[0])
583 va_start (args, format);
589 if (get_backtrace(frames, 2))
590 ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd);
596 save_backtrace (int fd, int err, const StringSP &string_sp, bool is_create)
599 get_backtrace(frames, 2);
601 FDEventSP fd_event_sp (new FDEvent (fd, err, string_sp, is_create, frames));
603 FDEventMap::iterator pos = g_fd_event_map.find (fd);
605 if (pos != g_fd_event_map.end())
607 // We have history for this fd...
609 FDEventArray &event_array = g_fd_event_map[fd];
610 if (fd_event_sp->IsCreateEvent())
612 // The current fd event is a function that creates
613 // a descriptor, check in case last event was
615 if (event_array.back()->IsCreateEvent())
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);
624 // We are compacting so we remove previous create event
625 // when we get the correspinding delete event
626 event_array.pop_back();
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())
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);
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();
652 event_array.push_back(fd_event_sp);
656 g_fd_event_map[fd].push_back(fd_event_sp);
660 //----------------------------------------------------------------------
661 // socket() interpose function
662 //----------------------------------------------------------------------
664 socket$__interposed__ (int domain, int type, int protocol)
666 const int pid = get_interposed_pid();
669 Locker locker (&g_mutex);
670 const int fd = ::socket (domain, type, protocol);
671 InvalidFDErrno fd_errno(fd);
672 StringSP description_sp(new String);
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());
676 description_sp->printf("pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i", pid, domain, type, protocol, fd);
678 description_sp->log (get_logging_fd());
680 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
685 return ::socket (domain, type, protocol);
689 //----------------------------------------------------------------------
690 // socketpair() interpose function
691 //----------------------------------------------------------------------
693 socketpair$__interposed__ (int domain, int type, int protocol, int fds[2])
695 const int pid = get_interposed_pid();
698 Locker locker (&g_mutex);
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));
705 description_sp->log (get_logging_fd());
707 save_backtrace (fds[0], err_errno.get_errno(), description_sp, true);
709 save_backtrace (fds[1], err_errno.get_errno(), description_sp, true);
714 return socketpair (domain, type, protocol, fds);
718 //----------------------------------------------------------------------
719 // open() interpose function
720 //----------------------------------------------------------------------
722 open$__interposed__ (const char *path, int oflag, int mode)
724 const int pid = get_interposed_pid();
727 Locker locker (&g_mutex);
729 StringSP description_sp(new String);
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);
737 fd = ::open (path, oflag);
738 description_sp->printf("pid=%i: open (path = '%s', oflag = %i) -> fd=%i", pid, path, oflag, fd);
741 InvalidFDErrno fd_errno(fd);
743 description_sp->log (get_logging_fd());
745 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
750 return ::open (path, oflag, mode);
754 //----------------------------------------------------------------------
755 // open$NOCANCEL() interpose function
756 //----------------------------------------------------------------------
758 open$NOCANCEL$__interposed__ (const char *path, int oflag, int mode)
760 const int pid = get_interposed_pid();
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));
768 description_sp->log (get_logging_fd());
770 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
775 return ::open$NOCANCEL (path, oflag, mode);
780 //----------------------------------------------------------------------
781 // __open_extended() interpose function
782 //----------------------------------------------------------------------
784 __open_extended$__interposed__ (const char *path, int oflag, uid_t uid, gid_t gid, int mode, struct kauth_filesec *fsacl)
786 const int pid = get_interposed_pid();
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));
794 description_sp->log (get_logging_fd());
796 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
801 return ::__open_extended (path, oflag, uid, gid, mode, fsacl);
805 //----------------------------------------------------------------------
806 // kqueue() interpose function
807 //----------------------------------------------------------------------
809 kqueue$__interposed__ (void)
811 const int pid = get_interposed_pid();
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));
819 description_sp->log (get_logging_fd());
821 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
830 //----------------------------------------------------------------------
831 // shm_open() interpose function
832 //----------------------------------------------------------------------
834 shm_open$__interposed__ (const char *path, int oflag, int mode)
836 const int pid = get_interposed_pid();
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));
844 description_sp->log (get_logging_fd());
846 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
851 return ::shm_open (path, oflag, mode);
855 //----------------------------------------------------------------------
856 // accept() interpose function
857 //----------------------------------------------------------------------
859 accept$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
861 const int pid = get_interposed_pid();
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));
869 description_sp->log (get_logging_fd());
871 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
876 return ::accept (socket, address, address_len);
881 //----------------------------------------------------------------------
882 // accept$NOCANCEL() interpose function
883 //----------------------------------------------------------------------
885 accept$NOCANCEL$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
887 const int pid = get_interposed_pid();
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));
895 description_sp->log (get_logging_fd());
897 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
902 return ::accept$NOCANCEL (socket, address, address_len);
906 //----------------------------------------------------------------------
907 // dup() interpose function
908 //----------------------------------------------------------------------
910 dup$__interposed__ (int fd2)
912 const int pid = get_interposed_pid();
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));
920 description_sp->log (get_logging_fd());
922 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
931 //----------------------------------------------------------------------
932 // dup2() interpose function
933 //----------------------------------------------------------------------
935 dup2$__interposed__ (int fd1, int fd2)
937 const int pid = get_interposed_pid();
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);
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));
953 description_sp->log (get_logging_fd());
956 save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
961 return ::dup2(fd1, fd2);
965 //----------------------------------------------------------------------
966 // close() interpose function
967 //----------------------------------------------------------------------
969 close$__interposed__ (int fd)
971 const int pid = get_interposed_pid();
974 Locker locker (&g_mutex);
975 const int err = close(fd);
976 NegativeErrorErrno err_errno(err);
977 StringSP description_sp (new String);
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()));
981 description_sp->printf("pid=%i: close (fd=%i) => %i", pid, fd, err);
983 description_sp->log (get_logging_fd());
988 save_backtrace (fd, err, description_sp, false);
992 if (err_errno.get_errno() == EBADF && fd != -1)
994 backtrace_error ("close (fd=%d) resulted in EBADF:\n", fd);
996 FDEventMap::iterator pos = g_fd_event_map.find (fd);
997 if (pos != g_fd_event_map.end())
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");
1011 //----------------------------------------------------------------------
1012 // close$NOCANCEL() interpose function
1013 //----------------------------------------------------------------------
1015 close$NOCANCEL$__interposed__ (int fd)
1017 const int pid = get_interposed_pid();
1020 Locker locker (&g_mutex);
1021 const int err = close$NOCANCEL(fd);
1022 NegativeErrorErrno err_errno(err);
1023 StringSP description_sp (new String);
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()));
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());
1034 save_backtrace (fd, err, description_sp, false);
1038 if (err_errno.get_errno() == EBADF && fd != -1)
1040 backtrace_error ("close$NOCANCEL (fd=%d) resulted in EBADF\n:", fd);
1042 FDEventMap::iterator pos = g_fd_event_map.find (fd);
1043 if (pos != g_fd_event_map.end())
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");
1053 return close$NOCANCEL(fd);
1057 //----------------------------------------------------------------------
1058 // pipe() interpose function
1059 //----------------------------------------------------------------------
1061 pipe$__interposed__ (int fds[2])
1063 const int pid = get_interposed_pid();
1066 Locker locker (&g_mutex);
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());
1075 save_backtrace (fds[0], saved_errno, description_sp, true);
1077 save_backtrace (fds[1], saved_errno, description_sp, true);
1078 errno = saved_errno;
1087 //----------------------------------------------------------------------
1090 // This function allows runtime access to the file descriptor history.
1092 // @param[in] log_fd
1093 // The file descriptor to log to
1096 // The file descriptor whose history should be dumped
1097 //----------------------------------------------------------------------
1099 get_fd_history (int log_fd, int fd)
1101 // "create" below needs to be outside of the mutex locker scope
1104 bool got_lock = false;
1105 Locker locker (&g_mutex, got_lock);
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())
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);
1119 log_to_fd (log_fd, "error: no file descriptor events found for fd=%i\n", fd);
1124 log_to_fd (log_fd, "error: fd event mutex is locked...\n");
1129 //----------------------------------------------------------------------
1131 //----------------------------------------------------------------------
1132 // FD creation routines
1133 DYLD_INTERPOSE(accept$__interposed__, accept);
1134 DYLD_INTERPOSE(accept$NOCANCEL$__interposed__, accept$NOCANCEL);
1135 DYLD_INTERPOSE(dup$__interposed__, dup);
1136 DYLD_INTERPOSE(dup2$__interposed__, dup2);
1137 DYLD_INTERPOSE(kqueue$__interposed__, kqueue);
1138 DYLD_INTERPOSE(open$__interposed__, open);
1139 DYLD_INTERPOSE(open$NOCANCEL$__interposed__, open$NOCANCEL);
1140 DYLD_INTERPOSE(__open_extended$__interposed__, __open_extended);
1141 DYLD_INTERPOSE(pipe$__interposed__, pipe);
1142 DYLD_INTERPOSE(shm_open$__interposed__, shm_open);
1143 DYLD_INTERPOSE(socket$__interposed__, socket);
1144 DYLD_INTERPOSE(socketpair$__interposed__, socketpair);
1146 // FD deleting routines
1147 DYLD_INTERPOSE(close$__interposed__, close);
1148 DYLD_INTERPOSE(close$NOCANCEL$__interposed__, close$NOCANCEL);
1150 } // namespace fd_interposing