diff options
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/aio.c | 4 | ||||
| -rw-r--r-- | src/core/aio.h | 4 | ||||
| -rw-r--r-- | src/nng.c | 18 | ||||
| -rw-r--r-- | src/nng.h | 2 | ||||
| -rw-r--r-- | src/platform/posix/posix_pipedesc.c | 58 | ||||
| -rw-r--r-- | src/platform/posix/posix_udp.c | 25 | ||||
| -rw-r--r-- | src/platform/windows/win_ipc.c | 4 | ||||
| -rw-r--r-- | src/platform/windows/win_tcp.c | 8 | ||||
| -rw-r--r-- | src/platform/windows/win_udp.c | 25 | ||||
| -rw-r--r-- | src/supplemental/http/http_conn.c | 6 | ||||
| -rw-r--r-- | src/supplemental/tls/mbedtls/tls.c | 8 | ||||
| -rw-r--r-- | tests/aio.c | 8 |
13 files changed, 130 insertions, 41 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 439001d6..70d7b29f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -379,6 +379,7 @@ else () nng_check_sym (AF_UNIX sys/socket.h NNG_HAVE_UNIX_SOCKETS) nng_check_sym (backtrace_symbols_fd execinfo.h NNG_HAVE_BACKTRACE) + nng_check_sym (alloca alloca.h NNG_HAVE_ALLOCA) nng_check_struct_member(msghdr msg_control sys/socket.h NNG_HAVE_MSG_CONTROL) endif () diff --git a/src/core/aio.c b/src/core/aio.c index 341b218e..ee1ddf2a 100644 --- a/src/core/aio.c +++ b/src/core/aio.c @@ -147,7 +147,7 @@ nni_aio_fini(nni_aio *aio) } int -nni_aio_set_iov(nni_aio *aio, int niov, const nni_iov *iov) +nni_aio_set_iov(nni_aio *aio, unsigned niov, const nni_iov *iov) { if ((niov > NNI_NUM_ELEMENTS(aio->a_iovinl)) && (niov > aio->a_niovalloc)) { @@ -584,7 +584,7 @@ nni_aio_set_prov_extra(nni_aio *aio, unsigned index, void *data) } void -nni_aio_get_iov(nni_aio *aio, int *niovp, nni_iov **iovp) +nni_aio_get_iov(nni_aio *aio, unsigned *niovp, nni_iov **iovp) { *niovp = aio->a_niov; *iovp = aio->a_iov; diff --git a/src/core/aio.h b/src/core/aio.h index 34f4a56b..b17c8e97 100644 --- a/src/core/aio.h +++ b/src/core/aio.h @@ -147,10 +147,10 @@ extern size_t nni_aio_iov_advance(nni_aio *, size_t); // nni_aio_iov_count returns the number of bytes referenced by the aio's iov. extern size_t nni_aio_iov_count(nni_aio *); -extern int nni_aio_set_iov(nni_aio *, int, const nni_iov *); +extern int nni_aio_set_iov(nni_aio *, unsigned, const nni_iov *); extern void nni_aio_set_timeout(nni_aio *, nng_duration); -extern void nni_aio_get_iov(nni_aio *, int *, nni_iov **); +extern void nni_aio_get_iov(nni_aio *, unsigned *, nni_iov **); extern void nni_aio_normalize_timeout(nni_aio *, nng_duration); extern void nni_aio_bump_count(nni_aio *, size_t); @@ -1086,8 +1086,22 @@ nng_aio_set_timeout(nng_aio *aio, nni_duration when) } int -nng_aio_set_iov(nng_aio *aio, int niov, nng_iov *iov) -{ +nng_aio_set_iov(nng_aio *aio, unsigned niov, const nng_iov *iov) +{ +// We limit the niov to prevent user insanity. This is required +// to avoid stack allocations that might smash the stack. The +// assumption is that we can always put at least 1kB on the stack -- +// our nng_iov structures are 16B. Systems without stack allocation +// get a smaller limit, because we use an automatic variable. +#if defined(NNG_HAVE_ALLOCA) || defined(_WIN32) + if (niov > 64) { + return (NNG_EINVAL); + } +#else + if (niov > 16) { + return (NNG_EINVAL); + } +#endif return (nni_aio_set_iov(aio, niov, iov)); } @@ -334,7 +334,7 @@ NNG_DECL void nng_aio_set_timeout(nng_aio *, nng_duration); // itself is copied. Data members (the memory regions referenced) *may* be // copied as well, depending on the operation. This operation is guaranteed // to succeed if n <= 4, otherwise it may fail due to NNG_ENOMEM. -NNG_DECL int nng_aio_set_iov(nng_aio *, int, nng_iov *); +NNG_DECL int nng_aio_set_iov(nng_aio *, unsigned, const nng_iov *); // Message API. NNG_DECL int nng_msg_alloc(nng_msg **, size_t); diff --git a/src/platform/posix/posix_pipedesc.c b/src/platform/posix/posix_pipedesc.c index 23d69e51..f387c60c 100644 --- a/src/platform/posix/posix_pipedesc.c +++ b/src/platform/posix/posix_pipedesc.c @@ -69,14 +69,32 @@ nni_posix_pipedesc_dowrite(nni_posix_pipedesc *pd) nni_aio *aio; while ((aio = nni_list_first(&pd->writeq)) != NULL) { - int i; - int n; - struct iovec iovec[4]; - int niov; - int naiov; - nni_iov * aiov; + unsigned i; + int n; + int niov; + unsigned naiov; + nni_iov *aiov; +#ifdef NNG_HAVE_ALLOCA + struct iovec *iovec; +#else + struct iovec iovec[16]; +#endif nni_aio_get_iov(aio, &naiov, &aiov); + +#ifdef NNG_HAVE_ALLOCA + if (naiov > 64) { + nni_posix_pipedesc_finish(aio, NNG_EINVAL); + continue; + } + iovec = alloca(naiov * sizeof(*iovec)); +#else + if (naiov > NNI_NUM_ELEMENTS(iovec)) { + nni_posix_pipedesc_finish(aio, NNG_EINVAL); + continue; + } +#endif + for (niov = 0, i = 0; i < naiov; i++) { if (aiov[i].iov_len > 0) { iovec[niov].iov_len = aiov[i].iov_len; @@ -112,14 +130,30 @@ nni_posix_pipedesc_doread(nni_posix_pipedesc *pd) nni_aio *aio; while ((aio = nni_list_first(&pd->readq)) != NULL) { - int i; - int n; - struct iovec iovec[4]; - int niov; - int naiov; - nni_iov * aiov; + unsigned i; + int n; + int niov; + unsigned naiov; + nni_iov *aiov; +#ifdef NNG_HAVE_ALLOCA + struct iovec *iovec; +#else + struct iovec iovec[16]; +#endif nni_aio_get_iov(aio, &naiov, &aiov); +#ifdef NNG_HAVE_ALLOCA + if (naiov > 64) { + nni_posix_pipedesc_finish(aio, NNG_EINVAL); + continue; + } + iovec = alloca(naiov * sizeof(*iovec)); +#else + if (naiov > NNI_NUM_ELEMENTS(iovec)) { + nni_posix_pipedesc_finish(aio, NNG_EINVAL); + continue; + } +#endif for (niov = 0, i = 0; i < naiov; i++) { if (aiov[i].iov_len != 0) { iovec[niov].iov_len = aiov[i].iov_len; diff --git a/src/platform/posix/posix_udp.c b/src/platform/posix/posix_udp.c index e01f6883..cd7b0561 100644 --- a/src/platform/posix/posix_udp.c +++ b/src/platform/posix/posix_udp.c @@ -63,7 +63,7 @@ nni_posix_udp_dorecv(nni_plat_udp *udp) // While we're able to recv, do so. while ((aio = nni_list_first(q)) != NULL) { struct iovec iov[4]; - int niov; + unsigned niov; nni_iov * aiov; struct sockaddr_storage ss; nng_sockaddr * sa; @@ -73,7 +73,7 @@ nni_posix_udp_dorecv(nni_plat_udp *udp) nni_aio_get_iov(aio, &niov, &aiov); - for (int i = 0; i < niov; i++) { + for (unsigned i = 0; i < niov; i++) { iov[i].iov_base = aiov[i].iov_buf; iov[i].iov_len = aiov[i].iov_len; } @@ -123,13 +123,28 @@ nni_posix_udp_dosend(nni_plat_udp *udp) rv = NNG_EADDRINVAL; } else { struct msghdr hdr; - struct iovec iov[4]; - int niov; + unsigned niov; nni_iov * aiov; +#ifdef NNG_HAVE_ALLOCA + struct iovec *iov; +#else + struct iovec iov[16]; +#endif nni_aio_get_iov(aio, &niov, &aiov); +#ifdef NNG_HAVE_ALLOCA + if (niov > 64) { + rv = NNG_EINVAL; + } else { + iov = alloca(niov * sizeof(*iov)); + } +#else + if (niov > NNI_NUM_ELEMENTS(iov)) { + rv = NNG_EINVAL; + } +#endif - for (int i = 0; i < niov; i++) { + for (unsigned i = 0; i < niov; i++) { iov[i].iov_base = aiov[i].iov_buf; iov[i].iov_len = aiov[i].iov_len; } diff --git a/src/platform/windows/win_ipc.c b/src/platform/windows/win_ipc.c index 022a18ea..76180d23 100644 --- a/src/platform/windows/win_ipc.c +++ b/src/platform/windows/win_ipc.c @@ -59,8 +59,8 @@ nni_win_ipc_pipe_start(nni_win_event *evt, nni_aio *aio) BOOL ok; int rv; nni_plat_ipc_pipe *pipe = evt->ptr; - int idx; - int naiov; + unsigned idx; + unsigned naiov; nni_iov * aiov; NNI_ASSERT(aio != NULL); diff --git a/src/platform/windows/win_tcp.c b/src/platform/windows/win_tcp.c index c9935719..254cf40b 100644 --- a/src/platform/windows/win_tcp.c +++ b/src/platform/windows/win_tcp.c @@ -12,6 +12,7 @@ #ifdef NNG_PLATFORM_WINDOWS +#include <malloc.h> #include <stdio.h> struct nni_plat_tcp_pipe { @@ -101,15 +102,16 @@ nni_win_tcp_pipe_start(nni_win_event *evt, nni_aio *aio) { int rv; SOCKET s; - WSABUF iov[4]; // XXX: consider _alloca() DWORD niov; DWORD flags; nni_plat_tcp_pipe *pipe = evt->ptr; int i; - int naiov; + unsigned naiov; nni_iov * aiov; + WSABUF * iov; nni_aio_get_iov(aio, &naiov, &aiov); + iov = _malloca(naiov * sizeof(*iov)); // Put the AIOs in Windows form. for (niov = 0, i = 0; i < naiov; i++) { @@ -121,6 +123,7 @@ nni_win_tcp_pipe_start(nni_win_event *evt, nni_aio *aio) } if ((s = pipe->s) == INVALID_SOCKET) { + _freea(iov); evt->status = NNG_ECLOSED; evt->count = 0; return (1); @@ -136,6 +139,7 @@ nni_win_tcp_pipe_start(nni_win_event *evt, nni_aio *aio) } else { rv = WSARecv(s, iov, niov, NULL, &flags, &evt->olpd, NULL); } + _freea(iov); if ((rv == SOCKET_ERROR) && ((rv = GetLastError()) != ERROR_IO_PENDING)) { diff --git a/src/platform/windows/win_udp.c b/src/platform/windows/win_udp.c index ba947719..81aa2c06 100644 --- a/src/platform/windows/win_udp.c +++ b/src/platform/windows/win_udp.c @@ -15,6 +15,7 @@ #ifdef NNG_PLATFORM_WINDOWS +#include <malloc.h> #include <stdio.h> struct nni_plat_udp { @@ -134,11 +135,11 @@ nni_win_udp_start_rx(nni_win_event *evt, nni_aio *aio) { int rv; SOCKET s; - WSABUF iov[4]; // XXX: consider _alloca DWORD flags; nni_plat_udp *u = evt->ptr; nni_iov * aiov; - int naiov; + unsigned naiov; + WSABUF * iov; if ((s = u->s) == INVALID_SOCKET) { evt->status = NNG_ECLOSED; @@ -149,8 +150,13 @@ nni_win_udp_start_rx(nni_win_event *evt, nni_aio *aio) u->rxsalen = sizeof(SOCKADDR_STORAGE); nni_aio_get_iov(aio, &naiov, &aiov); + // This is a stack allocation- it should always succeed - or + // throw an exception if there is not sufficient stack space. + // (Turns out it can allocate from the heap, but same semantics.) + iov = _malloca(sizeof(*iov) * naiov); + // Put the AIOs in Windows form. - for (int i = 0; i < naiov; i++) { + for (unsigned i = 0; i < naiov; i++) { iov[i].buf = aiov[i].iov_buf; iov[i].len = (ULONG) aiov[i].iov_len; } @@ -164,6 +170,8 @@ nni_win_udp_start_rx(nni_win_event *evt, nni_aio *aio) rv = WSARecvFrom(u->s, iov, (DWORD) naiov, NULL, &flags, (struct sockaddr *) &u->rxsa, &u->rxsalen, &evt->olpd, NULL); + _freea(iov); + if ((rv == SOCKET_ERROR) && ((rv = GetLastError()) != ERROR_IO_PENDING)) { // Synchronous failure. @@ -183,12 +191,12 @@ nni_win_udp_start_tx(nni_win_event *evt, nni_aio *aio) { int rv; SOCKET s; - WSABUF iov[4]; - int naiov; + unsigned naiov; nni_iov * aiov; nni_plat_udp *u = evt->ptr; int salen; nni_sockaddr *sa; + WSABUF * iov; if ((s = u->s) == INVALID_SOCKET) { evt->status = NNG_ECLOSED; @@ -205,8 +213,11 @@ nni_win_udp_start_tx(nni_win_event *evt, nni_aio *aio) } nni_aio_get_iov(aio, &naiov, &aiov); + + iov = _malloca(sizeof(*iov) * naiov); + // Put the AIOs in Windows form. - for (int i = 0; i < naiov; i++) { + for (unsigned i = 0; i < naiov; i++) { iov[i].buf = aiov[i].iov_buf; iov[i].len = (ULONG) aiov[i].iov_len; } @@ -219,6 +230,8 @@ nni_win_udp_start_tx(nni_win_event *evt, nni_aio *aio) rv = WSASendTo(u->s, iov, (DWORD) naiov, NULL, 0, (struct sockaddr *) &u->txsa, salen, &evt->olpd, NULL); + _freea(iov); + if ((rv == SOCKET_ERROR) && ((rv = GetLastError()) != ERROR_IO_PENDING)) { // Synchronous failure. diff --git a/src/supplemental/http/http_conn.c b/src/supplemental/http/http_conn.c index 484d2242..6a72a731 100644 --- a/src/supplemental/http/http_conn.c +++ b/src/supplemental/http/http_conn.c @@ -145,7 +145,7 @@ http_rd_buf(nni_http_conn *conn, nni_aio *aio) int rv; bool raw = false; nni_iov *iov; - int niov; + unsigned niov; rbuf += conn->rd_get; @@ -274,7 +274,7 @@ http_rd_cb(void *arg) nni_aio * uaio; size_t cnt; int rv; - int niov; + unsigned niov; nni_iov * iov; nni_mtx_lock(&conn->mtx); @@ -377,7 +377,7 @@ http_wr_start(nni_http_conn *conn) { nni_aio *aio; nni_iov *iov; - int niov; + unsigned niov; if ((aio = conn->wr_uaio) == NULL) { if ((aio = nni_list_first(&conn->wrq)) == NULL) { diff --git a/src/supplemental/tls/mbedtls/tls.c b/src/supplemental/tls/mbedtls/tls.c index cb0a4bbf..ca6c716c 100644 --- a/src/supplemental/tls/mbedtls/tls.c +++ b/src/supplemental/tls/mbedtls/tls.c @@ -642,11 +642,11 @@ nni_tls_do_send(nni_tls *tp) uint8_t *buf = NULL; size_t len = 0; nni_iov *iov; - int niov; + unsigned niov; nni_aio_get_iov(aio, &niov, &iov); - for (int i = 0; i < niov; i++) { + for (unsigned i = 0; i < niov; i++) { if (iov[i].iov_len != 0) { buf = iov[i].iov_buf; len = iov[i].iov_len; @@ -688,11 +688,11 @@ nni_tls_do_recv(nni_tls *tp) uint8_t *buf = NULL; size_t len = 0; nni_iov *iov; - int niov; + unsigned niov; nni_aio_get_iov(aio, &niov, &iov); - for (int i = 0; i < niov; i++) { + for (unsigned i = 0; i < niov; i++) { if (iov[i].iov_len != 0) { buf = iov[i].iov_buf; len = iov[i].iov_len; diff --git a/tests/aio.c b/tests/aio.c index fc5d4baf..8af5dbc7 100644 --- a/tests/aio.c +++ b/tests/aio.c @@ -129,6 +129,14 @@ Main({ }) }); + + Convey("We cannot set insane IOVs", { + nng_aio *aio; + nng_iov iov; + + So(nng_aio_alloc(&aio, NULL, NULL) == 0); + So(nng_aio_set_iov(aio, 1024, &iov) == NNG_EINVAL); + }); }); nng_fini(); |
