File: | include/sys/select.h |
Warning: | line 95, column 10 Array access (via field 'fds_bits') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- SelectHelper.cpp --------------------------------------------------===// | ||||
2 | // | ||||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
4 | // See https://llvm.org/LICENSE.txt for license information. | ||||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
6 | // | ||||
7 | //===----------------------------------------------------------------------===// | ||||
8 | |||||
9 | #if defined(__APPLE__) | ||||
10 | // Enable this special support for Apple builds where we can have unlimited | ||||
11 | // select bounds. We tried switching to poll() and kqueue and we were panicing | ||||
12 | // the kernel, so we have to stick with select for now. | ||||
13 | #define _DARWIN_UNLIMITED_SELECT | ||||
14 | #endif | ||||
15 | |||||
16 | #include "lldb/Utility/SelectHelper.h" | ||||
17 | #include "lldb/Utility/LLDBAssert.h" | ||||
18 | #include "lldb/Utility/Status.h" | ||||
19 | #include "lldb/lldb-enumerations.h" | ||||
20 | #include "lldb/lldb-types.h" | ||||
21 | |||||
22 | #include "llvm/ADT/DenseMap.h" | ||||
23 | |||||
24 | #include <algorithm> | ||||
25 | #include <chrono> | ||||
26 | #include <optional> | ||||
27 | |||||
28 | #include <cerrno> | ||||
29 | #if defined(_WIN32) | ||||
30 | // Define NOMINMAX to avoid macros that conflict with std::min and std::max | ||||
31 | #define NOMINMAX | ||||
32 | #include <winsock2.h> | ||||
33 | #else | ||||
34 | #include <sys/time.h> | ||||
35 | #include <sys/select.h> | ||||
36 | #endif | ||||
37 | |||||
38 | |||||
39 | SelectHelper::SelectHelper() | ||||
40 | : m_fd_map(), m_end_time() // Infinite timeout unless | ||||
41 | // SelectHelper::SetTimeout() gets called | ||||
42 | {} | ||||
43 | |||||
44 | void SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) { | ||||
45 | using namespace std::chrono; | ||||
46 | m_end_time = steady_clock::time_point(steady_clock::now() + timeout); | ||||
47 | } | ||||
48 | |||||
49 | void SelectHelper::FDSetRead(lldb::socket_t fd) { | ||||
50 | m_fd_map[fd].read_set = true; | ||||
51 | } | ||||
52 | |||||
53 | void SelectHelper::FDSetWrite(lldb::socket_t fd) { | ||||
54 | m_fd_map[fd].write_set = true; | ||||
55 | } | ||||
56 | |||||
57 | void SelectHelper::FDSetError(lldb::socket_t fd) { | ||||
58 | m_fd_map[fd].error_set = true; | ||||
59 | } | ||||
60 | |||||
61 | bool SelectHelper::FDIsSetRead(lldb::socket_t fd) const { | ||||
62 | auto pos = m_fd_map.find(fd); | ||||
63 | if (pos != m_fd_map.end()) | ||||
64 | return pos->second.read_is_set; | ||||
65 | else | ||||
66 | return false; | ||||
67 | } | ||||
68 | |||||
69 | bool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const { | ||||
70 | auto pos = m_fd_map.find(fd); | ||||
71 | if (pos != m_fd_map.end()) | ||||
72 | return pos->second.write_is_set; | ||||
73 | else | ||||
74 | return false; | ||||
75 | } | ||||
76 | |||||
77 | bool SelectHelper::FDIsSetError(lldb::socket_t fd) const { | ||||
78 | auto pos = m_fd_map.find(fd); | ||||
79 | if (pos != m_fd_map.end()) | ||||
80 | return pos->second.error_is_set; | ||||
81 | else | ||||
82 | return false; | ||||
83 | } | ||||
84 | |||||
85 | static void updateMaxFd(std::optional<lldb::socket_t> &vold, | ||||
86 | lldb::socket_t vnew) { | ||||
87 | if (!vold) | ||||
88 | vold = vnew; | ||||
89 | else | ||||
90 | vold = std::max(*vold, vnew); | ||||
91 | } | ||||
92 | |||||
93 | lldb_private::Status SelectHelper::Select() { | ||||
94 | lldb_private::Status error; | ||||
95 | #ifdef _WIN32 | ||||
96 | // On windows FD_SETSIZE limits the number of file descriptors, not their | ||||
97 | // numeric value. | ||||
98 | lldbassert(m_fd_map.size() <= FD_SETSIZE)lldb_private::lldb_assert(static_cast<bool>(m_fd_map.size () <= 1024), "m_fd_map.size() <= FD_SETSIZE", __FUNCTION__ , "/usr/src/gnu/usr.bin/clang/liblldbUtility/../../../llvm/lldb/source/Utility/SelectHelper.cpp" , 98); | ||||
99 | if (m_fd_map.size() > FD_SETSIZE1024) | ||||
100 | return lldb_private::Status("Too many file descriptors for select()"); | ||||
101 | #endif | ||||
102 | |||||
103 | std::optional<lldb::socket_t> max_read_fd; | ||||
104 | std::optional<lldb::socket_t> max_write_fd; | ||||
105 | std::optional<lldb::socket_t> max_error_fd; | ||||
106 | std::optional<lldb::socket_t> max_fd; | ||||
107 | for (auto &pair : m_fd_map) { | ||||
108 | pair.second.PrepareForSelect(); | ||||
109 | const lldb::socket_t fd = pair.first; | ||||
110 | #if !defined(__APPLE__) && !defined(_WIN32) | ||||
111 | lldbassert(fd < static_cast<int>(FD_SETSIZE))lldb_private::lldb_assert(static_cast<bool>(fd < static_cast <int>(1024)), "fd < static_cast<int>(FD_SETSIZE)" , __FUNCTION__, "/usr/src/gnu/usr.bin/clang/liblldbUtility/../../../llvm/lldb/source/Utility/SelectHelper.cpp" , 111); | ||||
| |||||
112 | if (fd
| ||||
113 | error.SetErrorStringWithFormat("%i is too large for select()", fd); | ||||
114 | return error; | ||||
115 | } | ||||
116 | #endif | ||||
117 | if (pair.second.read_set) | ||||
118 | updateMaxFd(max_read_fd, fd); | ||||
119 | if (pair.second.write_set) | ||||
120 | updateMaxFd(max_write_fd, fd); | ||||
121 | if (pair.second.error_set) | ||||
122 | updateMaxFd(max_error_fd, fd); | ||||
123 | updateMaxFd(max_fd, fd); | ||||
124 | } | ||||
125 | |||||
126 | if (!max_fd) { | ||||
127 | error.SetErrorString("no valid file descriptors"); | ||||
128 | return error; | ||||
129 | } | ||||
130 | |||||
131 | const unsigned nfds = static_cast<unsigned>(*max_fd) + 1; | ||||
132 | fd_set *read_fdset_ptr = nullptr; | ||||
133 | fd_set *write_fdset_ptr = nullptr; | ||||
134 | fd_set *error_fdset_ptr = nullptr; | ||||
135 | // Initialize and zero out the fdsets | ||||
136 | #if defined(__APPLE__) | ||||
137 | llvm::SmallVector<fd_set, 1> read_fdset; | ||||
138 | llvm::SmallVector<fd_set, 1> write_fdset; | ||||
139 | llvm::SmallVector<fd_set, 1> error_fdset; | ||||
140 | |||||
141 | if (max_read_fd.has_value()) { | ||||
142 | read_fdset.resize((nfds / FD_SETSIZE1024) + 1); | ||||
143 | read_fdset_ptr = read_fdset.data(); | ||||
144 | } | ||||
145 | if (max_write_fd.has_value()) { | ||||
146 | write_fdset.resize((nfds / FD_SETSIZE1024) + 1); | ||||
147 | write_fdset_ptr = write_fdset.data(); | ||||
148 | } | ||||
149 | if (max_error_fd.has_value()) { | ||||
150 | error_fdset.resize((nfds / FD_SETSIZE1024) + 1); | ||||
151 | error_fdset_ptr = error_fdset.data(); | ||||
152 | } | ||||
153 | for (auto &fd_set : read_fdset) | ||||
154 | FD_ZERO(&fd_set)do { fd_set *_p = (&fd_set); __size_t _n = (((1024) + ((( (unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)(sizeof (__fd_mask) * 8)))); while (_n > 0) _p->fds_bits[--_n] = 0; } while (0); | ||||
155 | for (auto &fd_set : write_fdset) | ||||
156 | FD_ZERO(&fd_set)do { fd_set *_p = (&fd_set); __size_t _n = (((1024) + ((( (unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)(sizeof (__fd_mask) * 8)))); while (_n > 0) _p->fds_bits[--_n] = 0; } while (0); | ||||
157 | for (auto &fd_set : error_fdset) | ||||
158 | FD_ZERO(&fd_set)do { fd_set *_p = (&fd_set); __size_t _n = (((1024) + ((( (unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)(sizeof (__fd_mask) * 8)))); while (_n > 0) _p->fds_bits[--_n] = 0; } while (0); | ||||
159 | #else | ||||
160 | fd_set read_fdset; | ||||
161 | fd_set write_fdset; | ||||
162 | fd_set error_fdset; | ||||
163 | |||||
164 | if (max_read_fd) { | ||||
165 | FD_ZERO(&read_fdset)do { fd_set *_p = (&read_fdset); __size_t _n = (((1024) + ((((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)( sizeof(__fd_mask) * 8)))); while (_n > 0) _p->fds_bits[ --_n] = 0; } while (0); | ||||
166 | read_fdset_ptr = &read_fdset; | ||||
167 | } | ||||
168 | if (max_write_fd) { | ||||
169 | FD_ZERO(&write_fdset)do { fd_set *_p = (&write_fdset); __size_t _n = (((1024) + ((((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)( sizeof(__fd_mask) * 8)))); while (_n > 0) _p->fds_bits[ --_n] = 0; } while (0); | ||||
170 | write_fdset_ptr = &write_fdset; | ||||
171 | } | ||||
172 | if (max_error_fd) { | ||||
173 | FD_ZERO(&error_fdset)do { fd_set *_p = (&error_fdset); __size_t _n = (((1024) + ((((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)( sizeof(__fd_mask) * 8)))); while (_n > 0) _p->fds_bits[ --_n] = 0; } while (0); | ||||
174 | error_fdset_ptr = &error_fdset; | ||||
175 | } | ||||
176 | #endif | ||||
177 | // Set the FD bits in the fdsets for read/write/error | ||||
178 | for (auto &pair : m_fd_map) { | ||||
179 | const lldb::socket_t fd = pair.first; | ||||
180 | |||||
181 | if (pair.second.read_set) | ||||
182 | FD_SET(fd, read_fdset_ptr)__fd_set((fd), (read_fdset_ptr)); | ||||
183 | |||||
184 | if (pair.second.write_set) | ||||
185 | FD_SET(fd, write_fdset_ptr)__fd_set((fd), (write_fdset_ptr)); | ||||
186 | |||||
187 | if (pair.second.error_set) | ||||
188 | FD_SET(fd, error_fdset_ptr)__fd_set((fd), (error_fdset_ptr)); | ||||
189 | } | ||||
190 | |||||
191 | // Setup our timeout time value if needed | ||||
192 | struct timeval *tv_ptr = nullptr; | ||||
193 | struct timeval tv = {0, 0}; | ||||
194 | |||||
195 | while (true) { | ||||
196 | using namespace std::chrono; | ||||
197 | // Setup out relative timeout based on the end time if we have one | ||||
198 | if (m_end_time) { | ||||
199 | tv_ptr = &tv; | ||||
200 | const auto remaining_dur = | ||||
201 | duration_cast<microseconds>(*m_end_time - steady_clock::now()); | ||||
202 | if (remaining_dur.count() > 0) { | ||||
203 | // Wait for a specific amount of time | ||||
204 | const auto dur_secs = duration_cast<seconds>(remaining_dur); | ||||
205 | const auto dur_usecs = remaining_dur % seconds(1); | ||||
206 | tv.tv_sec = dur_secs.count(); | ||||
207 | tv.tv_usec = dur_usecs.count(); | ||||
208 | } else { | ||||
209 | // Just poll once with no timeout | ||||
210 | tv.tv_sec = 0; | ||||
211 | tv.tv_usec = 0; | ||||
212 | } | ||||
213 | } | ||||
214 | const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr, | ||||
215 | error_fdset_ptr, tv_ptr); | ||||
216 | if (num_set_fds < 0) { | ||||
217 | // We got an error | ||||
218 | error.SetErrorToErrno(); | ||||
219 | if (error.GetError() == EINTR4) { | ||||
220 | error.Clear(); | ||||
221 | continue; // Keep calling select if we get EINTR | ||||
222 | } else | ||||
223 | return error; | ||||
224 | } else if (num_set_fds == 0) { | ||||
225 | // Timeout | ||||
226 | error.SetError(ETIMEDOUT60, lldb::eErrorTypePOSIX); | ||||
227 | error.SetErrorString("timed out"); | ||||
228 | return error; | ||||
229 | } else { | ||||
230 | // One or more descriptors were set, update the FDInfo::select_is_set | ||||
231 | // mask so users can ask the SelectHelper class so clients can call one | ||||
232 | // of: | ||||
233 | |||||
234 | for (auto &pair : m_fd_map) { | ||||
235 | const int fd = pair.first; | ||||
236 | |||||
237 | if (pair.second.read_set) { | ||||
238 | if (FD_ISSET(fd, read_fdset_ptr)__fd_isset((fd), (read_fdset_ptr))) | ||||
239 | pair.second.read_is_set = true; | ||||
240 | } | ||||
241 | if (pair.second.write_set) { | ||||
242 | if (FD_ISSET(fd, write_fdset_ptr)__fd_isset((fd), (write_fdset_ptr))) | ||||
243 | pair.second.write_is_set = true; | ||||
244 | } | ||||
245 | if (pair.second.error_set) { | ||||
246 | if (FD_ISSET(fd, error_fdset_ptr)__fd_isset((fd), (error_fdset_ptr))) | ||||
247 | pair.second.error_is_set = true; | ||||
248 | } | ||||
249 | } | ||||
250 | break; | ||||
251 | } | ||||
252 | } | ||||
253 | return error; | ||||
254 | } |
1 | /* $OpenBSD: select.h,v 1.17 2016/09/12 19:41:20 guenther Exp $ */ | |||
2 | ||||
3 | /*- | |||
4 | * Copyright (c) 1992, 1993 | |||
5 | * The Regents of the University of California. All rights reserved. | |||
6 | * | |||
7 | * Redistribution and use in source and binary forms, with or without | |||
8 | * modification, are permitted provided that the following conditions | |||
9 | * are met: | |||
10 | * 1. Redistributions of source code must retain the above copyright | |||
11 | * notice, this list of conditions and the following disclaimer. | |||
12 | * 2. Redistributions in binary form must reproduce the above copyright | |||
13 | * notice, this list of conditions and the following disclaimer in the | |||
14 | * documentation and/or other materials provided with the distribution. | |||
15 | * 3. Neither the name of the University nor the names of its contributors | |||
16 | * may be used to endorse or promote products derived from this software | |||
17 | * without specific prior written permission. | |||
18 | * | |||
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
29 | * SUCH DAMAGE. | |||
30 | * | |||
31 | * @(#)select.h 8.2 (Berkeley) 1/4/94 | |||
32 | */ | |||
33 | ||||
34 | #ifndef _SYS_SELECT_H_ | |||
35 | #define _SYS_SELECT_H_ | |||
36 | ||||
37 | #include <sys/types.h> | |||
38 | ||||
39 | #ifndef _TIMEVAL_DECLARED | |||
40 | #define _TIMEVAL_DECLARED | |||
41 | struct timeval { | |||
42 | time_t tv_sec; /* seconds */ | |||
43 | suseconds_t tv_usec; /* and microseconds */ | |||
44 | }; | |||
45 | #endif | |||
46 | ||||
47 | #ifndef _TIMESPEC_DECLARED | |||
48 | #define _TIMESPEC_DECLARED | |||
49 | struct timespec { | |||
50 | time_t tv_sec; /* seconds */ | |||
51 | long tv_nsec; /* and nanoseconds */ | |||
52 | }; | |||
53 | #endif | |||
54 | ||||
55 | /* | |||
56 | * Select uses bit masks of file descriptors in longs. These macros | |||
57 | * manipulate such bit fields (the filesystem macros use chars). | |||
58 | * FD_SETSIZE may be defined by the user, but the default here should | |||
59 | * be enough for most uses. | |||
60 | */ | |||
61 | #ifndef FD_SETSIZE1024 | |||
62 | #define FD_SETSIZE1024 1024 | |||
63 | #endif | |||
64 | ||||
65 | /* | |||
66 | * We don't want to pollute the namespace with select(2) internals. | |||
67 | * Non-underscore versions are exposed later #if __BSD_VISIBLE | |||
68 | */ | |||
69 | #define __NBBY8 8 /* number of bits in a byte */ | |||
70 | typedef uint32_t __fd_mask; | |||
71 | #define __NFDBITS((unsigned)(sizeof(__fd_mask) * 8)) ((unsigned)(sizeof(__fd_mask) * __NBBY8)) /* bits per mask */ | |||
72 | #define __howmany(x, y)(((x) + ((y) - 1)) / (y)) (((x) + ((y) - 1)) / (y)) | |||
73 | ||||
74 | typedef struct fd_set { | |||
75 | __fd_mask fds_bits[__howmany(FD_SETSIZE, __NFDBITS)(((1024) + ((((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / ((( unsigned)(sizeof(__fd_mask) * 8))))]; | |||
76 | } fd_set; | |||
77 | ||||
78 | static __inlineinline void | |||
79 | __fd_set(int fd, fd_set *p) | |||
80 | { | |||
81 | p->fds_bits[fd / __NFDBITS((unsigned)(sizeof(__fd_mask) * 8))] |= (1U << (fd % __NFDBITS((unsigned)(sizeof(__fd_mask) * 8)))); | |||
82 | } | |||
83 | #define FD_SET(n, p)__fd_set((n), (p)) __fd_set((n), (p)) | |||
84 | ||||
85 | static __inlineinline void | |||
86 | __fd_clr(int fd, fd_set *p) | |||
87 | { | |||
88 | p->fds_bits[fd / __NFDBITS((unsigned)(sizeof(__fd_mask) * 8))] &= ~(1U << (fd % __NFDBITS((unsigned)(sizeof(__fd_mask) * 8)))); | |||
89 | } | |||
90 | #define FD_CLR(n, p)__fd_clr((n), (p)) __fd_clr((n), (p)) | |||
91 | ||||
92 | static __inlineinline int | |||
93 | __fd_isset(int fd, const fd_set *p) | |||
94 | { | |||
95 | return (p->fds_bits[fd / __NFDBITS((unsigned)(sizeof(__fd_mask) * 8))] & (1U << (fd % __NFDBITS((unsigned)(sizeof(__fd_mask) * 8))))); | |||
| ||||
96 | } | |||
97 | #define FD_ISSET(n, p)__fd_isset((n), (p)) __fd_isset((n), (p)) | |||
98 | ||||
99 | #if __BSD_VISIBLE1 | |||
100 | #define FD_COPY(f, t)(void)(*(t) = *(f)) (void)(*(t) = *(f)) | |||
101 | #endif | |||
102 | #define FD_ZERO(p)do { fd_set *_p = (p); __size_t _n = (((1024) + ((((unsigned) (sizeof(__fd_mask) * 8))) - 1)) / (((unsigned)(sizeof(__fd_mask ) * 8)))); while (_n > 0) _p->fds_bits[--_n] = 0; } while (0) do { \ | |||
103 | fd_set *_p = (p); \ | |||
104 | __size_t _n = __howmany(FD_SETSIZE, __NFDBITS)(((1024) + ((((unsigned)(sizeof(__fd_mask) * 8))) - 1)) / ((( unsigned)(sizeof(__fd_mask) * 8)))); \ | |||
105 | \ | |||
106 | while (_n > 0) \ | |||
107 | _p->fds_bits[--_n] = 0; \ | |||
108 | } while (0) | |||
109 | ||||
110 | #if __BSD_VISIBLE1 | |||
111 | #define NBBY8 __NBBY8 | |||
112 | #define fd_mask__fd_mask __fd_mask | |||
113 | #define NFDBITS((unsigned)(sizeof(__fd_mask) * 8)) __NFDBITS((unsigned)(sizeof(__fd_mask) * 8)) | |||
114 | #ifndef howmany | |||
115 | #define howmany(x, y)(((x) + ((y) - 1)) / (y)) __howmany(x, y)(((x) + ((y) - 1)) / (y)) | |||
116 | #endif | |||
117 | #endif /* __BSD_VISIBLE */ | |||
118 | ||||
119 | #ifndef _KERNEL | |||
120 | #ifndef _SIGSET_T_DEFINED_ | |||
121 | #define _SIGSET_T_DEFINED_ | |||
122 | typedef unsigned int sigset_t; | |||
123 | #endif | |||
124 | ||||
125 | #ifndef _SELECT_DEFINED_ | |||
126 | #define _SELECT_DEFINED_ | |||
127 | __BEGIN_DECLSextern "C" { | |||
128 | int select(int, fd_set * __restrict, fd_set * __restrict, | |||
129 | fd_set * __restrict, struct timeval * __restrict); | |||
130 | int pselect(int, fd_set * __restrict, fd_set * __restrict, | |||
131 | fd_set * __restrict, const struct timespec * __restrict, | |||
132 | const sigset_t * __restrict); | |||
133 | __END_DECLS} | |||
134 | #endif | |||
135 | #endif /* !_KERNEL */ | |||
136 | ||||
137 | #endif /* !_SYS_SELECT_H_ */ |