Skip to content

Commit

Permalink
strparse: switch to curl_off_t as base data type
Browse files Browse the repository at this point in the history
- add hex and octal parsers to the Curl_str_* family
- make curlx_strtoofft use these parsers
- remove all use of strtol() and strtoul() in library code
- generally use Curl_str_* more than strtoofft, for stricter parsing
- supports 64-bit universally, instead of 'long' which differs in size
  between platforms

Extended the unit test 1664 to verify hex and octal parsing.

Closes curl#16336
  • Loading branch information
bagder committed Feb 15, 2025
1 parent 876db10 commit b4538ec
Show file tree
Hide file tree
Showing 46 changed files with 537 additions and 496 deletions.
2 changes: 2 additions & 0 deletions lib/.checksrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ banfunc strncpy
banfunc sscanf
banfunc snprintf
banfunc vsnprint
banfunc strtoul
banfunc strtol
1 change: 1 addition & 0 deletions lib/Makefile.inc
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ LIB_CFILES = \
splay.c \
strcase.c \
strdup.c \
strequal.c \
strerror.c \
strparse.c \
strtok.c \
Expand Down
23 changes: 12 additions & 11 deletions lib/altsvc.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,10 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line)
struct Curl_str srcalpn;
struct Curl_str dstalpn;
struct Curl_str date;
size_t srcport;
size_t dstport;
size_t persist;
size_t prio;
curl_off_t srcport;
curl_off_t dstport;
curl_off_t persist;
curl_off_t prio;

if(Curl_str_word(&line, &srcalpn, MAX_ALTSVC_ALPNLEN) ||
Curl_str_singlespace(&line) ||
Expand Down Expand Up @@ -193,8 +193,8 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line)
memcpy(dbuf, date.str, date.len);
dbuf[date.len] = 0;
expires = Curl_getdate_capped(dbuf);
as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, srcport,
dstport);
as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn,
(size_t)srcport, (size_t)dstport);
if(as) {
as->expires = expires;
as->prio = 0; /* not supported to just set zero */
Expand Down Expand Up @@ -465,10 +465,11 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
return */
static time_t altsvc_debugtime(void *unused)
{
char *timestr = getenv("CURL_TIME");
const char *timestr = getenv("CURL_TIME");
(void)unused;
if(timestr) {
long val = strtol(timestr, NULL, 10);
curl_off_t val;
Curl_str_number(&timestr, &val, TIME_T_MAX);
return (time_t)val;
}
return time(NULL);
Expand Down Expand Up @@ -528,7 +529,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
size_t dstlen = 0; /* destination hostname length */
const char *value_ptr;
char option[32];
size_t num;
curl_off_t num;
bool quoted = FALSE;
time_t maxage = 24 * 3600; /* default is 24 hours */
bool persist = FALSE;
Expand Down Expand Up @@ -566,7 +567,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
dstlen = strlen(srchost);
}
if(*p == ':') {
size_t port = 0;
curl_off_t port = 0;
p++;
if(Curl_str_number(&p, &port, 0xffff) || (*p != '\"')) {
infof(data, "Unknown alt-svc port number, ignoring.");
Expand Down Expand Up @@ -617,7 +618,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
while(*p && !ISBLANK(*p) && *p!= ';' && *p != ',')
p++;
}
if(!Curl_str_number(&value_ptr, &num, SIZE_T_MAX)) {
if(!Curl_str_number(&value_ptr, &num, TIME_T_MAX)) {
if(strcasecompare("ma", option))
maxage = (time_t)num;
else if(strcasecompare("persist", option) && (num == 1))
Expand Down
20 changes: 10 additions & 10 deletions lib/cf-socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
Curl_printable_address. The latter returns only numeric scope
IDs and the former returns none at all. So the scope ID, if
present, is known to be numeric */
size_t scope_id;
curl_off_t scope_id;
if(Curl_str_number((const char **)&scope_ptr, &scope_id, UINT_MAX))
return CURLE_UNSUPPORTED_PROTOCOL;
si6->sin6_scope_id = (unsigned int)scope_id;
Expand Down Expand Up @@ -974,28 +974,28 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,

#ifdef DEBUGBUILD
{
char *p = getenv("CURL_DBG_SOCK_WBLOCK");
const char *p = getenv("CURL_DBG_SOCK_WBLOCK");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0 && l <= 100)
curl_off_t l;
if(!Curl_str_number(&p, &l, 100))
ctx->wblock_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_WPARTIAL");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0 && l <= 100)
curl_off_t l;
if(!Curl_str_number(&p, &l, 100))
ctx->wpartial_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_RBLOCK");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0 && l <= 100)
curl_off_t l;
if(!Curl_str_number(&p, &l, 100))
ctx->rblock_percent = (int)l;
}
p = getenv("CURL_DBG_SOCK_RMAX");
if(p) {
long l = strtol(p, NULL, 10);
if(l >= 0)
curl_off_t l;
if(!Curl_str_number(&p, &l, SIZE_T_MAX))
ctx->recv_max = (size_t)l;
}
}
Expand Down
9 changes: 5 additions & 4 deletions lib/cfilters.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include "progress.h"
#include "select.h"
#include "warnless.h"
#include "strparse.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
Expand Down Expand Up @@ -883,11 +884,11 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
{
/* Allow debug builds to override this logic to force short sends
*/
char *p = getenv("CURL_SMALLSENDS");
const char *p = getenv("CURL_SMALLSENDS");
if(p) {
size_t altsize = (size_t)strtoul(p, NULL, 10);
if(altsize)
write_len = CURLMIN(write_len, altsize);
curl_off_t altsize;
if(!Curl_str_number(&p, &altsize, SIZE_T_MAX))
write_len = CURLMIN(write_len, (size_t)altsize);
}
}
#endif
Expand Down
7 changes: 4 additions & 3 deletions lib/conncache.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include "connect.h"
#include "select.h"
#include "strcase.h"
#include "strparse.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
Expand Down Expand Up @@ -682,10 +683,10 @@ static void cpool_close_and_destroy_all(struct cpool *cpool)
/* Just for testing, run graceful shutdown */
#ifdef DEBUGBUILD
{
char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
const char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
if(p) {
long l = strtol(p, NULL, 10);
if(l > 0 && l < INT_MAX)
curl_off_t l;
if(!Curl_str_number(&p, &l, INT_MAX))
timeout_ms = (int)l;
}
}
Expand Down
31 changes: 12 additions & 19 deletions lib/cookie.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ Example set of cookies:
#include "sendf.h"
#include "slist.h"
#include "share.h"
#include "strtoofft.h"
#include "strcase.h"
#include "curl_get_line.h"
#include "curl_memrchr.h"
Expand All @@ -89,6 +88,7 @@ Example set of cookies:
#include "fopen.h"
#include "strdup.h"
#include "llist.h"
#include "strparse.h"

/* The last 3 #include files should be in this order */
#include "curl_printf.h"
Expand Down Expand Up @@ -708,21 +708,22 @@ parse_cookie_header(struct Curl_easy *data,
* client should discard the cookie. A value of zero means the
* cookie should be discarded immediately.
*/
CURLofft offt;
int rc;
const char *maxage = valuep;
offt = curlx_strtoofft((*maxage == '\"') ?
&maxage[1] : &maxage[0], NULL, 10,
&co->expires);
switch(offt) {
case CURL_OFFT_FLOW:
if(*maxage == '\"')
maxage++;
rc = Curl_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);

switch(rc) {
case STRE_OVERFLOW:
/* overflow, used max value */
co->expires = CURL_OFF_T_MAX;
break;
case CURL_OFFT_INVAL:
default:
/* negative or otherwise bad, expire */
co->expires = 1;
break;
case CURL_OFFT_OK:
case STRE_OK:
if(!co->expires)
/* already expired */
co->expires = 1;
Expand Down Expand Up @@ -915,16 +916,8 @@ parse_netscape(struct Cookie *co,
}
break;
case 4:
{
char *endp;
const char *p;
/* make sure curlx_strtoofft won't read past the current field */
for(p = ptr; p < &ptr[len] && ISDIGIT(*p); ++p)
;
if(p == ptr || p != &ptr[len] ||
curlx_strtoofft(ptr, &endp, 10, &co->expires) || endp != &ptr[len])
return CERR_RANGE;
}
if(Curl_str_number(&ptr, &co->expires, CURL_OFF_T_MAX))
return CERR_RANGE;
break;
case 5:
co->name = Curl_memdup0(ptr, len);
Expand Down
1 change: 1 addition & 0 deletions lib/curl_ctype.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#define ISCNTRL(x) (ISLOWCNTRL(x) || IS7F(x))
#define ISALPHA(x) (ISLOWER(x) || ISUPPER(x))
#define ISXDIGIT(x) (ISDIGIT(x) || ISLOWHEXALHA(x) || ISUPHEXALHA(x))
#define ISODIGIT(x) (((x) >= '0') && ((x) <= '7'))
#define ISALNUM(x) (ISDIGIT(x) || ISLOWER(x) || ISUPPER(x))
#define ISUPPER(x) (((x) >= 'A') && ((x) <= 'Z'))
#define ISLOWER(x) (((x) >= 'a') && ((x) <= 'z'))
Expand Down
33 changes: 17 additions & 16 deletions lib/curl_range.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
#include <curl/curl.h>
#include "curl_range.h"
#include "sendf.h"
#include "strtoofft.h"
#include "strparse.h"

/* Only include this function if one or more of FTP, FILE are enabled. */
#if !defined(CURL_DISABLE_FTP) || !defined(CURL_DISABLE_FILE)
Expand All @@ -37,28 +37,29 @@
*/
CURLcode Curl_range(struct Curl_easy *data)
{
curl_off_t from, to;
char *ptr;
char *ptr2;

if(data->state.use_range && data->state.range) {
CURLofft from_t;
CURLofft to_t;
from_t = curlx_strtoofft(data->state.range, &ptr, 10, &from);
if(from_t == CURL_OFFT_FLOW)
return CURLE_RANGE_ERROR;
while(*ptr && (ISBLANK(*ptr) || (*ptr == '-')))
ptr++;
to_t = curlx_strtoofft(ptr, &ptr2, 10, &to);
if(to_t == CURL_OFFT_FLOW)
curl_off_t from, to;
bool first_num = TRUE;
const char *p = data->state.range;
if(Curl_str_number(&p, &from, CURL_OFF_T_MAX))
first_num = FALSE;

if(Curl_str_single(&p, '-'))
/* no leading dash or after the first number is an error */
return CURLE_RANGE_ERROR;
if((to_t == CURL_OFFT_INVAL) && !from_t) {

if(Curl_str_number(&p, &to, CURL_OFF_T_MAX)) {
/* no second number */
/* X - */
data->state.resume_from = from;
DEBUGF(infof(data, "RANGE %" FMT_OFF_T " to end of file", from));
}
else if((from_t == CURL_OFFT_INVAL) && !to_t) {
else if(!first_num) {
/* -Y */
if(!to)
/* "-0" is just wrong */
return CURLE_RANGE_ERROR;

data->req.maxdownload = to;
data->state.resume_from = -to;
DEBUGF(infof(data, "RANGE the last %" FMT_OFF_T " bytes", to));
Expand Down
Loading

0 comments on commit b4538ec

Please sign in to comment.