File: | build/source/lldb/source/Utility/SelectHelper.cpp |
Warning: | line 185, column 7 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__ , "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__, "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 { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq" : "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) / sizeof (__fd_mask)), "1" (&((&fd_set)->fds_bits)[ 0]) : "memory"); } while (0); | |||
155 | for (auto &fd_set : write_fdset) | |||
156 | FD_ZERO(&fd_set)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq" : "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) / sizeof (__fd_mask)), "1" (&((&fd_set)->fds_bits)[ 0]) : "memory"); } while (0); | |||
157 | for (auto &fd_set : error_fdset) | |||
158 | FD_ZERO(&fd_set)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq" : "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) / sizeof (__fd_mask)), "1" (&((&fd_set)->fds_bits)[ 0]) : "memory"); } 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 { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq" : "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) / sizeof (__fd_mask)), "1" (&((&read_fdset)->fds_bits )[0]) : "memory"); } while (0); | |||
166 | read_fdset_ptr = &read_fdset; | |||
167 | } | |||
168 | if (max_write_fd) { | |||
169 | FD_ZERO(&write_fdset)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq" : "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) / sizeof (__fd_mask)), "1" (&((&write_fdset)->fds_bits )[0]) : "memory"); } while (0); | |||
170 | write_fdset_ptr = &write_fdset; | |||
171 | } | |||
172 | if (max_error_fd) { | |||
173 | FD_ZERO(&error_fdset)do { int __d0, __d1; __asm__ __volatile__ ("cld; rep; " "stosq" : "=c" (__d0), "=D" (__d1) : "a" (0), "0" (sizeof (fd_set) / sizeof (__fd_mask)), "1" (&((&error_fdset)->fds_bits )[0]) : "memory"); } 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)((void) (((read_fdset_ptr)->fds_bits)[__extension__ ({ long int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d && __d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn (__d)) : __fdelt_chk (__d)); })] |= ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof (__fd_mask))))))); | |||
183 | ||||
184 | if (pair.second.write_set) | |||
185 | FD_SET(fd, write_fdset_ptr)((void) (((write_fdset_ptr)->fds_bits)[__extension__ ({ long int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d && __d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn (__d)) : __fdelt_chk (__d)); })] |= ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof (__fd_mask))))))); | |||
| ||||
186 | ||||
187 | if (pair.second.error_set) | |||
188 | FD_SET(fd, error_fdset_ptr)((void) (((error_fdset_ptr)->fds_bits)[__extension__ ({ long int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d && __d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn (__d)) : __fdelt_chk (__d)); })] |= ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof (__fd_mask))))))); | |||
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(ETIMEDOUT110, 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)((((read_fdset_ptr)->fds_bits)[__extension__ ({ long int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d && __d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn (__d)) : __fdelt_chk (__d)); })] & ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof (__fd_mask)))))) != 0)) | |||
239 | pair.second.read_is_set = true; | |||
240 | } | |||
241 | if (pair.second.write_set) { | |||
242 | if (FD_ISSET(fd, write_fdset_ptr)((((write_fdset_ptr)->fds_bits)[__extension__ ({ long int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d && __d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn (__d)) : __fdelt_chk (__d)); })] & ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof (__fd_mask)))))) != 0)) | |||
243 | pair.second.write_is_set = true; | |||
244 | } | |||
245 | if (pair.second.error_set) { | |||
246 | if (FD_ISSET(fd, error_fdset_ptr)((((error_fdset_ptr)->fds_bits)[__extension__ ({ long int __d = (fd); (__builtin_constant_p (__d) ? (0 <= __d && __d < 1024 ? (__d / (8 * (int) sizeof (__fd_mask))) : __fdelt_warn (__d)) : __fdelt_chk (__d)); })] & ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof (__fd_mask)))))) != 0)) | |||
247 | pair.second.error_is_set = true; | |||
248 | } | |||
249 | } | |||
250 | break; | |||
251 | } | |||
252 | } | |||
253 | return error; | |||
254 | } |