mirror of
https://github.com/curl/curl.git
synced 2025-02-17 14:59:45 +08:00
tool: use our own stderr variable
Earlier this year we changed our own stderr variable to use the standard name `stderr` (to avoid bugs where someone is using `stderr` instead of the curl-tool specific variable). This solution needed to override the standard `stderr` symbol via the preprocessor. This in turn didn't play well with unity builds and caused curl tool to crash or stay silent due to an uninitialized stderr. This was a hard to find issue, fixed by manually breaking out one file from the unity sources. To avoid two these two tricks, this patch implements a different solution: Restore using our own local variable for our stderr output and leave `stderr` as-is. To avoid using `stderr` by mistake, add a `checksrc` rule (based on logic we already used in lib for `strerror`) that detects any `stderr` use in `src` and points to using our own variable instead: `tool_stderr`. Follow-up to06133d3e9b
Follow-up to2f17a9b654
Closes #11958
This commit is contained in:
parent
b5bb84cbef
commit
e5bb88b8f8
@ -41,7 +41,7 @@ Copyright: Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
License: curl
|
||||
|
||||
# checksrc control files
|
||||
Files: lib/.checksrc docs/examples/.checksrc tests/libtest/.checksrc
|
||||
Files: lib/.checksrc src/.checksrc docs/examples/.checksrc tests/libtest/.checksrc
|
||||
Copyright: Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
License: curl
|
||||
|
||||
|
@ -137,6 +137,8 @@ Currently these are the extended warnings which can be enabled:
|
||||
|
||||
- `STRERROR`: use of banned function strerror()
|
||||
|
||||
- `STDERR`: use of banned variable `stderr`
|
||||
|
||||
## Ignore certain warnings
|
||||
|
||||
Due to the nature of the source code and the flaws of the `checksrc` tool,
|
||||
|
@ -50,6 +50,7 @@ my @ignore_line;
|
||||
my %warnings_extended = (
|
||||
'COPYRIGHTYEAR' => 'copyright year incorrect',
|
||||
'STRERROR', => 'strerror() detected',
|
||||
'STDERR', => 'stderr detected',
|
||||
);
|
||||
|
||||
my %warnings = (
|
||||
@ -729,6 +730,18 @@ sub scanfile {
|
||||
}
|
||||
}
|
||||
}
|
||||
if($warnings{"STDERR"}) {
|
||||
# scan for use of banned stderr. This is not a BANNEDFUNC to
|
||||
# allow for individual enable/disable of this warning.
|
||||
if($l =~ /^([^\"-]*\W)(stderr)[^\"_]/x) {
|
||||
if($1 !~ /^ *\#/) {
|
||||
# skip preprocessor lines
|
||||
checkwarn("STDERR",
|
||||
$line, length($1), $file, $ol,
|
||||
"use of $2 is banned (use tool_stderr instead)");
|
||||
}
|
||||
}
|
||||
}
|
||||
# scan for use of snprintf for curl-internals reasons
|
||||
if($l =~ /^(.*\W)(v?snprintf)\s*\(/x) {
|
||||
checkwarn("SNPRINTF",
|
||||
|
1
src/.checksrc
Normal file
1
src/.checksrc
Normal file
@ -0,0 +1 @@
|
||||
enable STDERR
|
@ -67,11 +67,6 @@ if(BUILD_STATIC_CURL)
|
||||
set(CURLX_CFILES ${CURLTOOL_LIBCURL_CFILES})
|
||||
endif()
|
||||
|
||||
# Compile this source separately to avoid having `stderr` overridden in this
|
||||
# file. Necessary for successfully initializing stderr in unity builds.
|
||||
# (Not necessary for the libcurltool target.)
|
||||
set_source_files_properties(tool_stderr.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
|
||||
|
||||
add_executable(
|
||||
${EXE_NAME}
|
||||
${CURL_CFILES} ${CURLX_CFILES} ${CURL_HFILES}
|
||||
|
@ -95,7 +95,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
|
||||
{
|
||||
struct OperationConfig *operation = userdata;
|
||||
struct GlobalConfig *config = operation->global;
|
||||
FILE *output = stderr;
|
||||
FILE *output = tool_stderr;
|
||||
const char *text;
|
||||
struct timeval tv;
|
||||
char timebuf[20];
|
||||
@ -137,7 +137,7 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
|
||||
config->trace_stream = stdout;
|
||||
else if(!strcmp("%", config->trace_dump))
|
||||
/* Ok, this is somewhat hackish but we do it undocumented for now */
|
||||
config->trace_stream = stderr;
|
||||
config->trace_stream = tool_stderr;
|
||||
else {
|
||||
config->trace_stream = fopen(config->trace_dump, FOPEN_WRITETEXT);
|
||||
config->trace_fopened = TRUE;
|
||||
@ -195,7 +195,8 @@ int tool_debug_cb(CURL *handle, curl_infotype type,
|
||||
to stderr or stdout, we don't display the alert about the data not
|
||||
being shown as the data _is_ shown then just not via this
|
||||
function */
|
||||
if(!config->isatty || ((output != stderr) && (output != stdout))) {
|
||||
if(!config->isatty ||
|
||||
((output != tool_stderr) && (output != stdout))) {
|
||||
if(!newl)
|
||||
log_line_start(output, timebuf, idsbuf, type);
|
||||
fprintf(output, "[%zu bytes data]\n", size);
|
||||
|
@ -274,7 +274,7 @@ void progressbarinit(struct ProgressData *bar,
|
||||
else if(bar->width > MAX_BARLENGTH)
|
||||
bar->width = MAX_BARLENGTH;
|
||||
|
||||
bar->out = stderr;
|
||||
bar->out = tool_stderr;
|
||||
bar->tick = 150;
|
||||
bar->barmove = 1;
|
||||
}
|
||||
|
@ -2777,9 +2777,9 @@ ParameterError parse_args(struct GlobalConfig *global, int argc,
|
||||
const char *reason = param2text(result);
|
||||
|
||||
if(orig_opt && strcmp(":", orig_opt))
|
||||
helpf(stderr, "option %s: %s", orig_opt, reason);
|
||||
helpf(tool_stderr, "option %s: %s", orig_opt, reason);
|
||||
else
|
||||
helpf(stderr, "%s", reason);
|
||||
helpf(tool_stderr, "%s", reason);
|
||||
}
|
||||
|
||||
curlx_unicodefree(orig_opt);
|
||||
|
@ -99,7 +99,7 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
|
||||
char *getpass_r(const char *prompt, char *buffer, size_t buflen)
|
||||
{
|
||||
size_t i;
|
||||
fputs(prompt, stderr);
|
||||
fputs(prompt, tool_stderr);
|
||||
|
||||
for(i = 0; i < buflen; i++) {
|
||||
buffer[i] = (char)getch();
|
||||
@ -114,7 +114,7 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen)
|
||||
i = i - (i >= 1 ? 2 : 1);
|
||||
}
|
||||
/* since echo is disabled, print a newline */
|
||||
fputs("\n", stderr);
|
||||
fputs("\n", tool_stderr);
|
||||
/* if user didn't hit ENTER, terminate buffer */
|
||||
if(i == buflen)
|
||||
buffer[buflen-1] = '\0';
|
||||
@ -184,7 +184,7 @@ char *getpass_r(const char *prompt, /* prompt to display */
|
||||
|
||||
disabled = ttyecho(FALSE, fd); /* disable terminal echo */
|
||||
|
||||
fputs(prompt, stderr);
|
||||
fputs(prompt, tool_stderr);
|
||||
nread = read(fd, password, buflen);
|
||||
if(nread > 0)
|
||||
password[--nread] = '\0'; /* null-terminate where enter is stored */
|
||||
@ -193,7 +193,7 @@ char *getpass_r(const char *prompt, /* prompt to display */
|
||||
|
||||
if(disabled) {
|
||||
/* if echo actually was disabled, add a newline */
|
||||
fputs("\n", stderr);
|
||||
fputs("\n", tool_stderr);
|
||||
(void)ttyecho(TRUE, fd); /* enable echo */
|
||||
}
|
||||
|
||||
|
@ -164,7 +164,7 @@ void tool_version_info(void)
|
||||
{
|
||||
const char *const *builtin;
|
||||
if(is_debug())
|
||||
fprintf(stderr, "WARNING: this libcurl is Debug-enabled, "
|
||||
fprintf(tool_stderr, "WARNING: this libcurl is Debug-enabled, "
|
||||
"do not use in production\n\n");
|
||||
|
||||
printf(CURL_ID "%s\n", curl_version());
|
||||
|
@ -42,7 +42,7 @@
|
||||
#endif
|
||||
|
||||
#ifndef STDERR_FILENO
|
||||
# define STDERR_FILENO fileno(stderr)
|
||||
# define STDERR_FILENO fileno(tool_stderr)
|
||||
#endif
|
||||
|
||||
#endif /* HEADER_CURL_TOOL_MAIN_H */
|
||||
|
@ -55,7 +55,7 @@ static void voutf(struct GlobalConfig *config,
|
||||
|
||||
ptr = print_buffer;
|
||||
while(len > 0) {
|
||||
fputs(prefix, stderr);
|
||||
fputs(prefix, tool_stderr);
|
||||
|
||||
if(len > width) {
|
||||
size_t cut = width-1;
|
||||
@ -68,14 +68,14 @@ static void voutf(struct GlobalConfig *config,
|
||||
max text width then! */
|
||||
cut = width-1;
|
||||
|
||||
(void)fwrite(ptr, cut + 1, 1, stderr);
|
||||
fputs("\n", stderr);
|
||||
(void)fwrite(ptr, cut + 1, 1, tool_stderr);
|
||||
fputs("\n", tool_stderr);
|
||||
ptr += cut + 1; /* skip the space too */
|
||||
len -= cut + 1;
|
||||
}
|
||||
else {
|
||||
fputs(ptr, stderr);
|
||||
fputs("\n", stderr);
|
||||
fputs(ptr, tool_stderr);
|
||||
fputs("\n", tool_stderr);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
@ -304,7 +304,7 @@ static CURLcode pre_transfer(struct GlobalConfig *global,
|
||||
if((per->infd == -1) || fstat(per->infd, &fileinfo))
|
||||
#endif
|
||||
{
|
||||
helpf(stderr, "Can't open '%s'", per->uploadfile);
|
||||
helpf(tool_stderr, "Can't open '%s'", per->uploadfile);
|
||||
if(per->infd != -1) {
|
||||
close(per->infd);
|
||||
per->infd = STDIN_FILENO;
|
||||
@ -415,10 +415,10 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
|
||||
if(!config->synthetic_error && result &&
|
||||
(!global->silent || global->showerror)) {
|
||||
const char *msg = per->errorbuffer;
|
||||
fprintf(stderr, "curl: (%d) %s\n", result,
|
||||
fprintf(tool_stderr, "curl: (%d) %s\n", result,
|
||||
(msg && msg[0]) ? msg : curl_easy_strerror(result));
|
||||
if(result == CURLE_PEER_FAILED_VERIFICATION)
|
||||
fputs(CURL_CA_CERT_ERRORMSG, stderr);
|
||||
fputs(CURL_CA_CERT_ERRORMSG, tool_stderr);
|
||||
}
|
||||
else if(config->failwithbody) {
|
||||
/* if HTTP response >= 400, return error */
|
||||
@ -426,7 +426,7 @@ static CURLcode post_per_transfer(struct GlobalConfig *global,
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
|
||||
if(code >= 400) {
|
||||
if(!global->silent || global->showerror)
|
||||
fprintf(stderr,
|
||||
fprintf(tool_stderr,
|
||||
"curl: (%d) The requested URL returned error: %ld\n",
|
||||
CURLE_HTTP_RETURNED_ERROR, code);
|
||||
result = CURLE_HTTP_RETURNED_ERROR;
|
||||
@ -864,19 +864,19 @@ clean:
|
||||
|
||||
switch(result) {
|
||||
case CURLE_URL_MALFORMAT:
|
||||
helpf(stderr, "malformed URL. Visit https://curl.se/"
|
||||
helpf(tool_stderr, "malformed URL. Visit https://curl.se/"
|
||||
"docs/ipfs.html#Gateway-file-and-"
|
||||
"environment-variable for more "
|
||||
"information");
|
||||
break;
|
||||
case CURLE_FILE_COULDNT_READ_FILE:
|
||||
helpf(stderr, "IPFS automatic gateway detection "
|
||||
helpf(tool_stderr, "IPFS automatic gateway detection "
|
||||
"failure. Visit https://curl.se/docs/"
|
||||
"ipfs.html#Malformed-gateway-URL for "
|
||||
"more information");
|
||||
break;
|
||||
case CURLE_BAD_FUNCTION_ARGUMENT:
|
||||
helpf(stderr, "--ipfs-gateway argument results in "
|
||||
helpf(tool_stderr, "--ipfs-gateway argument results in "
|
||||
"malformed URL. Visit https://curl.se/"
|
||||
"docs/ipfs.html#Malformed-gateway-URL "
|
||||
"for more information");
|
||||
@ -1020,7 +1020,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
||||
/* Unless explicitly shut off */
|
||||
result = glob_url(&inglob, infiles, &state->infilenum,
|
||||
(!global->silent || global->showerror)?
|
||||
stderr:NULL);
|
||||
tool_stderr:NULL);
|
||||
if(result)
|
||||
break;
|
||||
config->state.inglob = inglob;
|
||||
@ -1056,7 +1056,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
||||
expressions and return total number of URLs in pattern set */
|
||||
result = glob_url(&state->urls, urlnode->url, &state->urlnum,
|
||||
(!global->silent || global->showerror)?
|
||||
stderr:NULL);
|
||||
tool_stderr:NULL);
|
||||
if(result)
|
||||
break;
|
||||
urlnum = state->urlnum;
|
||||
@ -2074,7 +2074,7 @@ static CURLcode single_transfer(struct GlobalConfig *global,
|
||||
my_setopt(curl, CURLOPT_TIMEVALUE_LARGE, config->condtime);
|
||||
my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
|
||||
customrequest_helper(config, config->httpreq, config->customrequest);
|
||||
my_setopt(curl, CURLOPT_STDERR, stderr);
|
||||
my_setopt(curl, CURLOPT_STDERR, tool_stderr);
|
||||
|
||||
/* three new ones in libcurl 7.3: */
|
||||
my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
|
||||
@ -2745,7 +2745,7 @@ static CURLcode transfer_per_config(struct GlobalConfig *global,
|
||||
|
||||
/* Check we have a url */
|
||||
if(!config->url_list || !config->url_list->url) {
|
||||
helpf(stderr, "(%d) no URL specified", CURLE_FAILED_INIT);
|
||||
helpf(tool_stderr, "(%d) no URL specified", CURLE_FAILED_INIT);
|
||||
return CURLE_FAILED_INIT;
|
||||
}
|
||||
|
||||
@ -2922,7 +2922,7 @@ CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
|
||||
|
||||
/* If we had no arguments then make sure a url was specified in .curlrc */
|
||||
if((argc < 2) && (!global->first->url_list)) {
|
||||
helpf(stderr, NULL);
|
||||
helpf(tool_stderr, NULL);
|
||||
result = CURLE_FAILED_INIT;
|
||||
}
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
|
||||
*line++ = '\0'; /* null-terminate, we have a local copy of the data */
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
fprintf(stderr, "GOT: %s\n", option);
|
||||
fprintf(tool_stderr, "GOT: %s\n", option);
|
||||
#endif
|
||||
|
||||
/* pass spaces and separator(s) */
|
||||
@ -221,7 +221,7 @@ int parseconfig(const char *filename, struct GlobalConfig *global)
|
||||
}
|
||||
|
||||
#ifdef DEBUG_CONFIG
|
||||
fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
|
||||
fprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
|
||||
#endif
|
||||
res = getparameter(option, param, NULL, &usedarg, global, operation);
|
||||
operation = global->last;
|
||||
|
@ -173,7 +173,7 @@ bool progress_meter(struct GlobalConfig *global,
|
||||
header = TRUE;
|
||||
fputs("DL% UL% Dled Uled Xfers Live "
|
||||
"Total Current Left Speed\n",
|
||||
stderr);
|
||||
tool_stderr);
|
||||
}
|
||||
if(final || (diff > 500)) {
|
||||
char time_left[10];
|
||||
@ -275,7 +275,7 @@ bool progress_meter(struct GlobalConfig *global,
|
||||
}
|
||||
time2str(time_spent, spent);
|
||||
|
||||
fprintf(stderr,
|
||||
fprintf(tool_stderr,
|
||||
"\r"
|
||||
"%-3s " /* percent downloaded */
|
||||
"%-3s " /* percent uploaded */
|
||||
|
@ -39,13 +39,6 @@
|
||||
|
||||
extern FILE *tool_stderr;
|
||||
|
||||
#if !defined(CURL_DO_NOT_OVERRIDE_STDERR) && !defined(UNITTESTS)
|
||||
#ifdef stderr
|
||||
#undef stderr
|
||||
#endif
|
||||
#define stderr tool_stderr
|
||||
#endif
|
||||
|
||||
/*
|
||||
* curl tool certainly uses libcurl's external interface.
|
||||
*/
|
||||
|
@ -22,20 +22,17 @@
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/* In this file, stdio.h's stderr macro is not overridden. */
|
||||
#define CURL_DO_NOT_OVERRIDE_STDERR
|
||||
|
||||
#include "tool_setup.h"
|
||||
#include "tool_stderr.h"
|
||||
#include "tool_msgs.h"
|
||||
|
||||
#include "memdebug.h" /* keep this as LAST include */
|
||||
|
||||
/* In other tool files stderr is defined as tool_stderr by tool_setup.h */
|
||||
FILE *tool_stderr;
|
||||
|
||||
void tool_init_stderr(void)
|
||||
{
|
||||
/* !checksrc! disable STDERR 1 */
|
||||
tool_stderr = stderr;
|
||||
}
|
||||
|
||||
@ -62,11 +59,13 @@ void tool_set_stderr_file(struct GlobalConfig *global, char *filename)
|
||||
|
||||
/* freopen the actual stderr (stdio.h stderr) instead of tool_stderr since
|
||||
the latter may be set to stdout. */
|
||||
/* !checksrc! disable STDERR 1 */
|
||||
fp = freopen(filename, FOPEN_WRITETEXT, stderr);
|
||||
if(!fp) {
|
||||
/* stderr may have been closed by freopen. there is nothing to be done. */
|
||||
DEBUGASSERT(0);
|
||||
return;
|
||||
}
|
||||
/* !checksrc! disable STDERR 1 */
|
||||
tool_stderr = stderr;
|
||||
}
|
||||
|
@ -668,7 +668,7 @@ CURLcode glob_match_url(char **result, char *filename, struct URLGlob *glob)
|
||||
appendlen = strlen(numbuf);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "internal error: invalid pattern type (%d)\n",
|
||||
fprintf(tool_stderr, "internal error: invalid pattern type (%d)\n",
|
||||
(int)pat->type);
|
||||
curlx_dyn_free(&dyn);
|
||||
return CURLE_FAILED_INIT;
|
||||
|
@ -566,7 +566,7 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
||||
if(fclose_stream)
|
||||
fclose(stream);
|
||||
fclose_stream = FALSE;
|
||||
stream = stderr;
|
||||
stream = tool_stderr;
|
||||
break;
|
||||
case VAR_JSON:
|
||||
ourWriteOutJSON(stream, variables, per, per_result);
|
||||
@ -583,7 +583,8 @@ void ourWriteOut(struct OperationConfig *config, struct per_transfer *per,
|
||||
}
|
||||
}
|
||||
if(!match) {
|
||||
fprintf(stderr, "curl: unknown --write-out variable: '%.*s'\n",
|
||||
fprintf(tool_stderr,
|
||||
"curl: unknown --write-out variable: '%.*s'\n",
|
||||
(int)vlen, ptr);
|
||||
}
|
||||
ptr = end + 1; /* pass the end */
|
||||
|
Loading…
Reference in New Issue
Block a user