lib: eliminate size_t casts

Add new functions in `curlx/warnless.h` for controlled type
conversions:

* curlx_uitouz, convert unsigned into to size_t (should always work)
* curlx_uztoso, convert size_t to curl_off_t, capping at CURL_OFF_T_MAX
* curlx_sztouz, convert ssize_t to size_t, return TRUE when ok
* curlx_sotouz_range, convert curl_off_t to size_t interval, capping
  values to interval bounds

Remove some unnecesary casts, convert some internal recv functions
to the "return result, have size_t* arg" pattern.

Closes #19495
This commit is contained in:
Stefan Eissing 2025-11-12 15:58:49 +01:00 committed by Daniel Stenberg
parent 78a610cb83
commit cb2bcb681f
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
13 changed files with 170 additions and 156 deletions

View file

@ -268,7 +268,7 @@ static CURLcode send_CONNECT(struct Curl_cfilter *cf,
DEBUGASSERT(blen >= nwritten); DEBUGASSERT(blen >= nwritten);
ts->nsent += nwritten; ts->nsent += nwritten;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)nwritten); Curl_debug(data, CURLINFO_HEADER_OUT, buf, nwritten);
out: out:
if(result) if(result)

View file

@ -847,7 +847,7 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
#endif #endif
} }
/* tunnel.recbuf has soft limit, any success MUST add all data */ /* tunnel.recbuf has soft limit, any success MUST add all data */
DEBUGASSERT((size_t)nwritten == len); DEBUGASSERT(nwritten == len);
return 0; return 0;
} }

View file

@ -290,3 +290,38 @@ size_t curlx_sitouz(int sinum)
# pragma warning(pop) # pragma warning(pop)
#endif #endif
} }
size_t curlx_uitouz(unsigned int uinum)
{
return (size_t)uinum;
}
size_t curlx_sotouz_range(curl_off_t sonum, size_t uzmin, size_t uzmax)
{
if(sonum < 0)
return uzmin;
#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
if(sonum > SIZE_MAX)
return uzmax;
#endif
return CURLMIN(CURLMAX((size_t)sonum, uzmin), uzmax);
}
bool curlx_sztouz(ssize_t sznum, size_t *puznum)
{
if(sznum < 0) {
*puznum = 0;
return FALSE;
}
*puznum = (size_t)sznum;
return TRUE;
}
curl_off_t curlx_uztoso(size_t uznum)
{
#if SIZEOF_SIZE_T >= SIZEOF_CURL_OFF_T
if(uznum > (size_t)CURL_OFF_T_MAX)
return CURL_OFF_T_MAX;
#endif
return (curl_off_t)uznum;
}

View file

@ -57,6 +57,18 @@ unsigned short curlx_uitous(unsigned int uinum);
size_t curlx_sitouz(int sinum); size_t curlx_sitouz(int sinum);
size_t curlx_uitouz(unsigned int uinum);
/* Convert a curl_off_t to fit into size_t interval [uzmin, uzmax].
* values outside this interval give the lower/upper bound. */
size_t curlx_sotouz_range(curl_off_t sonum, size_t uzmin, size_t uzmax);
/* Convert a size_t to curl_off_t, return CURL_OFF_T_MAX if too large. */
curl_off_t curlx_uztoso(size_t uznum);
/* Convert a ssize_t to size_t, return FALSE if negative and set 0 */
bool curlx_sztouz(ssize_t sznum, size_t *puznum);
#ifdef _WIN32 #ifdef _WIN32
#undef read #undef read
#define read(fd, buf, count) (ssize_t)_read(fd, buf, curlx_uztoui(count)) #define read(fd, buf, count) (ssize_t)_read(fd, buf, curlx_uztoui(count))

View file

@ -160,9 +160,9 @@ static CURLcode sendf(struct Curl_easy *data, const char *fmt, ...)
if(result) if(result)
break; break;
Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written); Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written);
if((size_t)bytes_written != write_len) { if(bytes_written != write_len) {
/* if not all was written at once, we must advance the pointer, decrease /* if not all was written at once, we must advance the pointer, decrease
the size left and try again! */ the size left and try again! */
write_len -= bytes_written; write_len -= bytes_written;

View file

@ -2222,9 +2222,11 @@ static CURLcode set_reader(struct Curl_easy *data, Curl_HttpReq httpreq)
result = Curl_creader_set_null(data); result = Curl_creader_set_null(data);
} }
else if(data->set.postfields) { else if(data->set.postfields) {
if(postsize > 0) size_t plen = curlx_sotouz_range(postsize, 0, SIZE_MAX);
result = Curl_creader_set_buf(data, data->set.postfields, if(plen == SIZE_MAX)
(size_t)postsize); return CURLE_OUT_OF_MEMORY;
else if(plen)
result = Curl_creader_set_buf(data, data->set.postfields, plen);
else else
result = Curl_creader_set_null(data); result = Curl_creader_set_null(data);
} }

View file

@ -45,6 +45,7 @@
#include "curlx/strparse.h" #include "curlx/strparse.h"
#include "transfer.h" #include "transfer.h"
#include "curlx/dynbuf.h" #include "curlx/dynbuf.h"
#include "curlx/warnless.h"
#include "headers.h" #include "headers.h"
/* The last 3 #include files should be in this order */ /* The last 3 #include files should be in this order */
@ -539,10 +540,12 @@ static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
* in the H1 request and we upgrade from there. This stream * in the H1 request and we upgrade from there. This stream
* is opened implicitly as #1. */ * is opened implicitly as #1. */
uint8_t binsettings[H2_BINSETTINGS_LEN]; uint8_t binsettings[H2_BINSETTINGS_LEN];
ssize_t binlen; /* length of the binsettings data */ ssize_t rclen;
size_t binlen; /* length of the binsettings data */
binlen = populate_binsettings(binsettings, data); rclen = populate_binsettings(binsettings, data);
if(binlen <= 0) {
if(!curlx_sztouz(rclen, &binlen) || !binlen) {
failf(data, "nghttp2 unexpectedly failed on pack_settings_payload"); failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
result = CURLE_FAILED_INIT; result = CURLE_FAILED_INIT;
goto out; goto out;
@ -554,7 +557,7 @@ static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf,
DEBUGASSERT(stream); DEBUGASSERT(stream);
stream->id = 1; stream->id = 1;
/* queue SETTINGS frame (again) */ /* queue SETTINGS frame (again) */
rc = nghttp2_session_upgrade2(ctx->h2, binsettings, (size_t)binlen, rc = nghttp2_session_upgrade2(ctx->h2, binsettings, binlen,
data->state.httpreq == HTTPREQ_HEAD, data->state.httpreq == HTTPREQ_HEAD,
NULL); NULL);
if(rc) { if(rc) {
@ -627,16 +630,16 @@ static CURLcode h2_process_pending_input(struct Curl_cfilter *cf,
{ {
struct cf_h2_ctx *ctx = cf->ctx; struct cf_h2_ctx *ctx = cf->ctx;
const unsigned char *buf; const unsigned char *buf;
size_t blen; size_t blen, nread;
ssize_t rv; ssize_t rv;
while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) { while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) {
rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen); rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen);
if(rv < 0) { if(!curlx_sztouz(rv, &nread)) {
failf(data, "nghttp2 recv error %zd: %s", rv, nghttp2_strerror((int)rv)); failf(data, "nghttp2 recv error %zd: %s", rv, nghttp2_strerror((int)rv));
return CURLE_HTTP2; return CURLE_HTTP2;
} }
Curl_bufq_skip(&ctx->inbufq, (size_t)rv); Curl_bufq_skip(&ctx->inbufq, nread);
if(Curl_bufq_is_empty(&ctx->inbufq)) { if(Curl_bufq_is_empty(&ctx->inbufq)) {
break; break;
} }
@ -1804,16 +1807,17 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
size_t blen; size_t blen;
struct SingleRequest *k = &data->req; struct SingleRequest *k = &data->req;
uint8_t binsettings[H2_BINSETTINGS_LEN]; uint8_t binsettings[H2_BINSETTINGS_LEN];
ssize_t binlen; /* length of the binsettings data */ ssize_t rc;
size_t binlen; /* length of the binsettings data */
binlen = populate_binsettings(binsettings, data); rc = populate_binsettings(binsettings, data);
if(binlen <= 0) { if(!curlx_sztouz(rc, &binlen) || !binlen) {
failf(data, "nghttp2 unexpectedly failed on pack_settings_payload"); failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
curlx_dyn_free(req); curlx_dyn_free(req);
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
} }
result = curlx_base64url_encode((const char *)binsettings, (size_t)binlen, result = curlx_base64url_encode((const char *)binsettings, binlen,
&base64, &blen); &base64, &blen);
if(result) { if(result) {
curlx_dyn_free(req); curlx_dyn_free(req);
@ -2173,15 +2177,16 @@ out:
return result; return result;
} }
static ssize_t cf_h2_body_send(struct Curl_cfilter *cf, static CURLcode cf_h2_body_send(struct Curl_cfilter *cf,
struct Curl_easy *data, struct Curl_easy *data,
struct h2_stream_ctx *stream, struct h2_stream_ctx *stream,
const void *buf, size_t blen, bool eos, const void *buf, size_t blen, bool eos,
CURLcode *err) size_t *pnwritten)
{ {
struct cf_h2_ctx *ctx = cf->ctx; struct cf_h2_ctx *ctx = cf->ctx;
size_t nwritten; CURLcode result;
*pnwritten = 0;
if(stream->closed) { if(stream->closed) {
if(stream->resp_hds_complete) { if(stream->resp_hds_complete) {
/* Server decided to close the stream after having sent us a final /* Server decided to close the stream after having sent us a final
@ -2193,31 +2198,29 @@ static ssize_t cf_h2_body_send(struct Curl_cfilter *cf,
"on closed stream with response", stream->id); "on closed stream with response", stream->id);
if(eos) if(eos)
stream->body_eos = TRUE; stream->body_eos = TRUE;
*err = CURLE_OK; *pnwritten = blen;
return (ssize_t)blen; return CURLE_OK;
} }
/* Server closed before we got a response, this is an error */ /* Server closed before we got a response, this is an error */
infof(data, "stream %u closed", stream->id); infof(data, "stream %u closed", stream->id);
*err = CURLE_SEND_ERROR; return CURLE_SEND_ERROR;
return -1;
} }
*err = Curl_bufq_write(&stream->sendbuf, buf, blen, &nwritten); result = Curl_bufq_write(&stream->sendbuf, buf, blen, pnwritten);
if(*err) if(result)
return -1; return result;
if(eos && (blen == nwritten)) if(eos && (blen == *pnwritten))
stream->body_eos = TRUE; stream->body_eos = TRUE;
if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) { if(eos || !Curl_bufq_is_empty(&stream->sendbuf)) {
/* resume the potentially suspended stream */ /* resume the potentially suspended stream */
int rv = nghttp2_session_resume_data(ctx->h2, stream->id); int rv = nghttp2_session_resume_data(ctx->h2, stream->id);
if(nghttp2_is_fatal(rv)) { if(nghttp2_is_fatal(rv))
*err = CURLE_SEND_ERROR; return CURLE_SEND_ERROR;
return -1;
}
} }
return (ssize_t)nwritten;
return CURLE_OK;
} }
static CURLcode h2_submit(struct h2_stream_ctx **pstream, static CURLcode h2_submit(struct h2_stream_ctx **pstream,
@ -2234,7 +2237,8 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream,
nghttp2_data_provider data_prd; nghttp2_data_provider data_prd;
int32_t stream_id; int32_t stream_id;
nghttp2_priority_spec pri_spec; nghttp2_priority_spec pri_spec;
ssize_t nwritten; ssize_t rc;
size_t nwritten;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
*pnwritten = 0; *pnwritten = 0;
@ -2244,10 +2248,10 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream,
if(result) if(result)
goto out; goto out;
nwritten = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result); rc = Curl_h1_req_parse_read(&stream->h1, buf, len, NULL, 0, &result);
if(nwritten < 0) if(!curlx_sztouz(rc, &nwritten))
goto out; goto out;
*pnwritten = (size_t)nwritten; *pnwritten = nwritten;
if(!stream->h1.done) { if(!stream->h1.done) {
/* need more data */ /* need more data */
goto out; goto out;
@ -2321,8 +2325,9 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream,
bodylen = len - *pnwritten; bodylen = len - *pnwritten;
if(bodylen || eos) { if(bodylen || eos) {
ssize_t n = cf_h2_body_send(cf, data, stream, body, bodylen, eos, &result); size_t n;
if(n >= 0) result = cf_h2_body_send(cf, data, stream, body, bodylen, eos, &n);
if(!result)
*pnwritten += n; *pnwritten += n;
else if(result == CURLE_AGAIN) else if(result == CURLE_AGAIN)
result = CURLE_OK; result = CURLE_OK;
@ -2347,7 +2352,6 @@ static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
struct cf_h2_ctx *ctx = cf->ctx; struct cf_h2_ctx *ctx = cf->ctx;
struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data); struct h2_stream_ctx *stream = H2_STREAM_CTX(ctx, data);
struct cf_call_data save; struct cf_call_data save;
ssize_t nwritten;
CURLcode result = CURLE_OK, r2; CURLcode result = CURLE_OK, r2;
CF_DATA_SAVE(save, cf, data); CF_DATA_SAVE(save, cf, data);
@ -2364,21 +2368,19 @@ static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
* being able to flush stream->sendbuf. Make a 0-length write * being able to flush stream->sendbuf. Make a 0-length write
* to trigger flushing again. * to trigger flushing again.
* If this works, we report to have written `len` bytes. */ * If this works, we report to have written `len` bytes. */
size_t n;
DEBUGASSERT(eos); DEBUGASSERT(eos);
nwritten = cf_h2_body_send(cf, data, stream, buf, 0, eos, &result); result = cf_h2_body_send(cf, data, stream, buf, 0, eos, &n);
CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %zd, %d, eos=%d", CURL_TRC_CF(data, cf, "[%d] cf_body_send last CHUNK -> %d, %zu, eos=%d",
stream->id, nwritten, result, eos); stream->id, result, n, eos);
if(nwritten < 0) { if(result)
goto out; goto out;
}
*pnwritten = len; *pnwritten = len;
} }
else { else {
nwritten = cf_h2_body_send(cf, data, stream, buf, len, eos, &result); result = cf_h2_body_send(cf, data, stream, buf, len, eos, pnwritten);
CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %zd, %d, eos=%d", CURL_TRC_CF(data, cf, "[%d] cf_body_send(len=%zu) -> %d, %zu, eos=%d",
stream->id, len, nwritten, result, eos); stream->id, len, result, *pnwritten, eos);
if(nwritten >= 0)
*pnwritten = (size_t)nwritten;
} }
/* Call the nghttp2 send loop and flush to write ALL buffered data, /* Call the nghttp2 send loop and flush to write ALL buffered data,

View file

@ -3879,10 +3879,10 @@ CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data,
} }
if(!data->multi->xfer_buf) { if(!data->multi->xfer_buf) {
data->multi->xfer_buf = malloc((size_t)data->set.buffer_size); data->multi->xfer_buf = malloc(curlx_uitouz(data->set.buffer_size));
if(!data->multi->xfer_buf) { if(!data->multi->xfer_buf) {
failf(data, "could not allocate xfer_buf of %zu bytes", failf(data, "could not allocate xfer_buf of %u bytes",
(size_t)data->set.buffer_size); data->set.buffer_size);
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
data->multi->xfer_buf_len = data->set.buffer_size; data->multi->xfer_buf_len = data->set.buffer_size;
@ -3932,10 +3932,11 @@ CURLcode Curl_multi_xfer_ulbuf_borrow(struct Curl_easy *data,
} }
if(!data->multi->xfer_ulbuf) { if(!data->multi->xfer_ulbuf) {
data->multi->xfer_ulbuf = malloc((size_t)data->set.upload_buffer_size); data->multi->xfer_ulbuf =
malloc(curlx_uitouz(data->set.upload_buffer_size));
if(!data->multi->xfer_ulbuf) { if(!data->multi->xfer_ulbuf) {
failf(data, "could not allocate xfer_ulbuf of %zu bytes", failf(data, "could not allocate xfer_ulbuf of %u bytes",
(size_t)data->set.upload_buffer_size); data->set.upload_buffer_size);
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
data->multi->xfer_ulbuf_len = data->set.upload_buffer_size; data->multi->xfer_ulbuf_len = data->set.upload_buffer_size;

View file

@ -209,20 +209,7 @@ static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit)
{ {
if(limit != -1) { if(limit != -1) {
/* How much more are we allowed to write? */ /* How much more are we allowed to write? */
curl_off_t remain_diff; return curlx_sotouz_range(limit - data->req.bytecount, 0, SIZE_MAX);
remain_diff = limit - data->req.bytecount;
if(remain_diff < 0) {
/* already written too much! */
return 0;
}
#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T
else if(remain_diff > SSIZE_MAX) {
return SIZE_MAX;
}
#endif
else {
return (size_t)remain_diff;
}
} }
return SIZE_MAX; return SIZE_MAX;
} }
@ -678,11 +665,7 @@ static CURLcode cr_in_read(struct Curl_easy *data,
} }
/* respect length limitations */ /* respect length limitations */
if(ctx->total_len >= 0) { if(ctx->total_len >= 0) {
curl_off_t remain = ctx->total_len - ctx->read_len; blen = curlx_sotouz_range(ctx->total_len - ctx->read_len, 0, blen);
if(remain <= 0)
blen = 0;
else if(remain < (curl_off_t)blen)
blen = (size_t)remain;
} }
nread = 0; nread = 0;
if(ctx->read_cb && blen) { if(ctx->read_cb && blen) {
@ -1363,9 +1346,9 @@ static CURLcode cr_buf_resume_from(struct Curl_easy *data,
/* already started reading? */ /* already started reading? */
if(ctx->index) if(ctx->index)
return CURLE_READ_ERROR; return CURLE_READ_ERROR;
if(offset <= 0) boffset = curlx_sotouz_range(offset, 0, SIZE_MAX);
if(!boffset)
return CURLE_OK; return CURLE_OK;
boffset = (size_t)offset;
if(boffset > ctx->blen) if(boffset > ctx->blen)
return CURLE_READ_ERROR; return CURLE_READ_ERROR;

View file

@ -1689,22 +1689,20 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
if(!ptr || s->postfieldsize == -1) if(!ptr || s->postfieldsize == -1)
result = Curl_setstropt(&s->str[STRING_COPYPOSTFIELDS], ptr); result = Curl_setstropt(&s->str[STRING_COPYPOSTFIELDS], ptr);
else { else {
size_t pflen;
if(s->postfieldsize < 0) if(s->postfieldsize < 0)
return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_BAD_FUNCTION_ARGUMENT;
#if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T pflen = curlx_sotouz_range(s->postfieldsize, 0, SIZE_MAX);
/* if(pflen == SIZE_MAX)
* Check that requested length does not overflow the size_t type.
*/
else if(s->postfieldsize > SIZE_MAX)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
#endif
else { else {
/* Allocate even when size == 0. This satisfies the need of possible /* Allocate even when size == 0. This satisfies the need of possible
later address compare to detect the COPYPOSTFIELDS mode, and to later address compare to detect the COPYPOSTFIELDS mode, and to
mark that postfields is used rather than read function or form mark that postfields is used rather than read function or form
data. data.
*/ */
char *p = Curl_memdup0(ptr, (size_t)s->postfieldsize); char *p = Curl_memdup0(ptr, pflen);
if(!p) if(!p)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
else { else {

View file

@ -82,6 +82,7 @@
#include "hsts.h" #include "hsts.h"
#include "setopt.h" #include "setopt.h"
#include "headers.h" #include "headers.h"
#include "curlx/warnless.h"
/* The last 2 #include files should be in this order */ /* The last 2 #include files should be in this order */
#include "curl_memory.h" #include "curl_memory.h"
@ -189,53 +190,44 @@ CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done)
* @param err error code in case of -1 return * @param err error code in case of -1 return
* @return number of bytes read or -1 for error * @return number of bytes read or -1 for error
*/ */
static ssize_t xfer_recv_resp(struct Curl_easy *data, static CURLcode xfer_recv_resp(struct Curl_easy *data,
char *buf, size_t blen, char *buf, size_t blen,
bool eos_reliable, bool eos_reliable,
CURLcode *err) size_t *pnread)
{ {
size_t nread; CURLcode result;
DEBUGASSERT(blen > 0); DEBUGASSERT(blen > 0);
*pnread = 0;
/* If we are reading BODY data and the connection does NOT handle EOF /* If we are reading BODY data and the connection does NOT handle EOF
* and we know the size of the BODY data, limit the read amount */ * and we know the size of the BODY data, limit the read amount */
if(!eos_reliable && !data->req.header && data->req.size != -1) { if(!eos_reliable && !data->req.header && data->req.size != -1) {
curl_off_t totalleft = data->req.size - data->req.bytecount; blen = curlx_sotouz_range(data->req.size - data->req.bytecount, 0, blen);
if(totalleft <= 0)
blen = 0;
else if(totalleft < (curl_off_t)blen)
blen = (size_t)totalleft;
} }
else if(xfer_recv_shutdown_started(data)) { else if(xfer_recv_shutdown_started(data)) {
/* we already received everything. Do not try more. */ /* we already received everything. Do not try more. */
blen = 0; blen = 0;
} }
if(!blen) { if(blen) {
/* want nothing more */ result = Curl_xfer_recv(data, buf, blen, pnread);
*err = CURLE_OK; if(result)
nread = 0; return result;
}
else {
*err = Curl_xfer_recv(data, buf, blen, &nread);
} }
if(*err) if(*pnread == 0) {
return -1;
if(nread == 0) {
if(data->req.shutdown) { if(data->req.shutdown) {
bool done; bool done;
*err = xfer_recv_shutdown(data, &done); result = xfer_recv_shutdown(data, &done);
if(*err) if(result)
return -1; return result;
if(!done) { if(!done) {
*err = CURLE_AGAIN; return CURLE_AGAIN;
return -1;
} }
} }
DEBUGF(infof(data, "sendrecv_dl: we are done")); DEBUGF(infof(data, "sendrecv_dl: we are done"));
} }
return (ssize_t)nread; return CURLE_OK;
} }
/* /*
@ -264,7 +256,6 @@ static CURLcode sendrecv_dl(struct Curl_easy *data,
read or we get a CURLE_AGAIN */ read or we get a CURLE_AGAIN */
do { do {
size_t bytestoread; size_t bytestoread;
ssize_t nread;
if(!is_multiplex) { if(!is_multiplex) {
/* Multiplexed connection have inherent handling of EOF and we do not /* Multiplexed connection have inherent handling of EOF and we do not
@ -288,9 +279,9 @@ static CURLcode sendrecv_dl(struct Curl_easy *data,
} }
rcvd_eagain = FALSE; rcvd_eagain = FALSE;
nread = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &result); result = xfer_recv_resp(data, buf, bytestoread, is_multiplex, &blen);
if(nread < 0) { if(result) {
if(CURLE_AGAIN != result) if(result != CURLE_AGAIN)
goto out; /* real error */ goto out; /* real error */
rcvd_eagain = TRUE; rcvd_eagain = TRUE;
result = CURLE_OK; result = CURLE_OK;
@ -298,7 +289,7 @@ static CURLcode sendrecv_dl(struct Curl_easy *data,
!data->req.resp_trailer) { !data->req.resp_trailer) {
DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, " DEBUGF(infof(data, "EAGAIN, download done, no trailer announced, "
"not waiting for EOS")); "not waiting for EOS"));
nread = 0; blen = 0;
/* continue as if we received the EOS */ /* continue as if we received the EOS */
} }
else else
@ -306,7 +297,6 @@ static CURLcode sendrecv_dl(struct Curl_easy *data,
} }
/* We only get a 0-length receive at the end of the response */ /* We only get a 0-length receive at the end of the response */
blen = (size_t)nread;
is_eos = (blen == 0); is_eos = (blen == 0);
if(!blen && (conn->recv[FIRSTSOCKET] == Curl_cf_recv)) { if(!blen && (conn->recv[FIRSTSOCKET] == Curl_cf_recv)) {
@ -899,8 +889,8 @@ CURLcode Curl_xfer_recv(struct Curl_easy *data,
DEBUGASSERT(data->conn); DEBUGASSERT(data->conn);
DEBUGASSERT(data->set.buffer_size > 0); DEBUGASSERT(data->set.buffer_size > 0);
if((size_t)data->set.buffer_size < blen) if(curlx_uitouz(data->set.buffer_size) < blen)
blen = (size_t)data->set.buffer_size; blen = curlx_uitouz(data->set.buffer_size);
return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd); return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd);
} }

View file

@ -1320,32 +1320,25 @@ static CURLcode init_ngh3_conn(struct Curl_cfilter *cf,
return CURLE_OK; return CURLE_OK;
} }
static ssize_t recv_closed_stream(struct Curl_cfilter *cf, static CURLcode recv_closed_stream(struct Curl_cfilter *cf,
struct Curl_easy *data, struct Curl_easy *data,
struct h3_stream_ctx *stream, struct h3_stream_ctx *stream,
CURLcode *err) size_t *pnread)
{ {
ssize_t nread = -1;
(void)cf; (void)cf;
*pnread = 0;
if(stream->reset) { if(stream->reset) {
failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id); failf(data, "HTTP/3 stream %" FMT_PRId64 " reset by server", stream->id);
*err = data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3; return data->req.bytecount ? CURLE_PARTIAL_FILE : CURLE_HTTP3;
goto out;
} }
else if(!stream->resp_hds_complete) { else if(!stream->resp_hds_complete) {
failf(data, failf(data,
"HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before " "HTTP/3 stream %" FMT_PRId64 " was closed cleanly, but before "
"getting all response header fields, treated as error", "getting all response header fields, treated as error",
stream->id); stream->id);
*err = CURLE_HTTP3; return CURLE_HTTP3;
goto out;
} }
*err = CURLE_OK; return CURLE_OK;
nread = 0;
out:
return nread;
} }
/* incoming data frames on the h3 stream */ /* incoming data frames on the h3 stream */
@ -1393,9 +1386,7 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
goto out; goto out;
} }
else if(stream->closed) { else if(stream->closed) {
ssize_t nread = recv_closed_stream(cf, data, stream, &result); result = recv_closed_stream(cf, data, stream, pnread);
if(nread > 0)
*pnread = (size_t)nread;
goto out; goto out;
} }
result = CURLE_AGAIN; result = CURLE_AGAIN;

View file

@ -41,6 +41,7 @@
#include "select.h" #include "select.h"
#include "curlx/nonblock.h" #include "curlx/nonblock.h"
#include "curlx/strparse.h" #include "curlx/strparse.h"
#include "curlx/warnless.h"
/* The last 2 #include files should be in this order */ /* The last 2 #include files should be in this order */
#include "curl_memory.h" #include "curl_memory.h"
@ -489,12 +490,13 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec,
size_t inlen; size_t inlen;
size_t nwritten; size_t nwritten;
CURLcode result; CURLcode result;
curl_off_t remain = dec->payload_len - dec->payload_offset; size_t remain = curlx_sotouz_range(dec->payload_len - dec->payload_offset,
0, SIZE_MAX);
(void)data; (void)data;
while(remain && Curl_bufq_peek(inraw, &inbuf, &inlen)) { while(remain && Curl_bufq_peek(inraw, &inbuf, &inlen)) {
if((curl_off_t)inlen > remain) if(inlen > remain)
inlen = (size_t)remain; inlen = remain;
result = write_cb(inbuf, inlen, dec->frame_age, dec->frame_flags, result = write_cb(inbuf, inlen, dec->frame_age, dec->frame_flags,
dec->payload_offset, dec->payload_len, dec->payload_offset, dec->payload_len,
write_ctx, &nwritten); write_ctx, &nwritten);
@ -502,9 +504,10 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec,
return result; return result;
Curl_bufq_skip(inraw, nwritten); Curl_bufq_skip(inraw, nwritten);
dec->payload_offset += nwritten; dec->payload_offset += nwritten;
remain = dec->payload_len - dec->payload_offset; remain = curlx_sotouz_range(dec->payload_len - dec->payload_offset,
CURL_TRC_WS(data, "passed %zu bytes payload, %" 0, SIZE_MAX);
FMT_OFF_T " remain", nwritten, remain); CURL_TRC_WS(data, "passed %zu bytes payload, %zu remain",
nwritten, remain);
} }
return remain ? CURLE_AGAIN : CURLE_OK; return remain ? CURLE_AGAIN : CURLE_OK;
@ -651,16 +654,13 @@ static curl_off_t ws_payload_remain(curl_off_t payload_total,
curl_off_t payload_offset, curl_off_t payload_offset,
size_t payload_buffered) size_t payload_buffered)
{ {
curl_off_t remain = payload_total - payload_offset; curl_off_t buffered, remain = payload_total - payload_offset;
if((payload_total < 0) || (payload_offset < 0) || (remain < 0)) if((payload_total < 0) || (payload_offset < 0) || (remain < 0))
return -1; return -1;
#if SIZEOF_SIZE_T >= SIZEOF_CURL_OFF_T buffered = curlx_uztoso(payload_buffered);
if(payload_buffered > (size_t)CURL_OFF_T_MAX) if(remain < buffered)
return -1; return -1;
#endif return remain - buffered;
if(remain < (curl_off_t)payload_buffered)
return -1;
return remain - (curl_off_t)payload_buffered;
} }
static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen, static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen,
@ -947,7 +947,7 @@ static CURLcode ws_enc_write_payload(struct ws_encoder *enc,
struct bufq *out, size_t *pnwritten) struct bufq *out, size_t *pnwritten)
{ {
CURLcode result; CURLcode result;
size_t i, len, n; size_t i, len, n, remain;
*pnwritten = 0; *pnwritten = 0;
if(Curl_bufq_is_full(out)) if(Curl_bufq_is_full(out))
@ -955,8 +955,9 @@ static CURLcode ws_enc_write_payload(struct ws_encoder *enc,
/* not the most performant way to do this */ /* not the most performant way to do this */
len = buflen; len = buflen;
if((curl_off_t)len > enc->payload_remain) remain = curlx_sotouz_range(enc->payload_remain, 0, SIZE_MAX);
len = (size_t)enc->payload_remain; if(remain < len)
len = remain;
for(i = 0; i < len; ++i) { for(i = 0; i < len; ++i) {
unsigned char c = buf[i] ^ enc->mask[enc->xori]; unsigned char c = buf[i] ^ enc->mask[enc->xori];
@ -1167,8 +1168,7 @@ static CURLcode cr_ws_read(struct Curl_easy *data,
if(ws->enc.payload_remain) { if(ws->enc.payload_remain) {
CURL_TRC_WS(data, "current frame, %" FMT_OFF_T " remaining", CURL_TRC_WS(data, "current frame, %" FMT_OFF_T " remaining",
ws->enc.payload_remain); ws->enc.payload_remain);
if(ws->enc.payload_remain < (curl_off_t)blen) blen = curlx_sotouz_range(ws->enc.payload_remain, 0, blen);
blen = (size_t)ws->enc.payload_remain;
} }
result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos); result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos);