mirror of
https://github.com/curl/curl.git
synced 2026-07-27 22:13:06 +03:00
tool: fix memory mixups
memory allocated by libcurl must be freed with curl_free() and vice versa, memory allocated by the tool itself must be freed with curlx_free(). - dynbuf: free libcurl data with curl_free() - tool_operate: make sure we get URL using the right memory - tool_operhlp: free libcurl memory with curl_free() - tool_operate: free curl_maprintf() pointer with curl_free - var: data from curlx_base64_decode needs curlx_free - tool_operate: fix memory juggling in etag handling - tool_cb_hdr: fix memory area mixups - tool_operate: another mixup in etag management - tool_cb_hdr: more memory mixup fixes - tool_cfgable.c: document some details - tool_help: show global-mem-debug in -V output Closes #21099
This commit is contained in:
parent
46d0ade086
commit
b71973c115
7 changed files with 69 additions and 28 deletions
|
|
@ -205,7 +205,7 @@ CURLcode curlx_dyn_vaddf(struct dynbuf *s, const char *fmt, va_list ap)
|
||||||
|
|
||||||
if(str) {
|
if(str) {
|
||||||
CURLcode result = dyn_nappend(s, (const unsigned char *)str, strlen(str));
|
CURLcode result = dyn_nappend(s, (const unsigned char *)str, strlen(str));
|
||||||
curlx_free(str);
|
curl_free(str);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
/* If we failed, we cleanup the whole buffer and return error */
|
/* If we failed, we cleanup the whole buffer and return error */
|
||||||
|
|
|
||||||
|
|
@ -311,12 +311,16 @@ static size_t content_disposition(const char *str, const char *end,
|
||||||
return CURL_WRITEFUNC_ERROR;
|
return CURL_WRITEFUNC_ERROR;
|
||||||
}
|
}
|
||||||
if(outs->alloc_filename)
|
if(outs->alloc_filename)
|
||||||
curlx_free(outs->filename);
|
tool_safefree(outs->filename);
|
||||||
|
|
||||||
if(per->config->output_dir) {
|
if(per->config->output_dir) {
|
||||||
outs->filename = curl_maprintf("%s/%s", per->config->output_dir,
|
char *f = curl_maprintf("%s/%s", per->config->output_dir,
|
||||||
filename);
|
filename);
|
||||||
curlx_free(filename);
|
curlx_free(filename);
|
||||||
|
if(!f)
|
||||||
|
return CURL_WRITEFUNC_ERROR;
|
||||||
|
outs->filename = curlx_strdup(f);
|
||||||
|
curl_free(f);
|
||||||
if(!outs->filename)
|
if(!outs->filename)
|
||||||
return CURL_WRITEFUNC_ERROR;
|
return CURL_WRITEFUNC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
@ -362,12 +366,16 @@ static size_t content_disposition(const char *str, const char *end,
|
||||||
return CURL_WRITEFUNC_ERROR;
|
return CURL_WRITEFUNC_ERROR;
|
||||||
}
|
}
|
||||||
if(outs->alloc_filename)
|
if(outs->alloc_filename)
|
||||||
curlx_free(outs->filename);
|
tool_safefree(outs->filename);
|
||||||
|
|
||||||
if(per->config->output_dir) {
|
if(per->config->output_dir) {
|
||||||
outs->filename = curl_maprintf("%s/%s", per->config->output_dir,
|
char *f = curl_maprintf("%s/%s", per->config->output_dir,
|
||||||
filename);
|
filename);
|
||||||
curlx_free(filename);
|
curlx_free(filename);
|
||||||
|
if(!f)
|
||||||
|
return CURL_WRITEFUNC_ERROR;
|
||||||
|
outs->filename = curlx_strdup(f);
|
||||||
|
curl_free(f);
|
||||||
if(!outs->filename)
|
if(!outs->filename)
|
||||||
return CURL_WRITEFUNC_ERROR;
|
return CURL_WRITEFUNC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
@ -396,7 +404,7 @@ static size_t content_disposition(const char *str, const char *end,
|
||||||
hdrcbdata->config->show_headers) {
|
hdrcbdata->config->show_headers) {
|
||||||
/* still awaiting the Content-Disposition header, store the header in
|
/* still awaiting the Content-Disposition header, store the header in
|
||||||
memory. Since it is not null-terminated, we need an extra dance. */
|
memory. Since it is not null-terminated, we need an extra dance. */
|
||||||
char *clone = curl_maprintf("%.*s", (int)cb, str);
|
char *clone = curlx_memdup0(str, cb);
|
||||||
if(clone) {
|
if(clone) {
|
||||||
struct curl_slist *old = hdrcbdata->headlist;
|
struct curl_slist *old = hdrcbdata->headlist;
|
||||||
hdrcbdata->headlist = curl_slist_append(old, clone);
|
hdrcbdata->headlist = curl_slist_append(old, clone);
|
||||||
|
|
|
||||||
|
|
@ -219,8 +219,17 @@ void config_free(struct OperationConfig *config)
|
||||||
*
|
*
|
||||||
* The main point is to make sure that what is returned is different than what
|
* The main point is to make sure that what is returned is different than what
|
||||||
* the regular memory functions return so that mixup will trigger problems.
|
* the regular memory functions return so that mixup will trigger problems.
|
||||||
|
*
|
||||||
|
* This test setup currently only works when building with a *shared* libcurl
|
||||||
|
* and not static, as in the latter case the tool and the library share some of
|
||||||
|
* the functions in incompatible ways.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code appends this extra chunk of memory in front of every allocation
|
||||||
|
* done by libcurl with the only purpose to cause trouble when using the wrong
|
||||||
|
* free function on memory.
|
||||||
|
*/
|
||||||
struct extramem {
|
struct extramem {
|
||||||
size_t extra;
|
size_t extra;
|
||||||
union {
|
union {
|
||||||
|
|
@ -254,18 +263,17 @@ static void *custom_malloc(size_t wanted_size)
|
||||||
static char *custom_strdup(const char *ptr)
|
static char *custom_strdup(const char *ptr)
|
||||||
{
|
{
|
||||||
struct extramem *m;
|
struct extramem *m;
|
||||||
size_t size = strlen(ptr) + 1;
|
size_t len = strlen(ptr);
|
||||||
size_t sz = size + sizeof(struct extramem);
|
size_t sz = len + sizeof(struct extramem);
|
||||||
m = curlx_malloc(sz);
|
m = curlx_malloc(sz);
|
||||||
if(m) {
|
if(m) {
|
||||||
char *p = (char *)m->mem;
|
char *p = (char *)m->mem;
|
||||||
/* since strcpy is banned, we do memcpy */
|
/* since strcpy is banned, we do memcpy */
|
||||||
memcpy(p, ptr, sz);
|
memcpy(p, ptr, len);
|
||||||
p[sz] = 0;
|
p[len] = 0;
|
||||||
return (char *)m->mem;
|
return (char *)m->mem;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *custom_realloc(void *ptr, size_t size)
|
static void *custom_realloc(void *ptr, size_t size)
|
||||||
|
|
@ -273,7 +281,8 @@ static void *custom_realloc(void *ptr, size_t size)
|
||||||
struct extramem *m = NULL;
|
struct extramem *m = NULL;
|
||||||
size_t sz = size + sizeof(struct extramem);
|
size_t sz = size + sizeof(struct extramem);
|
||||||
if(ptr)
|
if(ptr)
|
||||||
m = (void *)((char *)ptr - offsetof(struct extramem, mem));
|
/* if given a pointer, figure out the original */
|
||||||
|
ptr = (void *)((char *)ptr - offsetof(struct extramem, mem));
|
||||||
m = curlx_realloc(ptr, sz);
|
m = curlx_realloc(ptr, sz);
|
||||||
if(m)
|
if(m)
|
||||||
return m->mem;
|
return m->mem;
|
||||||
|
|
@ -315,7 +324,7 @@ CURLcode globalconf_init(void)
|
||||||
global->first = global->last = config_alloc();
|
global->first = global->last = config_alloc();
|
||||||
if(global->first) {
|
if(global->first) {
|
||||||
/* Perform the libcurl initialization */
|
/* Perform the libcurl initialization */
|
||||||
#ifdef GLOBAL_MEM
|
#ifdef CURL_DEBUG_GLOBAL_MEM
|
||||||
result = curl_global_init_mem(CURL_GLOBAL_ALL, custom_malloc, custom_free,
|
result = curl_global_init_mem(CURL_GLOBAL_ALL, custom_malloc, custom_free,
|
||||||
custom_realloc, custom_strdup,
|
custom_realloc, custom_strdup,
|
||||||
custom_calloc);
|
custom_calloc);
|
||||||
|
|
|
||||||
|
|
@ -356,6 +356,9 @@ void tool_version_info(void)
|
||||||
size_t feat_ext_count = feature_count;
|
size_t feat_ext_count = feature_count;
|
||||||
#ifdef CURL_CA_EMBED
|
#ifdef CURL_CA_EMBED
|
||||||
++feat_ext_count;
|
++feat_ext_count;
|
||||||
|
#endif
|
||||||
|
#ifdef CURL_DEBUG_GLOBAL_MEM
|
||||||
|
++feat_ext_count;
|
||||||
#endif
|
#endif
|
||||||
feat_ext = curlx_malloc(sizeof(*feature_names) * (feat_ext_count + 1));
|
feat_ext = curlx_malloc(sizeof(*feature_names) * (feat_ext_count + 1));
|
||||||
if(feat_ext) {
|
if(feat_ext) {
|
||||||
|
|
@ -364,6 +367,9 @@ void tool_version_info(void)
|
||||||
feat_ext_count = feature_count;
|
feat_ext_count = feature_count;
|
||||||
#ifdef CURL_CA_EMBED
|
#ifdef CURL_CA_EMBED
|
||||||
feat_ext[feat_ext_count++] = "CAcert";
|
feat_ext[feat_ext_count++] = "CAcert";
|
||||||
|
#endif
|
||||||
|
#ifdef CURL_DEBUG_GLOBAL_MEM
|
||||||
|
feat_ext[feat_ext_count++] = "global-mem-debug";
|
||||||
#endif
|
#endif
|
||||||
feat_ext[feat_ext_count] = NULL;
|
feat_ext[feat_ext_count] = NULL;
|
||||||
qsort((void *)feat_ext, feat_ext_count, sizeof(*feat_ext),
|
qsort((void *)feat_ext, feat_ext_count, sizeof(*feat_ext),
|
||||||
|
|
|
||||||
|
|
@ -778,7 +778,7 @@ static CURLcode post_per_transfer(struct per_transfer *per,
|
||||||
tool_safefree(per->etag_save.filename);
|
tool_safefree(per->etag_save.filename);
|
||||||
|
|
||||||
if(outs->alloc_filename)
|
if(outs->alloc_filename)
|
||||||
curlx_free(outs->filename);
|
tool_safefree(outs->filename);
|
||||||
curl_slist_free_all(per->hdrcbdata.headlist);
|
curl_slist_free_all(per->hdrcbdata.headlist);
|
||||||
per->hdrcbdata.headlist = NULL;
|
per->hdrcbdata.headlist = NULL;
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -848,8 +848,13 @@ static CURLcode append2query(struct OperationConfig *config,
|
||||||
if(uerr)
|
if(uerr)
|
||||||
result = urlerr_cvt(uerr);
|
result = urlerr_cvt(uerr);
|
||||||
else {
|
else {
|
||||||
|
/* use our new URL instead! */
|
||||||
curlx_free(per->url); /* free previous URL */
|
curlx_free(per->url); /* free previous URL */
|
||||||
per->url = updated; /* use our new URL instead! */
|
/* make it allocated by tool memory */
|
||||||
|
per->url = curlx_strdup(updated);
|
||||||
|
curl_free(updated);
|
||||||
|
if(!per->url)
|
||||||
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
curl_url_cleanup(uh);
|
curl_url_cleanup(uh);
|
||||||
|
|
@ -876,11 +881,16 @@ static CURLcode etag_compare(struct OperationConfig *config)
|
||||||
|
|
||||||
if((PARAM_OK == file2string(&etag_from_file, file)) &&
|
if((PARAM_OK == file2string(&etag_from_file, file)) &&
|
||||||
etag_from_file) {
|
etag_from_file) {
|
||||||
header = curl_maprintf("If-None-Match: %s", etag_from_file);
|
char *h = curl_maprintf("If-None-Match: %s", etag_from_file);
|
||||||
tool_safefree(etag_from_file);
|
tool_safefree(etag_from_file);
|
||||||
|
if(h) {
|
||||||
|
/* move it to the right memory */
|
||||||
|
header = curlx_strdup(h);
|
||||||
|
curl_free(h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
header = curl_maprintf("If-None-Match: \"\"");
|
header = curlx_strdup("If-None-Match: \"\"");
|
||||||
|
|
||||||
if(!header) {
|
if(!header) {
|
||||||
if(file)
|
if(file)
|
||||||
|
|
@ -891,7 +901,7 @@ static CURLcode etag_compare(struct OperationConfig *config)
|
||||||
|
|
||||||
/* add Etag from file to list of custom headers */
|
/* add Etag from file to list of custom headers */
|
||||||
pe = add2list(&config->headers, header);
|
pe = add2list(&config->headers, header);
|
||||||
tool_safefree(header);
|
curlx_free(header);
|
||||||
|
|
||||||
if(file)
|
if(file)
|
||||||
curlx_fclose(file);
|
curlx_fclose(file);
|
||||||
|
|
@ -1042,10 +1052,13 @@ static CURLcode setup_outfile(struct OperationConfig *config,
|
||||||
|
|
||||||
if(config->output_dir && *config->output_dir) {
|
if(config->output_dir && *config->output_dir) {
|
||||||
char *d = curl_maprintf("%s/%s", config->output_dir, per->outfile);
|
char *d = curl_maprintf("%s/%s", config->output_dir, per->outfile);
|
||||||
if(!d)
|
tool_safefree(per->outfile);
|
||||||
|
if(d) {
|
||||||
|
per->outfile = curlx_strdup(d); /* move to right memory */
|
||||||
|
curl_free(d);
|
||||||
|
}
|
||||||
|
if(!d || !per->outfile)
|
||||||
return CURLE_WRITE_ERROR;
|
return CURLE_WRITE_ERROR;
|
||||||
curlx_free(per->outfile);
|
|
||||||
per->outfile = d;
|
|
||||||
}
|
}
|
||||||
/* Create the directory hierarchy, if not pre-existent to a multiple
|
/* Create the directory hierarchy, if not pre-existent to a multiple
|
||||||
file output call */
|
file output call */
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@ CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
|
||||||
if(!newpath)
|
if(!newpath)
|
||||||
goto out;
|
goto out;
|
||||||
uerr = curl_url_set(uh, CURLUPART_PATH, newpath, 0);
|
uerr = curl_url_set(uh, CURLUPART_PATH, newpath, 0);
|
||||||
curlx_free(newpath);
|
curl_free(newpath);
|
||||||
if(uerr) {
|
if(uerr) {
|
||||||
result = urlerr_cvt(uerr);
|
result = urlerr_cvt(uerr);
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -157,8 +157,13 @@ CURLcode add_file_name_to_url(CURL *curl, char **inurlp, const char *filename)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
curlx_free(*inurlp);
|
curlx_free(*inurlp);
|
||||||
*inurlp = newurl;
|
/* make it owned by tool memory */
|
||||||
result = CURLE_OK;
|
*inurlp = curlx_strdup(newurl);
|
||||||
|
curl_free(newurl);
|
||||||
|
if(*inurlp)
|
||||||
|
result = CURLE_OK;
|
||||||
|
else
|
||||||
|
result = CURLE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,7 @@ static ParameterError varfunc(char *c, /* content */
|
||||||
/* put it in the output */
|
/* put it in the output */
|
||||||
if(curlx_dyn_addn(out, enc, elen))
|
if(curlx_dyn_addn(out, enc, elen))
|
||||||
err = PARAM_NO_MEM;
|
err = PARAM_NO_MEM;
|
||||||
curl_free(enc);
|
curlx_free(enc);
|
||||||
if(err)
|
if(err)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ static ParameterError varfunc(char *c, /* content */
|
||||||
else {
|
else {
|
||||||
if(curlx_dyn_addn(out, enc, elen))
|
if(curlx_dyn_addn(out, enc, elen))
|
||||||
err = PARAM_NO_MEM;
|
err = PARAM_NO_MEM;
|
||||||
curl_free(enc);
|
curlx_free(enc);
|
||||||
}
|
}
|
||||||
if(err)
|
if(err)
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue