| File: | os/unix/ngx_readv_chain.c |
| Location: | line 71, column 26 |
| Description: | Access to field 'iov_len' results in a dereference of a null pointer (loaded from variable 'iov') |
| 1 | ||||
| 2 | /* | |||
| 3 | * Copyright (C) Igor Sysoev | |||
| 4 | * Copyright (C) Nginx, Inc. | |||
| 5 | */ | |||
| 6 | ||||
| 7 | ||||
| 8 | #include <ngx_config.h> | |||
| 9 | #include <ngx_core.h> | |||
| 10 | #include <ngx_event.h> | |||
| 11 | ||||
| 12 | ||||
| 13 | #define NGX_IOVS16 16 | |||
| 14 | ||||
| 15 | ||||
| 16 | #if (NGX_HAVE_KQUEUE1) | |||
| 17 | ||||
| 18 | ssize_t | |||
| 19 | ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) | |||
| 20 | { | |||
| 21 | u_char *prev; | |||
| 22 | ssize_t n, size; | |||
| 23 | ngx_err_t err; | |||
| 24 | ngx_array_t vec; | |||
| 25 | ngx_event_t *rev; | |||
| 26 | struct iovec *iov, iovs[NGX_IOVS16]; | |||
| 27 | ||||
| 28 | rev = c->read; | |||
| 29 | ||||
| 30 | if (ngx_event_flags & NGX_USE_KQUEUE_EVENT0x00000008) { | |||
| ||||
| 31 | ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0, | |||
| 32 | "readv: eof:%d, avail:%d, err:%d", | |||
| 33 | rev->pending_eof, rev->available, rev->kq_errno); | |||
| 34 | ||||
| 35 | if (rev->available == 0) { | |||
| 36 | if (rev->pending_eof) { | |||
| 37 | rev->ready = 0; | |||
| 38 | rev->eof = 1; | |||
| 39 | ||||
| 40 | ngx_log_error(NGX_LOG_INFO, c->log, rev->kq_errno,if ((c->log)->log_level >= 7) ngx_log_error_core(7, c ->log, rev->kq_errno, "kevent() reported about an closed connection" ) | |||
| 41 | "kevent() reported about an closed connection")if ((c->log)->log_level >= 7) ngx_log_error_core(7, c ->log, rev->kq_errno, "kevent() reported about an closed connection" ); | |||
| 42 | ||||
| 43 | if (rev->kq_errno) { | |||
| 44 | rev->error = 1; | |||
| 45 | ngx_set_socket_errno(rev->kq_errno)(*__error()) = rev->kq_errno; | |||
| 46 | return NGX_ERROR-1; | |||
| 47 | } | |||
| 48 | ||||
| 49 | return 0; | |||
| 50 | ||||
| 51 | } else { | |||
| 52 | return NGX_AGAIN-2; | |||
| 53 | } | |||
| 54 | } | |||
| 55 | } | |||
| 56 | ||||
| 57 | prev = NULL((void*)0); | |||
| 58 | iov = NULL((void*)0); | |||
| 59 | size = 0; | |||
| 60 | ||||
| 61 | vec.elts = iovs; | |||
| 62 | vec.nelts = 0; | |||
| 63 | vec.size = sizeof(struct iovec); | |||
| 64 | vec.nalloc = NGX_IOVS16; | |||
| 65 | vec.pool = c->pool; | |||
| 66 | ||||
| 67 | /* coalesce the neighbouring bufs */ | |||
| 68 | ||||
| 69 | while (chain) { | |||
| 70 | if (prev == chain->buf->last) { | |||
| 71 | iov->iov_len += chain->buf->end - chain->buf->last; | |||
| ||||
| 72 | ||||
| 73 | } else { | |||
| 74 | if (vec.nelts >= IOV_MAX1024) { | |||
| 75 | break; | |||
| 76 | } | |||
| 77 | ||||
| 78 | iov = ngx_array_push(&vec); | |||
| 79 | if (iov == NULL((void*)0)) { | |||
| 80 | return NGX_ERROR-1; | |||
| 81 | } | |||
| 82 | ||||
| 83 | iov->iov_base = (void *) chain->buf->last; | |||
| 84 | iov->iov_len = chain->buf->end - chain->buf->last; | |||
| 85 | } | |||
| 86 | ||||
| 87 | size += chain->buf->end - chain->buf->last; | |||
| 88 | prev = chain->buf->end; | |||
| 89 | chain = chain->next; | |||
| 90 | } | |||
| 91 | ||||
| 92 | ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |||
| 93 | "readv: %d, last:%d", vec.nelts, iov->iov_len); | |||
| 94 | ||||
| 95 | rev = c->read; | |||
| 96 | ||||
| 97 | do { | |||
| 98 | n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); | |||
| 99 | ||||
| 100 | if (n >= 0) { | |||
| 101 | if (ngx_event_flags & NGX_USE_KQUEUE_EVENT0x00000008) { | |||
| 102 | rev->available -= n; | |||
| 103 | ||||
| 104 | /* | |||
| 105 | * rev->available may be negative here because some additional | |||
| 106 | * bytes may be received between kevent() and recv() | |||
| 107 | */ | |||
| 108 | ||||
| 109 | if (rev->available <= 0) { | |||
| 110 | if (!rev->pending_eof) { | |||
| 111 | rev->ready = 0; | |||
| 112 | } | |||
| 113 | ||||
| 114 | if (rev->available < 0) { | |||
| 115 | rev->available = 0; | |||
| 116 | } | |||
| 117 | } | |||
| 118 | ||||
| 119 | if (n == 0) { | |||
| 120 | ||||
| 121 | /* | |||
| 122 | * on FreeBSD recv() may return 0 on closed socket | |||
| 123 | * even if kqueue reported about available data | |||
| 124 | */ | |||
| 125 | ||||
| 126 | #if 0 | |||
| 127 | ngx_log_error(NGX_LOG_ALERT, c->log, 0,if ((c->log)->log_level >= 2) ngx_log_error_core(2, c ->log, 0, "readv() returned 0 while kevent() reported " "%d available bytes" , rev->available) | |||
| 128 | "readv() returned 0 while kevent() reported "if ((c->log)->log_level >= 2) ngx_log_error_core(2, c ->log, 0, "readv() returned 0 while kevent() reported " "%d available bytes" , rev->available) | |||
| 129 | "%d available bytes", rev->available)if ((c->log)->log_level >= 2) ngx_log_error_core(2, c ->log, 0, "readv() returned 0 while kevent() reported " "%d available bytes" , rev->available); | |||
| 130 | #endif | |||
| 131 | ||||
| 132 | rev->eof = 1; | |||
| 133 | rev->available = 0; | |||
| 134 | } | |||
| 135 | ||||
| 136 | return n; | |||
| 137 | } | |||
| 138 | ||||
| 139 | if (n < size) { | |||
| 140 | rev->ready = 0; | |||
| 141 | } | |||
| 142 | ||||
| 143 | if (n == 0) { | |||
| 144 | rev->eof = 1; | |||
| 145 | } | |||
| 146 | ||||
| 147 | return n; | |||
| 148 | } | |||
| 149 | ||||
| 150 | err = ngx_socket_errno(*__error()); | |||
| 151 | ||||
| 152 | if (err == NGX_EAGAIN35 || err == NGX_EINTR4) { | |||
| 153 | ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | |||
| 154 | "readv() not ready"); | |||
| 155 | n = NGX_AGAIN-2; | |||
| 156 | ||||
| 157 | } else { | |||
| 158 | n = ngx_connection_error(c, err, "readv() failed"); | |||
| 159 | break; | |||
| 160 | } | |||
| 161 | ||||
| 162 | } while (err == NGX_EINTR4); | |||
| 163 | ||||
| 164 | rev->ready = 0; | |||
| 165 | ||||
| 166 | if (n == NGX_ERROR-1) { | |||
| 167 | c->read->error = 1; | |||
| 168 | } | |||
| 169 | ||||
| 170 | return n; | |||
| 171 | } | |||
| 172 | ||||
| 173 | #else /* ! NGX_HAVE_KQUEUE */ | |||
| 174 | ||||
| 175 | ssize_t | |||
| 176 | ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) | |||
| 177 | { | |||
| 178 | u_char *prev; | |||
| 179 | ssize_t n, size; | |||
| 180 | ngx_err_t err; | |||
| 181 | ngx_array_t vec; | |||
| 182 | ngx_event_t *rev; | |||
| 183 | struct iovec *iov, iovs[NGX_IOVS16]; | |||
| 184 | ||||
| 185 | prev = NULL((void*)0); | |||
| 186 | iov = NULL((void*)0); | |||
| 187 | size = 0; | |||
| 188 | ||||
| 189 | vec.elts = iovs; | |||
| 190 | vec.nelts = 0; | |||
| 191 | vec.size = sizeof(struct iovec); | |||
| 192 | vec.nalloc = NGX_IOVS16; | |||
| 193 | vec.pool = c->pool; | |||
| 194 | ||||
| 195 | /* coalesce the neighbouring bufs */ | |||
| 196 | ||||
| 197 | while (chain) { | |||
| 198 | if (prev == chain->buf->last) { | |||
| 199 | iov->iov_len += chain->buf->end - chain->buf->last; | |||
| 200 | ||||
| 201 | } else { | |||
| 202 | if (vec.nelts >= IOV_MAX1024) { | |||
| 203 | break; | |||
| 204 | } | |||
| 205 | ||||
| 206 | iov = ngx_array_push(&vec); | |||
| 207 | if (iov == NULL((void*)0)) { | |||
| 208 | return NGX_ERROR-1; | |||
| 209 | } | |||
| 210 | ||||
| 211 | iov->iov_base = (void *) chain->buf->last; | |||
| 212 | iov->iov_len = chain->buf->end - chain->buf->last; | |||
| 213 | } | |||
| 214 | ||||
| 215 | size += chain->buf->end - chain->buf->last; | |||
| 216 | prev = chain->buf->end; | |||
| 217 | chain = chain->next; | |||
| 218 | } | |||
| 219 | ||||
| 220 | ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |||
| 221 | "readv: %d:%d", vec.nelts, iov->iov_len); | |||
| 222 | ||||
| 223 | rev = c->read; | |||
| 224 | ||||
| 225 | do { | |||
| 226 | n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); | |||
| 227 | ||||
| 228 | if (n == 0) { | |||
| 229 | rev->ready = 0; | |||
| 230 | rev->eof = 1; | |||
| 231 | ||||
| 232 | return n; | |||
| 233 | ||||
| 234 | } else if (n > 0) { | |||
| 235 | ||||
| 236 | if (n < size && !(ngx_event_flags & NGX_USE_GREEDY_EVENT0x00000020)) { | |||
| 237 | rev->ready = 0; | |||
| 238 | } | |||
| 239 | ||||
| 240 | return n; | |||
| 241 | } | |||
| 242 | ||||
| 243 | err = ngx_socket_errno(*__error()); | |||
| 244 | ||||
| 245 | if (err == NGX_EAGAIN35 || err == NGX_EINTR4) { | |||
| 246 | ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, err, | |||
| 247 | "readv() not ready"); | |||
| 248 | n = NGX_AGAIN-2; | |||
| 249 | ||||
| 250 | } else { | |||
| 251 | n = ngx_connection_error(c, err, "readv() failed"); | |||
| 252 | break; | |||
| 253 | } | |||
| 254 | ||||
| 255 | } while (err == NGX_EINTR4); | |||
| 256 | ||||
| 257 | rev->ready = 0; | |||
| 258 | ||||
| 259 | if (n == NGX_ERROR-1) { | |||
| 260 | c->read->error = 1; | |||
| 261 | } | |||
| 262 | ||||
| 263 | return n; | |||
| 264 | } | |||
| 265 | ||||
| 266 | #endif /* NGX_HAVE_KQUEUE */ |