mqtt: convert sendleftovers to dynbuf

Avoid frequent strdups/free calls, including the double-free risk.

Reported-by: Ronald Crane
Closes #16823
This commit is contained in:
Daniel Stenberg 2025-03-24 11:46:34 +01:00
parent 38b94c80f3
commit b2078c0e1c
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
3 changed files with 22 additions and 25 deletions

View file

@ -97,5 +97,6 @@ char *Curl_dyn_take(struct dynbuf *s, size_t *plen);
#define DYN_PINGPPONG_CMD (64*1024)
#define DYN_IMAP_CMD (64*1024)
#define DYN_MQTT_RECV (64*1024)
#define DYN_MQTT_SEND 0xFFFFFFF
#define DYN_CRLFILE_SIZE (400*1024*1024) /* 400mb */
#endif

View file

@ -112,6 +112,7 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data,
if(!mq)
return CURLE_OUT_OF_MEMORY;
Curl_dyn_init(&mq->recvbuf, DYN_MQTT_RECV);
Curl_dyn_init(&mq->sendbuf, DYN_MQTT_SEND);
data->req.p.mqtt = mq;
return CURLE_OK;
}
@ -119,25 +120,24 @@ static CURLcode mqtt_setup_conn(struct Curl_easy *data,
static CURLcode mqtt_send(struct Curl_easy *data,
const char *buf, size_t len)
{
CURLcode result = CURLE_OK;
struct MQTT *mq = data->req.p.mqtt;
size_t n;
result = Curl_xfer_send(data, buf, len, FALSE, &n);
CURLcode result = Curl_xfer_send(data, buf, len, FALSE, &n);
if(result)
return result;
Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
if(len != n) {
size_t nsend = len - n;
char *sendleftovers = Curl_memdup(&buf[n], nsend);
if(!sendleftovers)
return CURLE_OUT_OF_MEMORY;
mq->sendleftovers = sendleftovers;
mq->nsend = nsend;
}
else {
mq->sendleftovers = NULL;
mq->nsend = 0;
if(Curl_dyn_len(&mq->sendbuf)) {
DEBUGASSERT(Curl_dyn_len(&mq->sendbuf) >= nsend);
result = Curl_dyn_tail(&mq->sendbuf, nsend); /* keep this much */
}
else {
result = Curl_dyn_addn(&mq->sendbuf, &buf[n], nsend);
}
}
else
Curl_dyn_reset(&mq->sendbuf);
return result;
}
@ -352,7 +352,7 @@ static CURLcode mqtt_disconnect(struct Curl_easy *data)
CURLcode result = CURLE_OK;
struct MQTT *mq = data->req.p.mqtt;
result = mqtt_send(data, "\xe0\x00", 2);
Curl_safefree(mq->sendleftovers);
Curl_dyn_free(&mq->sendbuf);
Curl_dyn_free(&mq->recvbuf);
return result;
}
@ -732,7 +732,7 @@ static CURLcode mqtt_done(struct Curl_easy *data,
struct MQTT *mq = data->req.p.mqtt;
(void)status;
(void)premature;
Curl_safefree(mq->sendleftovers);
Curl_dyn_free(&mq->sendbuf);
Curl_dyn_free(&mq->recvbuf);
return CURLE_OK;
}
@ -740,19 +740,17 @@ static CURLcode mqtt_done(struct Curl_easy *data,
static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
struct mqtt_conn *mqtt = &conn->proto.mqtt;
struct mqtt_conn *mqtt = &data->conn->proto.mqtt;
struct MQTT *mq = data->req.p.mqtt;
ssize_t nread;
unsigned char recvbyte;
*done = FALSE;
if(mq->nsend) {
if(Curl_dyn_len(&mq->sendbuf)) {
/* send the remainder of an outgoing packet */
char *ptr = mq->sendleftovers;
result = mqtt_send(data, mq->sendleftovers, mq->nsend);
free(ptr);
result = mqtt_send(data, Curl_dyn_ptr(&mq->sendbuf),
Curl_dyn_len(&mq->sendbuf));
if(result)
return result;
}

View file

@ -49,15 +49,13 @@ struct mqtt_conn {
/* protocol-specific transfer-related data */
struct MQTT {
char *sendleftovers;
size_t nsend; /* size of sendleftovers */
struct dynbuf sendbuf;
/* when receiving */
size_t npacket; /* byte counter */
unsigned char firstbyte;
size_t remaining_length;
struct dynbuf recvbuf;
size_t npacket; /* byte counter */
size_t remaining_length;
unsigned char pkt_hd[4]; /* for decoding the arriving packet length */
unsigned char firstbyte;
};
#endif /* HEADER_CURL_MQTT_H */