Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name SelectHelper.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-eagerly-assume -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -mthread-model posix -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -momit-leaf-frame-pointer -ffunction-sections -fdata-sections -resource-dir /usr/lib/llvm-7/lib/clang/7.0.0 -D HAVE_ROUND -D LLDB_CONFIGURATION_RELEASE -D LLDB_USE_BUILTIN_DEMANGLER -D _DEBUG -D _GNU_SOURCE -D __STDC_CONSTANT_MACROS -D __STDC_FORMAT_MACROS -D __STDC_LIMIT_MACROS -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/lldb/source/Utility -I /build/llvm-toolchain-snapshot-7~svn329677/tools/lldb/source/Utility -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/lldb/include -I /build/llvm-toolchain-snapshot-7~svn329677/tools/lldb/include -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/include -I /build/llvm-toolchain-snapshot-7~svn329677/include -I /usr/include/python2.7 -I /build/llvm-toolchain-snapshot-7~svn329677/tools/clang/include -I /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/lldb/../clang/include -I /build/llvm-toolchain-snapshot-7~svn329677/tools/lldb/source/. -U NDEBUG -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/x86_64-linux-gnu/c++/7.3.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.3.0/../../../../include/c++/7.3.0/backward -internal-isystem /usr/include/clang/7.0.0/include/ -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-unused-parameter -Wwrite-strings -Wno-missing-field-initializers -Wno-long-long -Wno-maybe-uninitialized -Wno-comment -Wno-deprecated-declarations -Wno-unknown-pragmas -Wno-strict-aliasing -Wno-deprecated-register -Wno-vla-extension -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /build/llvm-toolchain-snapshot-7~svn329677/build-llvm/tools/lldb/source/Utility -ferror-limit 19 -fmessage-length 0 -fvisibility-inlines-hidden -fobjc-runtime=gcc -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -o /tmp/scan-build-2018-04-11-031539-24776-1 -x c++ /build/llvm-toolchain-snapshot-7~svn329677/tools/lldb/source/Utility/SelectHelper.cpp
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
40SelectHelper::SelectHelper()
41 : m_fd_map(), m_end_time() // Infinite timeout unless
42 // SelectHelper::SetTimeout() gets called
43{}
44
45void 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
50void SelectHelper::FDSetRead(lldb::socket_t fd) {
51 m_fd_map[fd].read_set = true;
52}
53
54void SelectHelper::FDSetWrite(lldb::socket_t fd) {
55 m_fd_map[fd].write_set = true;
56}
57
58void SelectHelper::FDSetError(lldb::socket_t fd) {
59 m_fd_map[fd].error_set = true;
60}
61
62bool 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
70bool 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
78bool 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
86static 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
94lldb_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(m_fd_map.size() <= 1024, "m_fd_map.size() <= FD_SETSIZE"
, __FUNCTION__, "/build/llvm-toolchain-snapshot-7~svn329677/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 < FD_SETSIZE)lldb_private::lldb_assert(fd < 1024, "fd < FD_SETSIZE",
__FUNCTION__, "/build/llvm-toolchain-snapshot-7~svn329677/tools/lldb/source/Utility/SelectHelper.cpp"
, 112)
;
113 if (fd >= FD_SETSIZE1024) {
1
Taking false branch
114 error.SetErrorStringWithFormat("%i is too large for select()", fd);
115 return error;
116 }
117#endif
118 if (pair.second.read_set)
2
Assuming the condition is false
3
Taking false branch
119 updateMaxFd(max_read_fd, fd);
120 if (pair.second.write_set)
4
Assuming the condition is false
5
Taking false branch
121 updateMaxFd(max_write_fd, fd);
122 if (pair.second.error_set)
6
Assuming the condition is false
7
Taking false branch
123 updateMaxFd(max_error_fd, fd);
124 updateMaxFd(max_fd, fd);
125 }
126
127 if (!max_fd.hasValue()) {
8
Taking false branch
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;
9
'write_fdset_ptr' initialized to a null pointer value
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()) {
10
Taking false branch
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()) {
11
Taking false branch
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()) {
12
Taking false branch
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)
13
Assuming the condition is false
14
Taking false branch
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)
15
Assuming the condition is true
16
Taking true branch
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)))))))
;
17
Within the expansion of the macro 'FD_SET':
a
Array access (via field 'fds_bits') results in a null pointer dereference
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 mask
240 // so users can ask the SelectHelper class so clients can call one of:
241
242 for (auto &pair : m_fd_map) {
243 const int fd = pair.first;
244
245 if (pair.second.read_set) {
246 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)
)
247 pair.second.read_is_set = true;
248 }
249 if (pair.second.write_set) {
250 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)
)
251 pair.second.write_is_set = true;
252 }
253 if (pair.second.error_set) {
254 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)
)
255 pair.second.error_is_set = true;
256 }
257 }
258 break;
259 }
260 }
261 return error;
262}