libexcept 1.1.19
Stack trace along C++ exceptions
file_inheritance.cpp
Go to the documentation of this file.
1// Copyright (c) 2011-2025 Made to Order Software Corp. All Rights Reserved
2//
3// https://snapwebsites.org/
4// contact@m2osw.com
5//
6// This program is free software; you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation; either version 2 of the License, or
9// (at your option) any later version.
10//
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with this program; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19
20// self
21//
23
24
25// C++
26//
27#include <fstream>
28#include <iostream>
29#include <list>
30#include <memory>
31
32
33// C
34//
35#include <dirent.h>
36#include <string.h>
37#include <unistd.h>
38
39
49namespace libexcept
50{
51
52
53
68std::string get_command_line(pid_t pid)
69{
70 std::string filename("/proc/");
71 filename += std::to_string(pid);
72 filename += "/cmdline";
73 std::ifstream cmdline(filename);
74 std::string line;
75 std::getline(cmdline, line, '\0');
76 return line;
77}
78
79
97{
98 auto closedir = [](DIR * d)
99 {
100 ::closedir(d);
101 };
102
103 int errcnt(0);
104
105 std::string path("/proc/");
106 path += std::to_string(getpid());
107 path += "/fd";
108 DIR * d(opendir(path.c_str()));
109 std::unique_ptr<DIR, decltype(closedir)> auto_close(d, closedir);
110
111 for(;;)
112 {
113 dirent const * ent(readdir(d));
114 if(ent == nullptr)
115 {
116 break;
117 }
118
119 char const * basename(ent->d_name);
120 if(basename[0] == '.')
121 {
122 // ignore all hidden files
123 continue;
124 }
125
126 if(basename[0] >= '0'
127 && basename[0] <= '2'
128 && basename[1] == '\0')
129 {
130 // skip stdin, stdout, stderr
131 continue;
132 }
133
134 int const fd(std::atoi(basename));
135 if(fd == dirfd(d))
136 {
137 // ignore the opendir() file descriptor
138 // (it is currently open since we are reading the directory)
139 //
140 continue;
141 }
142
143 if(allowed.find(fd) == allowed.end())
144 {
145 char link[256];
146 ssize_t const l(readlink((path + '/' + basename).c_str(), link, sizeof(link) - 1));
147 if(l <= 0)
148 {
149 link[0] = '\0';
150 }
151 else
152 {
153 link[l] = '\0';
154 }
155 std::cerr
156 << "warning: file descriptor "
157 << fd
158 << " ("
159 << link
160 << ") leaked on invocation. Parent PID "
161 << getppid()
162 << ": "
163 << get_command_line(getppid())
164 << '\n';
165 ++errcnt;
166 }
167 }
168
169#ifdef _DEBUG
170 if(errcnt > 0)
171 {
172 // this is a logic error
173 //
174 throw file_inherited("found unexpected file descriptor leaks.");
175 }
176#endif
177}
178
179
180
181}
182// namespace libexcept
183// vim: ts=4 sw=4 et
Declarations of the stack trace functions.
std::set< int > allowed_fds_t
std::string get_command_line(pid_t pid)
Load the command line of the specified process.
void verify_inherited_files(allowed_fds_t allowed)
Check the list of files opened in this process.

This document is part of the Snap! Websites Project.

Copyright by Made to Order Software Corp.