From 9f171d586c74fc3cd8ff99130b12d48d836a97b6 Mon Sep 17 00:00:00 2001 From: shikokuchuo <53399081+shikokuchuo@users.noreply.github.com> Date: Sat, 23 Dec 2023 22:27:12 +0000 Subject: [PATCH] safety against longjmp --- README.Rmd | 2 +- README.md | 2 +- src/aio.c | 54 ++++++++++++++------------- src/core.c | 104 ++++++++++++++-------------------------------------- src/utils.c | 16 ++++---- 5 files changed, 65 insertions(+), 113 deletions(-) diff --git a/README.Rmd b/README.Rmd index 23b2d1b6d..2692e291c 100644 --- a/README.Rmd +++ b/README.Rmd @@ -29,7 +29,7 @@ As its own [threaded concurrency framework](https://shikokuchuo.net/nanonext/art Designed for performance and reliability, the NNG library is written in C and [`nanonext`](https://doi.org/10.5281/zenodo.7903429) is a lightweight zero-dependency wrapper. -Provides the interface for code and processes to communicate with each other - [receive data generated in Python, perform analysis in R, and send results to a C++ program](https://shikokuchuo.net/nanonext/articles/nanonext.html#cross-language-exchange) – all on the same computer or on networks spanning the globe. +Provides the interface for code and processes to communicate with each other - [receive data generated in Python, perform analysis in R, and send results to a C++ program](https://shikokuchuo.net/nanonext/articles/nanonext.html#cross-language-exchange) – on the same computer or across networks spanning the globe. Implemented scalability protocols: diff --git a/README.md b/README.md index cebd0e78e..e3798ee19 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Provides the interface for code and processes to communicate with each other - [receive data generated in Python, perform analysis in R, and send results to a C++ program](https://shikokuchuo.net/nanonext/articles/nanonext.html#cross-language-exchange) -– all on the same computer or on networks spanning the globe. +– on the same computer or across networks spanning the globe. Implemented scalability protocols: diff --git a/src/aio.c b/src/aio.c index a63b1c1fe..1ee1bee30 100644 --- a/src/aio.c +++ b/src/aio.c @@ -890,11 +890,6 @@ SEXP rnng_send_aio(SEXP con, SEXP data, SEXP mode, SEXP timeout, SEXP clo) { const SEXP ptrtag = R_ExternalPtrTag(con); if (ptrtag == nano_SocketSymbol) { - nng_socket *sock = (nng_socket *) R_ExternalPtrAddr(con); - nng_msg *msg; - saio = R_Calloc(1, nano_aio); - saio->type = SENDAIO; - switch (nano_encodes(mode)) { case 1: nano_serialize(&buf, data); break; @@ -904,6 +899,11 @@ SEXP rnng_send_aio(SEXP con, SEXP data, SEXP mode, SEXP timeout, SEXP clo) { nano_serialize_next(&buf, data); break; } + nng_socket *sock = (nng_socket *) R_ExternalPtrAddr(con); + nng_msg *msg; + saio = R_Calloc(1, nano_aio); + saio->type = SENDAIO; + if ((xc = nng_msg_alloc(&msg, 0))) goto exitlevel2; @@ -923,11 +923,6 @@ SEXP rnng_send_aio(SEXP con, SEXP data, SEXP mode, SEXP timeout, SEXP clo) { } else if (ptrtag == nano_ContextSymbol) { - nng_ctx *ctxp = (nng_ctx *) R_ExternalPtrAddr(con); - nng_msg *msg; - saio = R_Calloc(1, nano_aio); - saio->type = SENDAIO; - switch (nano_encodes(mode)) { case 1: nano_serialize(&buf, data); break; @@ -937,6 +932,11 @@ SEXP rnng_send_aio(SEXP con, SEXP data, SEXP mode, SEXP timeout, SEXP clo) { nano_serialize_next(&buf, data); break; } + nng_ctx *ctxp = (nng_ctx *) R_ExternalPtrAddr(con); + nng_msg *msg; + saio = R_Calloc(1, nano_aio); + saio->type = SENDAIO; + if ((xc = nng_msg_alloc(&msg, 0))) goto exitlevel2; @@ -956,12 +956,13 @@ SEXP rnng_send_aio(SEXP con, SEXP data, SEXP mode, SEXP timeout, SEXP clo) { } else if (ptrtag == nano_StreamSymbol) { - nng_stream *sp = (nng_stream *) R_ExternalPtrAddr(con); const int frames = LOGICAL(Rf_getAttrib(con, nano_TextframesSymbol))[0]; - nng_iov iov; nano_encode(&buf, data); + nng_stream *sp = (nng_stream *) R_ExternalPtrAddr(con); + nng_iov iov; + saio = R_Calloc(1, nano_aio); saio->type = IOV_SENDAIO; saio->data = R_Calloc(buf.cur, unsigned char); @@ -1018,15 +1019,16 @@ SEXP rnng_recv_aio(SEXP con, SEXP mode, SEXP timeout, SEXP bytes, SEXP clo) { const nng_duration dur = timeout == R_NilValue ? NNG_DURATION_DEFAULT : (nng_duration) Rf_asInteger(timeout); nano_aio *raio; SEXP aio; - int xc; + int mod, xc; const SEXP ptrtag = R_ExternalPtrTag(con); if (ptrtag == nano_SocketSymbol) { + mod = nano_matcharg(mode); nng_socket *sock = (nng_socket *) R_ExternalPtrAddr(con); raio = R_Calloc(1, nano_aio); raio->type = RECVAIO; - raio->mode = nano_matcharg(mode); + raio->mode = mod; if ((xc = nng_aio_alloc(&raio->aio, raio_complete, raio))) goto exitlevel1; @@ -1039,10 +1041,11 @@ SEXP rnng_recv_aio(SEXP con, SEXP mode, SEXP timeout, SEXP bytes, SEXP clo) { } else if (ptrtag == nano_ContextSymbol) { + mod = nano_matcharg(mode); nng_ctx *ctxp = (nng_ctx *) R_ExternalPtrAddr(con); raio = R_Calloc(1, nano_aio); raio->type = RECVAIO; - raio->mode = nano_matcharg(mode); + raio->mode = mod; if ((xc = nng_aio_alloc(&raio->aio, raio_complete, raio))) goto exitlevel1; @@ -1055,13 +1058,14 @@ SEXP rnng_recv_aio(SEXP con, SEXP mode, SEXP timeout, SEXP bytes, SEXP clo) { } else if (ptrtag == nano_StreamSymbol) { - nng_stream *sp = (nng_stream *) R_ExternalPtrAddr(con); + mod = nano_matchargs(mode); const size_t xlen = (size_t) Rf_asInteger(bytes); + nng_stream *sp = (nng_stream *) R_ExternalPtrAddr(con); nng_iov iov; raio = R_Calloc(1, nano_aio); raio->type = IOV_RECVAIO; - raio->mode = nano_matchargs(mode); + raio->mode = mod; raio->data = R_Calloc(xlen, unsigned char); iov.iov_len = xlen; iov.iov_buf = raio->data; @@ -1113,6 +1117,9 @@ SEXP rnng_ncurl_aio(SEXP http, SEXP convert, SEXP method, SEXP headers, SEXP dat SEXP timeout, SEXP tls, SEXP clo) { const char *httr = CHAR(STRING_ELT(http, 0)); + const char *mthd = method != R_NilValue ? CHAR(STRING_ELT(method, 0)) : NULL; + const int conv = LOGICAL(convert)[0]; + const nng_duration dur = timeout == R_NilValue ? NNG_DURATION_DEFAULT : (nng_duration) Rf_asInteger(timeout); if (tls != R_NilValue && R_ExternalPtrTag(tls) != nano_TlsSymbol) Rf_error("'tls' is not a valid TLS Configuration"); nano_aio *haio = R_Calloc(1, nano_aio); @@ -1122,7 +1129,7 @@ SEXP rnng_ncurl_aio(SEXP http, SEXP convert, SEXP method, SEXP headers, SEXP dat haio->type = HTTP_AIO; haio->data = handle; - haio->mode = LOGICAL(convert)[0]; + haio->mode = conv; handle->cfg = NULL; if ((xc = nng_url_parse(&handle->url, httr))) @@ -1131,12 +1138,8 @@ SEXP rnng_ncurl_aio(SEXP http, SEXP convert, SEXP method, SEXP headers, SEXP dat goto exitlevel2; if ((xc = nng_http_req_alloc(&handle->req, handle->url))) goto exitlevel3; - - if (method != R_NilValue) { - const char *met = CHAR(STRING_ELT(method, 0)); - if ((xc = nng_http_req_set_method(handle->req, met))) - goto exitlevel4; - } + if (mthd != NULL && (xc = nng_http_req_set_method(handle->req, mthd))) + goto exitlevel4; if (headers != R_NilValue) { R_xlen_t hlen = Rf_xlength(headers); @@ -1197,8 +1200,7 @@ SEXP rnng_ncurl_aio(SEXP http, SEXP convert, SEXP method, SEXP headers, SEXP dat } - if (timeout != R_NilValue) - nng_aio_set_timeout(haio->aio, (nng_duration) Rf_asInteger(timeout)); + nng_aio_set_timeout(haio->aio, dur); nng_http_client_transact(handle->cli, handle->req, handle->res, haio->aio); PROTECT(aio = R_MakeExternalPtr(haio, nano_AioSymbol, R_NilValue)); diff --git a/src/core.c b/src/core.c index b586cf692..b7db83721 100644 --- a/src/core.c +++ b/src/core.c @@ -242,6 +242,7 @@ void nano_serialize_next(nano_buf *buf, SEXP object) { if (TYPEOF(out) != RAWSXP) { R_ReleaseObject(nano_refList); nano_refList = R_NilValue; + if (buf->len) R_Free(buf->buf); Rf_error("serialization refhook did not return a raw vector"); } R_xlen_t xlen = XLENGTH(out); @@ -650,14 +651,13 @@ SEXP rnng_ctx_close(SEXP context) { SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { + const int flags = block == R_NilValue ? -2 : TYPEOF(block) == LGLSXP ? 0 : Rf_asInteger(block); nano_buf buf; int xc; const SEXP ptrtag = R_ExternalPtrTag(con); if (ptrtag == nano_SocketSymbol) { - nng_socket *sock = (nng_socket *) R_ExternalPtrAddr(con); - switch (nano_encodes(mode)) { case 1: nano_serialize(&buf, data); break; @@ -667,21 +667,17 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { nano_serialize_next(&buf, data); break; } - if (block == R_NilValue) { - - xc = nng_send(*sock, buf.buf, buf.cur, NNG_FLAG_NONBLOCK); - NANO_FREE(buf); + nng_socket *sock = (nng_socket *) R_ExternalPtrAddr(con); - } else if (TYPEOF(block) == LGLSXP) { + if (flags <= 0) { - xc = nng_send(*sock, buf.buf, buf.cur, (LOGICAL(block)[0] == 0) * NNG_FLAG_NONBLOCK); + xc = nng_send(*sock, buf.buf, buf.cur, flags ? NNG_FLAG_NONBLOCK : (LOGICAL(block)[0] == 0) * NNG_FLAG_NONBLOCK); NANO_FREE(buf); } else { nng_msg *msgp; nng_aio *aiop; - const nng_duration dur = (nng_duration) Rf_asInteger(block); if ((xc = nng_msg_alloc(&msgp, 0))) goto exitlevel1; @@ -693,7 +689,7 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { } nng_aio_set_msg(aiop, msgp); - nng_aio_set_timeout(aiop, dur); + nng_aio_set_timeout(aiop, flags); nng_send_aio(*sock, aiop); NANO_FREE(buf); nng_aio_wait(aiop); @@ -705,8 +701,6 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { } else if (ptrtag == nano_ContextSymbol) { - nng_ctx *ctxp = (nng_ctx *) R_ExternalPtrAddr(con); - switch (nano_encodes(mode)) { case 1: nano_serialize(&buf, data); break; @@ -716,13 +710,11 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { nano_serialize_next(&buf, data); break; } + nng_ctx *ctxp = (nng_ctx *) R_ExternalPtrAddr(con); nng_msg *msgp; #ifdef NANONEXT_LEGACY_NNG - const nng_duration dur = block == R_NilValue ? NNG_DURATION_DEFAULT : - TYPEOF(block) == LGLSXP ? (LOGICAL(block)[0] == 1) * NNG_DURATION_DEFAULT : (nng_duration) Rf_asInteger(block); - nng_aio *aiop; if ((xc = nng_msg_alloc(&msgp, 0))) @@ -735,7 +727,7 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { } nng_aio_set_msg(aiop, msgp); - nng_aio_set_timeout(aiop, dur); + nng_aio_set_timeout(aiop, flags ? flags : (LOGICAL(block)[0] == 1) * NNG_DURATION_DEFAULT); nng_ctx_send(*ctxp, aiop); NANO_FREE(buf); nng_aio_wait(aiop); @@ -745,26 +737,13 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { #else - if (block == R_NilValue) { + if (flags <= 0) { if ((xc = nng_msg_alloc(&msgp, 0))) goto exitlevel1; if ((xc = nng_msg_append(msgp, buf.buf, buf.cur)) || - (xc = nng_ctx_sendmsg(*ctxp, msgp, 0))) { - nng_msg_free(msgp); - goto exitlevel1; - } - - NANO_FREE(buf); - - } else if (TYPEOF(block) == LGLSXP) { - - if ((xc = nng_msg_alloc(&msgp, 0))) - goto exitlevel1; - - if ((xc = nng_msg_append(msgp, buf.buf, buf.cur)) || - (xc = nng_ctx_sendmsg(*ctxp, msgp, (LOGICAL(block)[0] == 0) * NNG_FLAG_NONBLOCK))) { + (xc = nng_ctx_sendmsg(*ctxp, msgp, flags ? 0 : (LOGICAL(block)[0] == 0) * NNG_FLAG_NONBLOCK))) { nng_msg_free(msgp); goto exitlevel1; } @@ -773,7 +752,6 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { } else { - const nng_duration dur = (nng_duration) Rf_asInteger(block); nng_aio *aiop; if ((xc = nng_msg_alloc(&msgp, 0))) @@ -786,7 +764,7 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { } nng_aio_set_msg(aiop, msgp); - nng_aio_set_timeout(aiop, dur); + nng_aio_set_timeout(aiop, flags); nng_ctx_send(*ctxp, aiop); NANO_FREE(buf); nng_aio_wait(aiop); @@ -800,15 +778,14 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { } else if (ptrtag == nano_StreamSymbol) { + const int frames = LOGICAL(Rf_getAttrib(con, nano_TextframesSymbol))[0]; + + nano_encode(&buf, data); + nng_stream *sp = (nng_stream *) R_ExternalPtrAddr(con); nng_aio *aiop; nng_iov iov; - const nng_duration dur = block == R_NilValue ? NNG_DURATION_DEFAULT : - TYPEOF(block) == LGLSXP ? (LOGICAL(block)[0] == 1) * NNG_DURATION_DEFAULT : (nng_duration) Rf_asInteger(block); - - nano_encode(&buf, data); - const int frames = LOGICAL(Rf_getAttrib(con, nano_TextframesSymbol))[0]; iov.iov_len = buf.cur - (frames == 1); iov.iov_buf = buf.buf; @@ -820,7 +797,7 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { return mk_error(xc); } - nng_aio_set_timeout(aiop, dur); + nng_aio_set_timeout(aiop, flags ? flags : (LOGICAL(block)[0] == 1) * NNG_DURATION_DEFAULT); nng_stream_send(sp, aiop); nng_aio_wait(aiop); xc = nng_aio_result(aiop); @@ -843,6 +820,8 @@ SEXP rnng_send(SEXP con, SEXP data, SEXP mode, SEXP block) { SEXP rnng_recv(SEXP con, SEXP mode, SEXP block, SEXP bytes) { + const int flags = block == R_NilValue ? -2 : TYPEOF(block) == LGLSXP ? 0 : Rf_asInteger(block); + const int mod = nano_matcharg(mode); int xc; unsigned char *buf; size_t sz; @@ -852,20 +831,10 @@ SEXP rnng_recv(SEXP con, SEXP mode, SEXP block, SEXP bytes) { if (ptrtag == nano_SocketSymbol) { nng_socket *sock = (nng_socket *) R_ExternalPtrAddr(con); - const int mod = nano_matcharg(mode); - - if (block == R_NilValue) { - - xc = nng_recv(*sock, &buf, &sz, NNG_FLAG_ALLOC + NNG_FLAG_NONBLOCK); - if (xc) - return mk_error(xc); - - res = nano_decode(buf, sz, mod); - nng_free(buf, sz); - } else if (TYPEOF(block) == LGLSXP) { + if (flags <= 0) { - xc = nng_recv(*sock, &buf, &sz, NNG_FLAG_ALLOC + (LOGICAL(block)[0] == 0) * NNG_FLAG_NONBLOCK); + xc = nng_recv(*sock, &buf, &sz, NNG_FLAG_ALLOC + (flags || LOGICAL(block)[0] == 0) * NNG_FLAG_NONBLOCK); if (xc) return mk_error(xc); @@ -875,10 +844,9 @@ SEXP rnng_recv(SEXP con, SEXP mode, SEXP block, SEXP bytes) { } else { nng_aio *aiop; - nng_duration dur = (nng_duration) Rf_asInteger(block); if ((xc = nng_aio_alloc(&aiop, NULL, NULL))) return mk_error(xc); - nng_aio_set_timeout(aiop, dur); + nng_aio_set_timeout(aiop, flags); nng_recv_aio(*sock, aiop); nng_aio_wait(aiop); if ((xc = nng_aio_result(aiop))) { @@ -896,18 +864,15 @@ SEXP rnng_recv(SEXP con, SEXP mode, SEXP block, SEXP bytes) { } else if (ptrtag == nano_ContextSymbol) { nng_ctx *ctxp = (nng_ctx *) R_ExternalPtrAddr(con); - const int mod = nano_matcharg(mode); nng_msg *msgp; #ifdef NANONEXT_LEGACY_NNG - const nng_duration dur = block == R_NilValue ? NNG_DURATION_DEFAULT : - TYPEOF(block) == LGLSXP ? (LOGICAL(block)[0] == 1) * NNG_DURATION_DEFAULT : (nng_duration) Rf_asInteger(block); nng_aio *aiop; if ((xc = nng_aio_alloc(&aiop, NULL, NULL))) return mk_error(xc); - nng_aio_set_timeout(aiop, dur); + nng_aio_set_timeout(aiop, flags ? flags : (LOGICAL(block)[0] == 1) * NNG_DURATION_DEFAULT)); nng_ctx_recv(*ctxp, aiop); nng_aio_wait(aiop); @@ -925,20 +890,9 @@ SEXP rnng_recv(SEXP con, SEXP mode, SEXP block, SEXP bytes) { #else - if (block == R_NilValue) { + if (flags <= 0) { - xc = nng_ctx_recvmsg(*ctxp, &msgp, 0); - if (xc) - return mk_error(xc); - - buf = nng_msg_body(msgp); - sz = nng_msg_len(msgp); - res = nano_decode(buf, sz, mod); - nng_msg_free(msgp); - - } else if (TYPEOF(block) == LGLSXP) { - - xc = nng_ctx_recvmsg(*ctxp, &msgp, (LOGICAL(block)[0] == 0) * NNG_FLAG_NONBLOCK); + xc = nng_ctx_recvmsg(*ctxp, &msgp, flags ? 0 : (LOGICAL(block)[0] == 0) * NNG_FLAG_NONBLOCK); if (xc) return mk_error(xc); @@ -949,12 +903,11 @@ SEXP rnng_recv(SEXP con, SEXP mode, SEXP block, SEXP bytes) { } else { - const nng_duration dur = (nng_duration) Rf_asInteger(block); nng_aio *aiop; if ((xc = nng_aio_alloc(&aiop, NULL, NULL))) return mk_error(xc); - nng_aio_set_timeout(aiop, dur); + nng_aio_set_timeout(aiop, flags); nng_ctx_recv(*ctxp, aiop); nng_aio_wait(aiop); @@ -976,11 +929,8 @@ SEXP rnng_recv(SEXP con, SEXP mode, SEXP block, SEXP bytes) { } else if (ptrtag == nano_StreamSymbol) { - nng_stream *sp = (nng_stream *) R_ExternalPtrAddr(con); - const int mod = nano_matchargs(mode); const size_t xlen = (size_t) Rf_asInteger(bytes); - const nng_duration dur = block == R_NilValue ? NNG_DURATION_DEFAULT : - TYPEOF(block) == LGLSXP ? (LOGICAL(block)[0] == 1) * NNG_DURATION_DEFAULT : (nng_duration) Rf_asInteger(block); + nng_stream *sp = (nng_stream *) R_ExternalPtrAddr(con); nng_iov iov; nng_aio *aiop; @@ -996,7 +946,7 @@ SEXP rnng_recv(SEXP con, SEXP mode, SEXP block, SEXP bytes) { goto exitlevel1; } - nng_aio_set_timeout(aiop, dur); + nng_aio_set_timeout(aiop, flags ? flags : (LOGICAL(block)[0] == 1) * NNG_DURATION_DEFAULT); nng_stream_recv(sp, aiop); nng_aio_wait(aiop); diff --git a/src/utils.c b/src/utils.c index 5efd1c6bd..9292129f2 100644 --- a/src/utils.c +++ b/src/utils.c @@ -174,8 +174,11 @@ SEXP rnng_is_error_value(SEXP x) { SEXP rnng_ncurl(SEXP http, SEXP convert, SEXP follow, SEXP method, SEXP headers, SEXP data, SEXP response, SEXP timeout, SEXP tls) { - const int conv = LOGICAL(convert)[0]; const char *addr = CHAR(STRING_ELT(http, 0)); + const char *mthd = method != R_NilValue ? CHAR(STRING_ELT(method, 0)) : NULL; + const int conv = LOGICAL(convert)[0]; + const int cont = LOGICAL(follow)[0]; + const nng_duration dur = timeout == R_NilValue ? NNG_DURATION_DEFAULT : (nng_duration) Rf_asInteger(timeout); if (tls != R_NilValue && R_ExternalPtrTag(tls) != nano_TlsSymbol) Rf_error("'tls' is not a valid TLS Configuration"); nng_url *url; @@ -196,10 +199,8 @@ SEXP rnng_ncurl(SEXP http, SEXP convert, SEXP follow, SEXP method, SEXP headers, goto exitlevel2; if ((xc = nng_http_req_alloc(&req, url))) goto exitlevel3; - if (method != R_NilValue) { - if ((xc = nng_http_req_set_method(req, CHAR(STRING_ELT(method, 0))))) - goto exitlevel4; - } + if (mthd != NULL && (xc = nng_http_req_set_method(req, mthd))) + goto exitlevel4; if (headers != R_NilValue) { const R_xlen_t hlen = Rf_xlength(headers); SEXP names = Rf_getAttrib(headers, R_NamesSymbol); @@ -257,8 +258,7 @@ SEXP rnng_ncurl(SEXP http, SEXP convert, SEXP follow, SEXP method, SEXP headers, } - if (timeout != R_NilValue) - nng_aio_set_timeout(aio, (nng_duration) Rf_asInteger(timeout)); + nng_aio_set_timeout(aio, dur); nng_http_client_transact(client, req, res, aio); nng_aio_wait(aio); if ((xc = nng_aio_result(aio))) @@ -270,7 +270,7 @@ SEXP rnng_ncurl(SEXP http, SEXP convert, SEXP follow, SEXP method, SEXP headers, code = nng_http_res_get_status(res), relo = code >= 300 && code < 400; - if (relo && LOGICAL(follow)[0]) { + if (relo && cont) { const char *location = nng_http_res_get_header(res, "Location"); if (location == NULL) goto resume; nng_url *oldurl = url;