Bug Summary

File:tools/lldb/source/Utility/SelectHelper.cpp
Warning:line 249, column 15
Array access (via field 'fds_bits') results in a null pointer dereference

Annotated Source Code

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/select.h>
36#endif
37
38
39SelectHelper::SelectHelper()
40 : m_fd_map(), m_end_time() // Infinite timeout unless
41 // SelectHelper::SetTimeout() gets called
42{}
43
44void 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
49void SelectHelper::FDSetRead(lldb::socket_t fd) {
50 m_fd_map[fd].read_set = true;
51}
52
53void SelectHelper::FDSetWrite(lldb::socket_t fd) {
54 m_fd_map[fd].write_set = true;
55}
56
57void SelectHelper::FDSetError(lldb::socket_t fd) {
58 m_fd_map[fd].error_set = true;
59}
60
61bool 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
69bool 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
77bool 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
85static void updateMaxFd(llvm::Optional<lldb::socket_t> &vold,
86 lldb::socket_t vnew) {
87 if (!vold.hasValue())
88 vold = vnew;
89 else
90 vold = std::max(*vold, vnew);
91}
92
93lldb_private::Status SelectHelper::Select() {
94 lldb_private::Status error;
95#ifdef _MSC_VER
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(m_fd_map.size() <= 1024, "m_fd_map.size() <= FD_SETSIZE"
, __FUNCTION__, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/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 llvm::Optional<lldb::socket_t> max_read_fd;
104 llvm::Optional<lldb::socket_t> max_write_fd;
105 llvm::Optional<lldb::socket_t> max_error_fd;
106 llvm::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(_MSC_VER)
111 lldbassert(fd < FD_SETSIZE)lldb_private::lldb_assert(fd < 1024, "fd < FD_SETSIZE",
__FUNCTION__, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/lldb/source/Utility/SelectHelper.cpp"
, 111)
;
112 if (fd >= FD_SETSIZE1024) {
1
Taking false branch
113 error.SetErrorStringWithFormat("%i is too large for select()", fd);
114 return error;
115 }
116#endif
117 if (pair.second.read_set)
2
Assuming the condition is false
3
Taking false branch
118 updateMaxFd(max_read_fd, fd);
119 if (pair.second.write_set)
4
Assuming the condition is false
5
Taking false branch
120 updateMaxFd(max_write_fd, fd);
121 if (pair.second.error_set)
6
Assuming the condition is false
7
Taking false branch
122 updateMaxFd(max_error_fd, fd);
123 updateMaxFd(max_fd, fd);
124 }
125
126 if (!max_fd.hasValue()) {
8
Taking false branch
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;
9
'write_fdset_ptr' initialized to a null pointer value
134 fd_set *error_fdset_ptr = nullptr;
135//----------------------------------------------------------------------
136// Initialize and zero out the fdsets
137//----------------------------------------------------------------------
138#if defined(__APPLE__)
139 llvm::SmallVector<fd_set, 1> read_fdset;
140 llvm::SmallVector<fd_set, 1> write_fdset;
141 llvm::SmallVector<fd_set, 1> error_fdset;
142
143 if (max_read_fd.hasValue()) {
144 read_fdset.resize((nfds / FD_SETSIZE1024) + 1);
145 read_fdset_ptr = read_fdset.data();
146 }
147 if (max_write_fd.hasValue()) {
148 write_fdset.resize((nfds / FD_SETSIZE1024) + 1);
149 write_fdset_ptr = write_fdset.data();
150 }
151 if (max_error_fd.hasValue()) {
152 error_fdset.resize((nfds / FD_SETSIZE1024) + 1);
153 error_fdset_ptr = error_fdset.data();
154 }
155 for (auto &fd_set : read_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 : write_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 for (auto &fd_set : error_fdset)
160 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)
;
161#else
162 fd_set read_fdset;
163 fd_set write_fdset;
164 fd_set error_fdset;
165
166 if (max_read_fd.hasValue()) {
10
Taking false branch
167 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)
;
168 read_fdset_ptr = &read_fdset;
169 }
170 if (max_write_fd.hasValue()) {
11
Taking false branch
171 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)
;
172 write_fdset_ptr = &write_fdset;
173 }
174 if (max_error_fd.hasValue()) {
12
Taking false branch
175 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)
;
176 error_fdset_ptr = &error_fdset;
177 }
178#endif
179 //----------------------------------------------------------------------
180 // Set the FD bits in the fdsets for read/write/error
181 //----------------------------------------------------------------------
182 for (auto &pair : m_fd_map) {
183 const lldb::socket_t fd = pair.first;
184
185 if (pair.second.read_set)
186 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)))))))
;
187
188 if (pair.second.write_set)
189 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)))))))
;
190
191 if (pair.second.error_set)
192 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)))))))
;
193 }
194
195 //----------------------------------------------------------------------
196 // Setup our timeout time value if needed
197 //----------------------------------------------------------------------
198 struct timeval *tv_ptr = nullptr;
199 struct timeval tv = {0, 0};
200
201 while (1) {
13
Loop condition is true. Entering loop body
202 using namespace std::chrono;
203 //------------------------------------------------------------------
204 // Setup out relative timeout based on the end time if we have one
205 //------------------------------------------------------------------
206 if (m_end_time.hasValue()) {
14
Assuming the condition is false
15
Taking false branch
207 tv_ptr = &tv;
208 const auto remaining_dur = duration_cast<microseconds>(
209 m_end_time.getValue() - steady_clock::now());
210 if (remaining_dur.count() > 0) {
211 // Wait for a specific amount of time
212 const auto dur_secs = duration_cast<seconds>(remaining_dur);
213 const auto dur_usecs = remaining_dur % seconds(1);
214 tv.tv_sec = dur_secs.count();
215 tv.tv_usec = dur_usecs.count();
216 } else {
217 // Just poll once with no timeout
218 tv.tv_sec = 0;
219 tv.tv_usec = 0;
220 }
221 }
222 const int num_set_fds = ::select(nfds, read_fdset_ptr, write_fdset_ptr,
223 error_fdset_ptr, tv_ptr);
224 if (num_set_fds < 0) {
16
Assuming 'num_set_fds' is >= 0
17
Taking false branch
225 // We got an error
226 error.SetErrorToErrno();
227 if (error.GetError() == EINTR4) {
228 error.Clear();
229 continue; // Keep calling select if we get EINTR
230 } else
231 return error;
232 } else if (num_set_fds == 0) {
18
Assuming 'num_set_fds' is not equal to 0
19
Taking false branch
233 // Timeout
234 error.SetError(ETIMEDOUT110, lldb::eErrorTypePOSIX);
235 error.SetErrorString("timed out");
236 return error;
237 } else {
238 // One or more descriptors were set, update the FDInfo::select_is_set mask
239 // so users can ask the SelectHelper class so clients can call one of:
240
241 for (auto &pair : m_fd_map) {
242 const int fd = pair.first;
243
244 if (pair.second.read_set) {
20
Assuming the condition is false
21
Taking false branch
245 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)
)
246 pair.second.read_is_set = true;
247 }
248 if (pair.second.write_set) {
22
Assuming the condition is true
23
Taking true branch
249 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)
)
24
Within the expansion of the macro 'FD_ISSET':
a
Array access (via field 'fds_bits') results in a null pointer dereference
250 pair.second.write_is_set = true;
251 }
252 if (pair.second.error_set) {
253 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)
)
254 pair.second.error_is_set = true;
255 }
256 }
257 break;
258 }
259 }
260 return error;
261}