File: | tools/lldb/source/Utility/SelectHelper.cpp |
Warning: | line 251, column 15 Array access (via field 'fds_bits') results in a null pointer dereference |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- SelectHelper.cpp ----------------------------------------*- C++ -*-===// | |||||
2 | // | |||||
3 | // The LLVM Compiler Infrastructure | |||||
4 | // | |||||
5 | // This file is distributed under the University of Illinois Open Source | |||||
6 | // License. See LICENSE.TXT for details. | |||||
7 | // | |||||
8 | //===----------------------------------------------------------------------===// | |||||
9 | ||||||
10 | #if defined(__APPLE__) | |||||
11 | // Enable this special support for Apple builds where we can have unlimited | |||||
12 | // select bounds. We tried switching to poll() and kqueue and we were panicing | |||||
13 | // the kernel, so we have to stick with select for now. | |||||
14 | #define _DARWIN_UNLIMITED_SELECT | |||||
15 | #endif | |||||
16 | ||||||
17 | #include "lldb/Utility/SelectHelper.h" | |||||
18 | #include "lldb/Utility/LLDBAssert.h" | |||||
19 | #include "lldb/Utility/Status.h" | |||||
20 | #include "lldb/lldb-enumerations.h" // for ErrorType::eErrorTypePOSIX | |||||
21 | #include "lldb/lldb-types.h" // for socket_t | |||||
22 | ||||||
23 | #include "llvm/ADT/DenseMap.h" // for DenseMapPair, DenseMap, Dense... | |||||
24 | #include "llvm/ADT/Optional.h" // for Optional | |||||
25 | ||||||
26 | #include <algorithm> | |||||
27 | #include <chrono> // for microseconds, seconds, steady... | |||||
28 | ||||||
29 | #include <errno(*__errno_location ()).h> | |||||
30 | #if defined(_WIN32) | |||||
31 | // Define NOMINMAX to avoid macros that conflict with std::min and std::max | |||||
32 | #define NOMINMAX | |||||
33 | #include <winsock2.h> | |||||
34 | #else | |||||
35 | #include <sys/time.h> | |||||
36 | #include <sys/select.h> | |||||
37 | #endif | |||||
38 | ||||||
39 | ||||||
40 | SelectHelper::SelectHelper() | |||||
41 | : m_fd_map(), m_end_time() // Infinite timeout unless | |||||
42 | // SelectHelper::SetTimeout() gets called | |||||
43 | {} | |||||
44 | ||||||
45 | void SelectHelper::SetTimeout(const std::chrono::microseconds &timeout) { | |||||
46 | using namespace std::chrono; | |||||
47 | m_end_time = steady_clock::time_point(steady_clock::now() + timeout); | |||||
48 | } | |||||
49 | ||||||
50 | void SelectHelper::FDSetRead(lldb::socket_t fd) { | |||||
51 | m_fd_map[fd].read_set = true; | |||||
52 | } | |||||
53 | ||||||
54 | void SelectHelper::FDSetWrite(lldb::socket_t fd) { | |||||
55 | m_fd_map[fd].write_set = true; | |||||
56 | } | |||||
57 | ||||||
58 | void SelectHelper::FDSetError(lldb::socket_t fd) { | |||||
59 | m_fd_map[fd].error_set = true; | |||||
60 | } | |||||
61 | ||||||
62 | bool SelectHelper::FDIsSetRead(lldb::socket_t fd) const { | |||||
63 | auto pos = m_fd_map.find(fd); | |||||
64 | if (pos != m_fd_map.end()) | |||||
65 | return pos->second.read_is_set; | |||||
66 | else | |||||
67 | return false; | |||||
68 | } | |||||
69 | ||||||
70 | bool SelectHelper::FDIsSetWrite(lldb::socket_t fd) const { | |||||
71 | auto pos = m_fd_map.find(fd); | |||||
72 | if (pos != m_fd_map.end()) | |||||
73 | return pos->second.write_is_set; | |||||
74 | else | |||||
75 | return false; | |||||
76 | } | |||||
77 | ||||||
78 | bool SelectHelper::FDIsSetError(lldb::socket_t fd) const { | |||||
79 | auto pos = m_fd_map.find(fd); | |||||
80 | if (pos != m_fd_map.end()) | |||||
81 | return pos->second.error_is_set; | |||||
82 | else | |||||
83 | return false; | |||||
84 | } | |||||
85 | ||||||
86 | static void updateMaxFd(llvm::Optional<lldb::socket_t> &vold, | |||||
87 | lldb::socket_t vnew) { | |||||
88 | if (!vold.hasValue()) | |||||
89 | vold = vnew; | |||||
90 | else | |||||
91 | vold = std::max(*vold, vnew); | |||||
92 | } | |||||
93 | ||||||
94 | lldb_private::Status SelectHelper::Select() { | |||||
95 | lldb_private::Status error; | |||||
96 | #ifdef _MSC_VER | |||||
97 | // On windows FD_SETSIZE limits the number of file descriptors, not their | |||||
98 | // numeric value. | |||||
99 | 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__ , "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/SelectHelper.cpp" , 99); | |||||
100 | if (m_fd_map.size() > FD_SETSIZE1024) | |||||
101 | return lldb_private::Status("Too many file descriptors for select()"); | |||||
102 | #endif | |||||
103 | ||||||
104 | llvm::Optional<lldb::socket_t> max_read_fd; | |||||
105 | llvm::Optional<lldb::socket_t> max_write_fd; | |||||
106 | llvm::Optional<lldb::socket_t> max_error_fd; | |||||
107 | llvm::Optional<lldb::socket_t> max_fd; | |||||
108 | for (auto &pair : m_fd_map) { | |||||
109 | pair.second.PrepareForSelect(); | |||||
110 | const lldb::socket_t fd = pair.first; | |||||
111 | #if !defined(__APPLE__) && !defined(_MSC_VER) | |||||
112 | 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__, "/build/llvm-toolchain-snapshot-8~svn345461/tools/lldb/source/Utility/SelectHelper.cpp" , 112); | |||||
113 | if (fd >= static_cast<int>(FD_SETSIZE1024)) { | |||||
| ||||||
114 | error.SetErrorStringWithFormat("%i is too large for select()", fd); | |||||
115 | return error; | |||||
116 | } | |||||
117 | #endif | |||||
118 | if (pair.second.read_set) | |||||
119 | updateMaxFd(max_read_fd, fd); | |||||
120 | if (pair.second.write_set) | |||||
121 | updateMaxFd(max_write_fd, fd); | |||||
122 | if (pair.second.error_set) | |||||
123 | updateMaxFd(max_error_fd, fd); | |||||
124 | updateMaxFd(max_fd, fd); | |||||
125 | } | |||||
126 | ||||||
127 | if (!max_fd.hasValue()) { | |||||
128 | error.SetErrorString("no valid file descriptors"); | |||||
129 | return error; | |||||
130 | } | |||||
131 | ||||||
132 | const unsigned nfds = static_cast<unsigned>(*max_fd) + 1; | |||||
133 | fd_set *read_fdset_ptr = nullptr; | |||||
134 | fd_set *write_fdset_ptr = nullptr; | |||||
135 | fd_set *error_fdset_ptr = nullptr; | |||||
136 | //---------------------------------------------------------------------- | |||||
137 | // Initialize and zero out the fdsets | |||||
138 | //---------------------------------------------------------------------- | |||||
139 | #if defined(__APPLE__) | |||||
140 | llvm::SmallVector<fd_set, 1> read_fdset; | |||||
141 | llvm::SmallVector<fd_set, 1> write_fdset; | |||||
142 | llvm::SmallVector<fd_set, 1> error_fdset; | |||||
143 | ||||||
144 | if (max_read_fd.hasValue()) { | |||||
145 | read_fdset.resize((nfds / FD_SETSIZE1024) + 1); | |||||
146 | read_fdset_ptr = read_fdset.data(); | |||||
147 | } | |||||
148 | if (max_write_fd.hasValue()) { | |||||
149 | write_fdset.resize((nfds / FD_SETSIZE1024) + 1); | |||||
150 | write_fdset_ptr = write_fdset.data(); | |||||
151 | } | |||||
152 | if (max_error_fd.hasValue()) { | |||||
153 | error_fdset.resize((nfds / FD_SETSIZE1024) + 1); | |||||
154 | error_fdset_ptr = error_fdset.data(); | |||||
155 | } | |||||
156 | for (auto &fd_set : read_fdset) | |||||
157 | 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); | |||||
158 | for (auto &fd_set : write_fdset) | |||||
159 | 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); | |||||
160 | for (auto &fd_set : error_fdset) | |||||
161 | 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); | |||||
162 | #else | |||||
163 | fd_set read_fdset; | |||||
164 | fd_set write_fdset; | |||||
165 | fd_set error_fdset; | |||||
166 | ||||||
167 | if (max_read_fd.hasValue()) { | |||||
168 | 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); | |||||
169 | read_fdset_ptr = &read_fdset; | |||||
170 | } | |||||
171 | if (max_write_fd.hasValue()) { | |||||
172 | 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); | |||||
173 | write_fdset_ptr = &write_fdset; | |||||
174 | } | |||||
175 | if (max_error_fd.hasValue()) { | |||||
176 | 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); | |||||
177 | error_fdset_ptr = &error_fdset; | |||||
178 | } | |||||
179 | #endif | |||||
180 | //---------------------------------------------------------------------- | |||||
181 | // Set the FD bits in the fdsets for read/write/error | |||||
182 | //---------------------------------------------------------------------- | |||||
183 | for (auto &pair : m_fd_map) { | |||||
184 | const lldb::socket_t fd = pair.first; | |||||
185 | ||||||
186 | if (pair.second.read_set) | |||||
187 | FD_SET(fd, read_fdset_ptr)((void) (((read_fdset_ptr)->fds_bits)[((fd) / (8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((fd) % (8 * (int ) sizeof (__fd_mask))))))); | |||||
188 | ||||||
189 | if (pair.second.write_set) | |||||
190 | FD_SET(fd, write_fdset_ptr)((void) (((write_fdset_ptr)->fds_bits)[((fd) / (8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((fd) % (8 * (int ) sizeof (__fd_mask))))))); | |||||
191 | ||||||
192 | if (pair.second.error_set) | |||||
193 | FD_SET(fd, error_fdset_ptr)((void) (((error_fdset_ptr)->fds_bits)[((fd) / (8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((fd) % (8 * (int ) sizeof (__fd_mask))))))); | |||||
194 | } | |||||
195 | ||||||
196 | //---------------------------------------------------------------------- | |||||
197 | // Setup our timeout time value if needed | |||||
198 | //---------------------------------------------------------------------- | |||||
199 | struct timeval *tv_ptr = nullptr; | |||||
200 | struct timeval tv = {0, 0}; | |||||
201 | ||||||
202 | while (1) { | |||||
203 | using namespace std::chrono; | |||||
204 | //------------------------------------------------------------------ | |||||
205 | // Setup out relative timeout based on the end time if we have one | |||||
206 | //------------------------------------------------------------------ | |||||
207 | if (m_end_time.hasValue()) { | |||||
208 | tv_ptr = &tv; | |||||
209 | const auto remaining_dur = duration_cast<microseconds>( | |||||
210 | m_end_time.getValue() - steady_clock::now()); | |||||
211 | if (remaining_dur.count() > 0) { | |||||
212 | // Wait for a specific amount of time | |||||
213 | const auto dur_secs = duration_cast<seconds>(remaining_dur); | |||||
214 | const auto dur_usecs = remaining_dur % seconds(1); | |||||
215 | tv.tv_sec = dur_secs.count(); | |||||
216 | tv.tv_usec = dur_usecs.count(); | |||||
217 | } else { | |||||
218 | // Just poll once with no timeout | |||||
219 | tv.tv_sec = 0; | |||||
220 | tv.tv_usec = 0; | |||||
221 | } | |||||
222 | } | |||||
223 | const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr, | |||||
224 | error_fdset_ptr, tv_ptr); | |||||
225 | if (num_set_fds < 0) { | |||||
226 | // We got an error | |||||
227 | error.SetErrorToErrno(); | |||||
228 | if (error.GetError() == EINTR4) { | |||||
229 | error.Clear(); | |||||
230 | continue; // Keep calling select if we get EINTR | |||||
231 | } else | |||||
232 | return error; | |||||
233 | } else if (num_set_fds == 0) { | |||||
234 | // Timeout | |||||
235 | error.SetError(ETIMEDOUT110, lldb::eErrorTypePOSIX); | |||||
236 | error.SetErrorString("timed out"); | |||||
237 | return error; | |||||
238 | } else { | |||||
239 | // One or more descriptors were set, update the FDInfo::select_is_set | |||||
240 | // mask so users can ask the SelectHelper class so clients can call one | |||||
241 | // of: | |||||
242 | ||||||
243 | for (auto &pair : m_fd_map) { | |||||
244 | const int fd = pair.first; | |||||
245 | ||||||
246 | if (pair.second.read_set) { | |||||
247 | if (FD_ISSET(fd, read_fdset_ptr)((((read_fdset_ptr)->fds_bits)[((fd) / (8 * (int) sizeof ( __fd_mask)))] & ((__fd_mask) (1UL << ((fd) % (8 * ( int) sizeof (__fd_mask)))))) != 0)) | |||||
248 | pair.second.read_is_set = true; | |||||
249 | } | |||||
250 | if (pair.second.write_set) { | |||||
251 | if (FD_ISSET(fd, write_fdset_ptr)((((write_fdset_ptr)->fds_bits)[((fd) / (8 * (int) sizeof ( __fd_mask)))] & ((__fd_mask) (1UL << ((fd) % (8 * ( int) sizeof (__fd_mask)))))) != 0)) | |||||
| ||||||
252 | pair.second.write_is_set = true; | |||||
253 | } | |||||
254 | if (pair.second.error_set) { | |||||
255 | if (FD_ISSET(fd, error_fdset_ptr)((((error_fdset_ptr)->fds_bits)[((fd) / (8 * (int) sizeof ( __fd_mask)))] & ((__fd_mask) (1UL << ((fd) % (8 * ( int) sizeof (__fd_mask)))))) != 0)) | |||||
256 | pair.second.error_is_set = true; | |||||
257 | } | |||||
258 | } | |||||
259 | break; | |||||
260 | } | |||||
261 | } | |||||
262 | return error; | |||||
263 | } |