File: | _build/../src/missing.cc |
Warning: | line 163, column 20 Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright © 2020 Christian Persch |
3 | * |
4 | * This library is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU Lesser General Public |
6 | * License as published by the Free Software Foundation; either |
7 | * version 3 of the License, or (at your option) any later version. |
8 | * |
9 | * This library is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | * Lesser General Public License for more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License |
15 | * along with this program. If not, see <https://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include "config.h" |
19 | |
20 | #ifdef HAVE_SYS_RESOURCE_H |
21 | #include <sys/resource.h> |
22 | #endif |
23 | |
24 | #include <glib-unix1.h> |
25 | #include <gio/gio.h> |
26 | |
27 | #ifdef __linux__1 |
28 | #include <sys/syscall.h> /* for syscall and SYS_getdents64 */ |
29 | #endif |
30 | |
31 | #include "missing.hh" |
32 | |
33 | /* BEGIN copied from glib |
34 | * |
35 | * Code for fdwalk copied from glib/glib/gspawn.c, there under LGPL2.1+, |
36 | * and used here under LGPL3+. |
37 | * |
38 | * Copyright 2000 Red Hat, Inc. |
39 | */ |
40 | |
41 | #ifndef HAVE_FDWALK |
42 | |
43 | #ifdef __linux__1 |
44 | |
45 | struct linux_dirent64 |
46 | { |
47 | guint64 d_ino; /* 64-bit inode number */ |
48 | guint64 d_off; /* 64-bit offset to next structure */ |
49 | unsigned short d_reclen; /* Size of this dirent */ |
50 | char d_name[]; /* Filename (null-terminated) */ |
51 | }; |
52 | |
53 | /* This function is called between fork and execve/_exit and so must be |
54 | * async-signal-safe; see man:signal-safety(7). |
55 | */ |
56 | static int |
57 | filename_to_fd (const char *p) |
58 | { |
59 | char c; |
60 | int fd = 0; |
61 | const int cutoff = G_MAXINT2147483647 / 10; |
62 | const int cutlim = G_MAXINT2147483647 % 10; |
63 | |
64 | if (*p == '\0') |
65 | return -1; |
66 | |
67 | while ((c = *p++) != '\0') |
68 | { |
69 | if (c < '0' || c > '9') |
70 | return -1; |
71 | c -= '0'; |
72 | |
73 | /* Check for overflow. */ |
74 | if (fd > cutoff || (fd == cutoff && c > cutlim)) |
75 | return -1; |
76 | |
77 | fd = fd * 10 + c; |
78 | } |
79 | |
80 | return fd; |
81 | } |
82 | |
83 | #endif /* __linux__ */ |
84 | |
85 | /* This function is called between fork and execve/_exit and so must be |
86 | * async-signal-safe; see man:signal-safety(7). |
87 | */ |
88 | static rlim_t |
89 | getrlimit_NOFILE_max(void) |
90 | { |
91 | #ifdef HAVE_SYS_RESOURCE_H |
92 | #ifdef __linux__1 |
93 | { |
94 | struct rlimit rlim; |
95 | |
96 | if (prlimit(0 /* this PID */, RLIMIT_NOFILERLIMIT_NOFILE, nullptr, &rlim) == 0) |
97 | return rlim.rlim_max; |
98 | |
99 | return RLIM_INFINITY0xffffffffffffffffuLL; |
100 | } |
101 | #endif /* __linux__ */ |
102 | |
103 | #ifdef __GLIBC__2 |
104 | { |
105 | struct rlimit rlim; |
106 | |
107 | /* Use getrlimit() function provided by the system if it is known to be |
108 | * async-signal safe. |
109 | * |
110 | * According to the glibc manual, getrlimit is AS-safe. |
111 | */ |
112 | if (getrlimit(RLIMIT_NOFILERLIMIT_NOFILE, &rlim) == 0) |
113 | return rlim.rlim_max; |
114 | } |
115 | |
116 | /* fallback */ |
117 | #endif /* __GLIBC__ */ |
118 | |
119 | #endif /* HAVE_SYS_RESOURCE_H */ |
120 | |
121 | #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__) |
122 | /* Use sysconf() function provided by the system if it is known to be |
123 | * async-signal safe. |
124 | */ |
125 | auto const r = sysconf(_SC_OPEN_MAX_SC_OPEN_MAX); |
126 | if (r != -1) |
127 | return r; |
128 | |
129 | /* fallback */ |
130 | #endif |
131 | |
132 | /* couldn't determine, so potentially infinite */ |
133 | return RLIM_INFINITY0xffffffffffffffffuLL; |
134 | } |
135 | |
136 | /* This function is called between fork and execve/_exit and so must be |
137 | * async-signal-safe; see man:signal-safety(7). |
138 | */ |
139 | int |
140 | fdwalk(int (*cb)(void *data, int fd), |
141 | void *data) |
142 | { |
143 | /* Fallback implementation of fdwalk. It should be async-signal safe, but it |
144 | * may be slow on non-Linux operating systems, especially on systems allowing |
145 | * very high number of open file descriptors. |
146 | */ |
147 | int fd; |
148 | int res = 0; |
149 | |
150 | #ifdef __linux__1 |
151 | /* Avoid use of opendir/closedir since these are not async-signal-safe. */ |
152 | int dir_fd = open ("/proc/self/fd", O_RDONLY00 | O_DIRECTORY0200000 | O_CLOEXEC02000000); |
153 | if (dir_fd >= 0) |
154 | { |
155 | char buf[4096]; |
156 | int pos, nread; |
157 | struct linux_dirent64 *de; |
158 | |
159 | while ((nread = syscall (SYS_getdents64217, dir_fd, buf, sizeof(buf))) > 0) |
160 | { |
161 | for (pos = 0; pos < nread; pos += de->d_reclen) |
162 | { |
163 | de = (struct linux_dirent64 *)(buf + pos); |
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption | |
164 | |
165 | fd = filename_to_fd (de->d_name); |
166 | if (fd < 0 || fd == dir_fd) |
167 | continue; |
168 | |
169 | if ((res = cb (data, fd)) != 0) |
170 | break; |
171 | } |
172 | } |
173 | |
174 | close (dir_fd); |
175 | return res; |
176 | } |
177 | |
178 | /* If /proc is not mounted or not accessible we fall back to the old |
179 | * rlimit trick */ |
180 | |
181 | #endif |
182 | |
183 | auto const open_max = getrlimit_NOFILE_max(); |
184 | if (open_max == RLIM_INFINITY0xffffffffffffffffuLL || open_max > G_MAXINT2147483647) { |
185 | /* We cannot close infinitely many FDs, but we also must not |
186 | * leak any FDs. Return an error. |
187 | */ |
188 | errno(*__errno_location ()) = ENFILE23; |
189 | return -1; |
190 | } |
191 | |
192 | for (fd = 0; fd < int(open_max); fd++) |
193 | if ((res = cb (data, fd)) != 0) |
194 | break; |
195 | |
196 | return res; |
197 | } |
198 | #endif /* !HAVE_FDWALK */ |
199 | |
200 | #ifndef HAVE_STRCHRNUL |
201 | /* Copied from glib */ |
202 | char* |
203 | strchrnul(char const* s, |
204 | int c) |
205 | { |
206 | char *p = (char *) s; |
207 | while (*p && (*p != c)) |
208 | ++p; |
209 | |
210 | return p; |
211 | } |
212 | #endif /* !HAVE_STRCHRNUL */ |
213 | |
214 | /* END copied from glib */ |