Bug Summary

File:su/su_select_port.c
Warning:line 600, column 11
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 su_select_port.c -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=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 -mdisable-fp-elim -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/llvm-7/lib/clang/7.0.1 -D HAVE_CONFIG_H -I . -I ../.. -I ../../libsofia-sip-ua/su/sofia-sip -D SU_DEBUG=0 -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-7/lib/clang/7.0.1/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /drone/src/libsofia-sip-ua/su -ferror-limit 19 -fmessage-length 0 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /drone/src/scan-build/2021-08-26-202507-364-1 -x c su_select_port.c -faddrsig
1/*
2 * This file is part of the Sofia-SIP package
3 *
4 * Copyright (C) 2005 Nokia Corporation.
5 *
6 * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 2.1 of
11 * the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25/**@ingroup su_wait
26 * @CFILE su_select_port.c
27 *
28 * Port implementation using select().
29 *
30 * @author Pekka Pessi <Pekka.Pessi@nokia.com>
31 * @author Kai Vehmanen <kai.vehmanen@nokia.com>
32 *
33 * @date Created: Fri Jan 26 17:56:34 2007 ppessi
34 */
35
36#include "config.h"
37
38#if HAVE_SELECT1
39
40#define su_port_ssu_select_port_s su_select_port_s
41
42#include "sofia-sip/su.h"
43#include "su_port.h"
44#include "sofia-sip/su_alloc.h"
45
46#include <stdlib.h>
47#include <assert.h>
48#include <stdarg.h>
49#include <stdio.h>
50#include <string.h>
51#include <limits.h>
52#include <errno(*__errno_location ()).h>
53
54#if HAVE_WIN32
55#error winsock select() not supported yet
56#else
57#if HAVE_SYS_SELECT_H1
58#include <sys/select.h>
59#elif HAVE_SYS_TIME_H1
60#include <sys/time.h>
61#endif
62
63#include <sys/types.h>
64#include <unistd.h>
65
66#ifndef __NFDBITS(8 * (int) sizeof (__fd_mask))
67#define __NFDBITS(8 * (int) sizeof (__fd_mask)) (8 * sizeof (long int))
68#endif
69
70#undef FDSETSIZE
71/* Size of fd set in bytes */
72#define FDSETSIZE(n)(((n) + (8 * (int) sizeof (__fd_mask)) - 1) / (8 * (int) sizeof
(__fd_mask)) * ((8 * (int) sizeof (__fd_mask)) / 8))
(((n) + __NFDBITS(8 * (int) sizeof (__fd_mask)) - 1) / __NFDBITS(8 * (int) sizeof (__fd_mask)) * (__NFDBITS(8 * (int) sizeof (__fd_mask)) / 8))
73#endif
74
75/** Port based on select(). */
76
77struct su_select_port_s {
78 su_socket_port_t sup_base[1];
79
80#define sup_homesup_base->sup_base->sup_base->sup_home sup_base->sup_base->sup_base->sup_homesup_base->sup_base->sup_base->sup_home
81
82 /** epoll fd */
83 int sup_epoll;
84 unsigned sup_multishot; /**< Multishot operation? */
85
86 unsigned sup_registers; /** Counter incremented by
87 su_port_register() or
88 su_port_unregister()
89 */
90 int sup_n_registrations;
91 int sup_max_index; /**< Indexes are equal or smaller than this */
92 int sup_size_indices; /**< Size of allocated index table */
93
94 /** Structure containing registration data */
95 struct su_select_register {
96 struct su_select_register *ser_next; /* Next in free list */
97 su_wakeup_f ser_cb;
98 su_wakeup_arg_t*ser_arg;
99 su_root_t *ser_root;
100 int ser_id; /** registration identifier */
101 su_wait_t ser_wait[1];
102 } **sup_indices;
103
104 int sup_maxfd, sup_allocfd;
105
106 fd_set *sup_readfds, *sup_readfds2;
107 fd_set *sup_writefds, *sup_writefds2;
108};
109
110static void su_select_port_decref(su_port_t *self,
111 int blocking,
112 char const *who);
113static int su_select_port_register(su_port_t *self,
114 su_root_t *root,
115 su_wait_t *wait,
116 su_wakeup_f callback,
117 su_wakeup_arg_t *arg,
118 int priority);
119static int su_select_port_unregister(su_port_t *port,
120 su_root_t *root,
121 su_wait_t *wait,
122 su_wakeup_f callback,
123 su_wakeup_arg_t *arg);
124static int su_select_port_deregister(su_port_t *self, int i);
125static int su_select_port_unregister_all(su_port_t *self, su_root_t *root);
126static int su_select_port_eventmask(su_port_t *self,
127 int index,
128 int socket,
129 int events);
130static int su_select_port_multishot(su_port_t *self, int multishot);
131static int su_select_port_wait_events(su_port_t *self, su_duration_t tout);
132static char const *su_select_port_name(su_port_t const *self);
133
134su_port_vtable_t const su_select_port_vtable[1] =
135 {{
136 /* su_vtable_size: */ sizeof su_select_port_vtable,
137 su_pthread_port_lock,
138 su_pthread_port_unlock,
139 su_base_port_incref,
140 su_select_port_decref,
141 su_base_port_gsource,
142 su_base_port_send,
143 su_select_port_register,
144 su_select_port_unregister,
145 su_select_port_deregister,
146 su_select_port_unregister_all,
147 su_select_port_eventmask,
148 su_base_port_run,
149 su_base_port_break,
150 su_base_port_step,
151 su_pthread_port_thread,
152 su_base_port_add_prepoll,
153 su_base_port_remove_prepoll,
154 su_base_port_timers,
155 su_select_port_multishot,
156 su_select_port_wait_events,
157 su_base_port_getmsgs,
158 su_base_port_getmsgs_from,
159 su_select_port_name,
160 su_base_port_start_shared,
161 su_pthread_port_wait,
162 su_pthread_port_execute,
163 su_base_port_deferrable,
164 su_base_port_max_defer,
165 su_socket_port_wakeup,
166 su_base_port_is_running,
167 }};
168
169static char const *su_select_port_name(su_port_t const *self)
170{
171 return "select";
172}
173
174static void su_select_port_decref(su_port_t *self, int blocking, char const *who)
175{
176 (void)su_base_port_decref(self, blocking, who);
177}
178
179static void su_select_port_deinit(void *arg)
180{
181 su_port_t *self = arg;
182
183 SU_DEBUG_9(("%s(%p) called\n", "su_select_port_deinit", (void *)self))((((su_log_global) != ((void*)0) && (su_log_global)->
log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) &&
(su_log_global)->log_init > 1) ? (su_log_global)->log_level
: su_log_default->log_level)) >= 9 ? (_su_llog((su_log_global
), 9, "su_select_port.c", (const char *)__func__, 183, "%s(%p) called\n"
, "su_select_port_deinit", (void *)self)) : (void)0)
;
184
185 su_socket_port_deinit(self->sup_base);
186}
187
188/** @internal
189 *
190 * Register a #su_wait_t object. The wait object, a callback function and
191 * an argument pointer is stored in the port object. The callback function
192 * will be called when the wait object is signaled.
193 *
194 * Please note if identical wait objects are inserted, only first one is
195 * ever signalled.
196 *
197 * @param self pointer to port
198 * @param root pointer to root object
199 * @param waits pointer to wait object
200 * @param callback callback function pointer
201 * @param arg argument given to callback function when it is invoked
202 * @param priority relative priority of the wait object
203 * (0 is normal, 1 important, 2 realtime)
204 *
205 * @return
206 * Positive index of the wait object,
207 * or -1 upon an error.
208 */
209int su_select_port_register(su_port_t *self,
210 su_root_t *root,
211 su_wait_t *wait,
212 su_wakeup_f callback,
213 su_wakeup_arg_t *arg,
214 int priority)
215{
216 int i, j, n;
217 struct su_select_register *ser;
218 struct su_select_register **indices = self->sup_indices;
219 int allocfd = self->sup_allocfd;
220 fd_set *readfds = self->sup_readfds, *readfds2 = self->sup_readfds2;
221 fd_set *writefds = self->sup_writefds, *writefds2 = self->sup_writefds2;
222
223 assert(su_port_own_thread(self))((void) sizeof ((su_port_own_thread(self)) ? 1 : 0), __extension__
({ if (su_port_own_thread(self)) ; else __assert_fail ("su_port_own_thread(self)"
, "su_select_port.c", 223, __extension__ __PRETTY_FUNCTION__)
; }))
;
224
225 n = self->sup_size_indices;
226
227 if (n >= SU_WAIT_MAX(0x7fffffff))
228 return su_seterrno(ENOMEM12);
229
230 self->sup_registers++;
231
232 if (wait->fd >= allocfd)
233 allocfd += __NFDBITS(8 * (int) sizeof (__fd_mask)); /* long at a time */
234
235 if (allocfd >= self->sup_allocfd) {
236 size_t bytes = FDSETSIZE(allocfd)(((allocfd) + (8 * (int) sizeof (__fd_mask)) - 1) / (8 * (int
) sizeof (__fd_mask)) * ((8 * (int) sizeof (__fd_mask)) / 8))
;
237 size_t bytes0 = FDSETSIZE(self->sup_allocfd)(((self->sup_allocfd) + (8 * (int) sizeof (__fd_mask)) - 1
) / (8 * (int) sizeof (__fd_mask)) * ((8 * (int) sizeof (__fd_mask
)) / 8))
;
238 /* (Re)allocate fd_sets */
239
240 readfds = su_realloc(self->sup_homesup_base->sup_base->sup_base->sup_home, readfds, bytes);
241 if (readfds) self->sup_readfds = readfds;
242 readfds2 = su_realloc(self->sup_homesup_base->sup_base->sup_base->sup_home, readfds2, bytes);
243 if (readfds2) self->sup_readfds2 = readfds2;
244 if (!readfds || !readfds2)
245 return -1;
246
247 writefds = su_realloc(self->sup_homesup_base->sup_base->sup_base->sup_home, writefds, bytes);
248 if (writefds) self->sup_writefds = writefds;
249 writefds2 = su_realloc(self->sup_homesup_base->sup_base->sup_base->sup_home, writefds2, bytes);
250 if (writefds2) self->sup_writefds2 = writefds2;
251 if (!writefds || !writefds2)
252 return -1;
253
254 memset((char *)readfds + bytes0, 0, bytes - bytes0);
255 memset((char *)writefds + bytes0, 0, bytes - bytes0);
256
257 self->sup_allocfd = allocfd;
258 }
259
260 ser = indices[0];
261
262 if (!ser) {
263 su_home_t *h = su_port_home(self);
264
265 i = self->sup_max_index, j = i == 0 ? 15 : i + 16;
266
267 if (j >= self->sup_size_indices) {
268 /* Reallocate index table */
269 n = n < 1024 ? 2 * n : n + 1024;
270 indices = su_realloc(h, indices, n * sizeof(indices[0]));
271 if (!indices)
272 return -1;
273 self->sup_indices = indices;
274 self->sup_size_indices = n;
275 }
276
277 /* Allocate registrations */
278 ser = su_zalloc(h, (j - i) * (sizeof *ser));
279 if (!ser)
280 return -1;
281
282 indices[0] = ser;
283
284 for (i++; i <= j; i++) {
285 ser->ser_id = i;
286 ser->ser_next = i < j ? ser + 1 : NULL((void*)0);
287 indices[i] = ser++;
288 }
289
290 self->sup_max_index = j;
291
292 ser = indices[0];
293 }
294
295 i = ser->ser_id;
296
297 indices[0] = ser->ser_next;
298
299 ser->ser_next = NULL((void*)0);
300 *ser->ser_wait = *wait;
301 ser->ser_cb = callback;
302 ser->ser_arg = arg;
303 ser->ser_root = root;
304
305 if (wait->events & SU_WAIT_IN(0x001))
306 FD_SET(wait->fd, readfds)((void) (((readfds)->fds_bits)[((wait->fd) / (8 * (int)
sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((wait->
fd) % (8 * (int) sizeof (__fd_mask)))))))
;
307 if (wait->events & SU_WAIT_OUT(0x004))
308 FD_SET(wait->fd, writefds)((void) (((writefds)->fds_bits)[((wait->fd) / (8 * (int
) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << ((wait->
fd) % (8 * (int) sizeof (__fd_mask)))))))
;
309
310 if (wait->fd >= self->sup_maxfd)
311 self->sup_maxfd = wait->fd + 1;
312
313 self->sup_n_registrations++;
314
315 return i; /* return index */
316}
317
318static void su_select_port_update_maxfd(su_port_t *self)
319{
320 int i;
321 su_socket_t maxfd = 0;
322
323 for (i = 1; i <= self->sup_max_index; i++) {
324 if (!self->sup_indices[i]->ser_cb)
325 continue;
326 if (maxfd <= self->sup_indices[i]->ser_wait->fd)
327 maxfd = self->sup_indices[i]->ser_wait->fd + 1;
328 }
329
330 self->sup_maxfd = maxfd;
331}
332
333/** Deregister a su_wait_t object. */
334static int su_select_port_deregister0(su_port_t *self, int i, int destroy_wait)
335{
336 struct su_select_register **indices = self->sup_indices;
337 struct su_select_register *ser;
338
339 ser = self->sup_indices[i];
340 if (ser == NULL((void*)0) || ser->ser_cb == NULL((void*)0)) {
341 su_seterrno(ENOENT2);
342 return -1;
343 }
344
345 assert(ser->ser_id == i)((void) sizeof ((ser->ser_id == i) ? 1 : 0), __extension__
({ if (ser->ser_id == i) ; else __assert_fail ("ser->ser_id == i"
, "su_select_port.c", 345, __extension__ __PRETTY_FUNCTION__)
; }))
;
346
347 FD_CLR(ser->ser_wait->fd, self->sup_readfds)((void) (((self->sup_readfds)->fds_bits)[((ser->ser_wait
->fd) / (8 * (int) sizeof (__fd_mask)))] &= ~((__fd_mask
) (1UL << ((ser->ser_wait->fd) % (8 * (int) sizeof
(__fd_mask)))))))
;
348 FD_CLR(ser->ser_wait->fd, self->sup_writefds)((void) (((self->sup_writefds)->fds_bits)[((ser->ser_wait
->fd) / (8 * (int) sizeof (__fd_mask)))] &= ~((__fd_mask
) (1UL << ((ser->ser_wait->fd) % (8 * (int) sizeof
(__fd_mask)))))))
;
349
350 if (ser->ser_wait->fd + 1 >= self->sup_maxfd)
351 self->sup_maxfd = 0;
352
353 memset(ser, 0, sizeof *ser);
354 ser->ser_id = i;
355 ser->ser_next = indices[0], indices[0] = ser;
356
357 self->sup_n_registrations--;
358 self->sup_registers++;
359
360 return i;
361}
362
363
364/** Unregister a su_wait_t object.
365 *
366 * The function su_select_port_unregister() unregisters a su_wait_t object.
367 * The registration defined by the wait object, the callback function and
368 * the argument pointer are removed from the port object.
369 *
370 * @param self - pointer to port object
371 * @param root - pointer to root object
372 * @param wait - pointer to wait object
373 * @param callback - callback function pointer (may be NULL)
374 * @param arg - argument given to callback function when it is invoked
375 * (may be NULL)
376 *
377 * @deprecated Use su_select_port_deregister() instead.
378 *
379 * @return Nonzero index of the wait object, or -1 upon an error.
380 */
381int su_select_port_unregister(su_port_t *self,
382 su_root_t *root,
383 su_wait_t *wait,
384 su_wakeup_f callback, /* XXX - ignored */
385 su_wakeup_arg_t *arg)
386{
387 int i, I;
388
389 struct su_select_register *ser;
390
391 assert(self)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ;
else __assert_fail ("self", "su_select_port.c", 391, __extension__
__PRETTY_FUNCTION__); }))
;
392 assert(su_port_own_thread(self))((void) sizeof ((su_port_own_thread(self)) ? 1 : 0), __extension__
({ if (su_port_own_thread(self)) ; else __assert_fail ("su_port_own_thread(self)"
, "su_select_port.c", 392, __extension__ __PRETTY_FUNCTION__)
; }))
;
393
394 I = self->sup_max_index;
395
396 for (i = 1; i <= I; i++) {
397 ser = self->sup_indices[i];
398
399 if (ser->ser_cb &&
400 arg == ser->ser_arg &&
401 SU_WAIT_CMP(wait[0], ser->ser_wait[0])(((wait[0]).fd - (ser->ser_wait[0]).fd) ? ((wait[0]).fd - (
ser->ser_wait[0]).fd) : ((wait[0]).events - (ser->ser_wait
[0]).events))
== 0)
402 return su_select_port_deregister0(self, ser->ser_id, 0);
403 }
404
405 su_seterrno(ENOENT2);
406
407 return -1;
408}
409
410/** Deregister a su_wait_t object.
411 *
412 * Deregisters a registration by index. The wait object, a callback
413 * function and a argument are removed from the port object. The wait
414 * object is destroyed.
415 *
416 * @param self - pointer to port object
417 * @param i - registration index
418 *
419 * @return Index of the wait object, or -1 upon an error.
420 */
421int su_select_port_deregister(su_port_t *self, int i)
422{
423 struct su_select_register *ser;
424
425 if (i <= 0 || i > self->sup_max_index)
426 return su_seterrno(EBADF9);
427
428 ser = self->sup_indices[i];
429 if (!ser->ser_cb)
430 return su_seterrno(EBADF9);
431
432 return su_select_port_deregister0(self, i, 1);
433}
434
435
436/** @internal
437 * Unregister all su_wait_t objects of given su_root_t instance.
438 *
439 * The function su_select_port_unregister_all() unregisters all su_wait_t
440 * objects associated with given root object.
441 *
442 * @param self - pointer to port object
443 * @param root - pointer to root object
444 *
445 * @return Number of wait objects removed.
446 */
447int su_select_port_unregister_all(su_port_t *self, su_root_t *root)
448{
449 int i, I, n;
450
451 struct su_select_register *ser;
452
453 assert(self)((void) sizeof ((self) ? 1 : 0), __extension__ ({ if (self) ;
else __assert_fail ("self", "su_select_port.c", 453, __extension__
__PRETTY_FUNCTION__); }))
; assert(root)((void) sizeof ((root) ? 1 : 0), __extension__ ({ if (root) ;
else __assert_fail ("root", "su_select_port.c", 453, __extension__
__PRETTY_FUNCTION__); }))
;
454 assert(su_port_own_thread(self))((void) sizeof ((su_port_own_thread(self)) ? 1 : 0), __extension__
({ if (su_port_own_thread(self)) ; else __assert_fail ("su_port_own_thread(self)"
, "su_select_port.c", 454, __extension__ __PRETTY_FUNCTION__)
; }))
;
455
456 I = self->sup_max_index;
457
458 for (i = 1, n = 0; i <= I; i++) {
459 ser = self->sup_indices[i];
460 if (ser->ser_root != root)
461 continue;
462 su_select_port_deregister0(self, ser->ser_id, 0);
463 n++;
464 }
465
466 return n;
467}
468
469/**Set mask for a registered event. @internal
470 *
471 * The function su_select_port_eventmask() sets the mask describing events
472 * that can signal the registered callback.
473 *
474 * @param port pointer to port object
475 * @param index registration index
476 * @param socket socket
477 * @param events new event mask
478 *
479 * @retval 0 when successful,
480 * @retval -1 upon an error.
481 */
482int su_select_port_eventmask(su_port_t *self,
483 int index,
484 int socket, int events)
485{
486 struct su_select_register *ser;
487
488 if (index <= 0 || index > self->sup_max_index)
489 return su_seterrno(EBADF9);
490
491 ser = self->sup_indices[index];
492 if (!ser->ser_cb)
493 return su_seterrno(EBADF9);
494
495 if (self->sup_maxfd == 0)
496 su_select_port_update_maxfd(self);
497
498 if (socket >= self->sup_maxfd)
499 return su_seterrno(EBADF9);
500
501 if (su_wait_mask(ser->ser_wait, socket, events) < 0)
502 return -1;
503
504 assert(socket < self->sup_maxfd)((void) sizeof ((socket < self->sup_maxfd) ? 1 : 0), __extension__
({ if (socket < self->sup_maxfd) ; else __assert_fail (
"socket < self->sup_maxfd", "su_select_port.c", 504, __extension__
__PRETTY_FUNCTION__); }))
;
505
506 if (events & SU_WAIT_IN(0x001))
507 FD_SET(socket, self->sup_readfds)((void) (((self->sup_readfds)->fds_bits)[((socket) / (8
* (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL << (
(socket) % (8 * (int) sizeof (__fd_mask)))))))
;
508 else
509 FD_CLR(socket, self->sup_readfds)((void) (((self->sup_readfds)->fds_bits)[((socket) / (8
* (int) sizeof (__fd_mask)))] &= ~((__fd_mask) (1UL <<
((socket) % (8 * (int) sizeof (__fd_mask)))))))
;
510
511 if (events & SU_WAIT_OUT(0x004))
512 FD_SET(socket, self->sup_writefds)((void) (((self->sup_writefds)->fds_bits)[((socket) / (
8 * (int) sizeof (__fd_mask)))] |= ((__fd_mask) (1UL <<
((socket) % (8 * (int) sizeof (__fd_mask)))))))
;
513 else
514 FD_CLR(socket, self->sup_writefds)((void) (((self->sup_writefds)->fds_bits)[((socket) / (
8 * (int) sizeof (__fd_mask)))] &= ~((__fd_mask) (1UL <<
((socket) % (8 * (int) sizeof (__fd_mask)))))))
;
515
516 return 0;
517}
518
519/** @internal Enable multishot mode.
520 *
521 * Enables, disables or queries the multishot mode for the port. The
522 * multishot mode determines how the events are scheduled by port. If
523 * multishot mode is enabled, port serves all the sockets that have received
524 * network events. If it is disabled, only first socket event is served.
525 *
526 * @param self pointer to port object
527 * @param multishot multishot mode (0 => disables, 1 => enables, -1 => query)
528 *
529 * @retval 0 multishot mode is disabled
530 * @retval 1 multishot mode is enabled
531 * @retval -1 an error occurred
532 */
533static
534int su_select_port_multishot(su_port_t *self, int multishot)
535{
536 if (multishot < 0)
537 return self->sup_multishot;
538 else if (multishot == 0 || multishot == 1)
539 return self->sup_multishot = multishot;
540 else
541 return (errno(*__errno_location ()) = EINVAL22), -1;
542}
543
544
545/** @internal
546 * Wait (poll()) for wait objects in port.
547 *
548 * @param self pointer to port
549 * @param tout timeout in milliseconds
550 *
551 * @return number of events handled
552 */
553static
554int su_select_port_wait_events(su_port_t *self, su_duration_t tout)
555{
556 int j, n, events = 0;
557 unsigned version = self->sup_registers;
558 size_t bytes;
559 struct timeval tv;
560 fd_set *rset = NULL((void*)0), *wset = NULL((void*)0);
1
'wset' initialized to a null pointer value
561
562 if (self->sup_maxfd == 0)
2
Assuming the condition is false
3
Taking false branch
563 su_select_port_update_maxfd(self);
564
565 bytes = FDSETSIZE(self->sup_maxfd)(((self->sup_maxfd) + (8 * (int) sizeof (__fd_mask)) - 1) /
(8 * (int) sizeof (__fd_mask)) * ((8 * (int) sizeof (__fd_mask
)) / 8))
;
566
567 if (bytes) {
4
Assuming 'bytes' is 0
5
Taking false branch
568 rset = memcpy(self->sup_readfds2, self->sup_readfds, bytes);
569 wset = memcpy(self->sup_writefds2, self->sup_writefds, bytes);
570 }
571
572 tv.tv_sec = tout / 1000;
573 tv.tv_usec = (tout % 1000) * 1000;
574
575 n = select(self->sup_maxfd, rset, wset, NULL((void*)0), &tv);
576
577 if (n < 0) {
6
Assuming 'n' is >= 0
7
Taking false branch
578 SU_DEBUG_0(("su_select_port_wait_events(%p): %s (%d)\n",((((su_log_global) != ((void*)0) && (su_log_global)->
log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) &&
(su_log_global)->log_init > 1) ? (su_log_global)->log_level
: su_log_default->log_level)) >= 0 ? (_su_llog((su_log_global
), 0, "su_select_port.c", (const char *)__func__, 579, "su_select_port_wait_events(%p): %s (%d)\n"
, (void *)self, su_strerror(su_errno()), su_errno())) : (void
)0)
579 (void *)self, su_strerror(su_errno()), su_errno()))((((su_log_global) != ((void*)0) && (su_log_global)->
log_init) == 0 ? 9 : (((su_log_global) != ((void*)0) &&
(su_log_global)->log_init > 1) ? (su_log_global)->log_level
: su_log_default->log_level)) >= 0 ? (_su_llog((su_log_global
), 0, "su_select_port.c", (const char *)__func__, 579, "su_select_port_wait_events(%p): %s (%d)\n"
, (void *)self, su_strerror(su_errno()), su_errno())) : (void
)0)
;
580 return 0;
581 }
582 else if (n == 0)
8
Assuming 'n' is not equal to 0
9
Taking false branch
583 return 0;
584
585 for (j = 1; j <= self->sup_max_index; j++) {
10
Assuming the condition is true
11
Loop condition is true. Entering loop body
586 struct su_select_register *ser;
587 su_root_magic_t *magic;
588 int fd;
589
590 ser = self->sup_indices[j];
591 if (!ser->ser_cb)
12
Assuming the condition is false
13
Taking false branch
592 continue;
593
594 fd = ser->ser_wait->fd;
595 ser->ser_wait->revents = 0;
596
597 if (ser->ser_wait->events & SU_WAIT_IN(0x001))
14
Assuming the condition is false
15
Taking false branch
598 if (FD_ISSET(fd, rset)((((rset)->fds_bits)[((fd) / (8 * (int) sizeof (__fd_mask)
))] & ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof
(__fd_mask)))))) != 0)
) ser->ser_wait->revents |= SU_WAIT_IN(0x001), n--;
599 if (ser->ser_wait->events & SU_WAIT_OUT(0x004))
16
Assuming the condition is true
17
Taking true branch
600 if (FD_ISSET(fd, wset)((((wset)->fds_bits)[((fd) / (8 * (int) sizeof (__fd_mask)
))] & ((__fd_mask) (1UL << ((fd) % (8 * (int) sizeof
(__fd_mask)))))) != 0)
) ser->ser_wait->revents |= SU_WAIT_OUT(0x004), n--;
18
Within the expansion of the macro 'FD_ISSET':
a
Array access (via field 'fds_bits') results in a null pointer dereference
601
602 if (ser->ser_wait->revents) {
603 magic = ser->ser_root ? su_root_magic(ser->ser_root) : NULL((void*)0);
604 ser->ser_cb(magic, ser->ser_wait, ser->ser_arg);
605 events++;
606 if (version != self->sup_registers)
607 /* Callback function used su_register()/su_deregister() */
608 return events;
609 if (!self->sup_multishot)
610 /* Callback function used su_register()/su_deregister() */
611 return events;
612 }
613
614 if (n == 0)
615 break;
616 }
617
618 assert(n == 0)((void) sizeof ((n == 0) ? 1 : 0), __extension__ ({ if (n == 0
) ; else __assert_fail ("n == 0", "su_select_port.c", 618, __extension__
__PRETTY_FUNCTION__); }))
;
619
620 return events;
621}
622
623/** Create a port using epoll() or poll().
624 */
625su_port_t *su_select_port_create(void)
626{
627 su_port_t *self;
628
629 self = su_home_new(sizeof *self);
630 if (!self)
631 return NULL((void*)0);
632
633 if (su_home_destructor(su_port_home(self), su_select_port_deinit) < 0 ||
634 !(self->sup_indices =
635 su_zalloc(su_port_home(self),
636 (sizeof self->sup_indices[0]) *
637 (self->sup_size_indices = __NFDBITS(8 * (int) sizeof (__fd_mask)))))) {
638 su_home_unref(su_port_home(self));
639 return NULL((void*)0);
640 }
641
642 self->sup_multishot = SU_ENABLE_MULTISHOT_POLL1;
643
644 if (su_socket_port_init(self->sup_base, su_select_port_vtable) < 0)
645 return su_home_unref(su_port_home(self)), NULL((void*)0);
646
647 return self;
648}
649
650int su_select_clone_start(su_root_t *parent,
651 su_clone_r return_clone,
652 su_root_magic_t *magic,
653 su_root_init_f init,
654 su_root_deinit_f deinit)
655{
656 return su_pthreaded_port_start(su_select_port_create,
657 parent, return_clone, magic, init, deinit);
658}
659
660
661#endif