✓ProveIt
Examples / Report #3137657 Saved analysis

Memory Leak

curl · 2025-05-0916.3s analysis · $0.026 in model calls

What the report claims

Memory leak in getstr() via strdup() in tool_getparam.c

Compare with curl's recorded outcome

Labeled AI slop

curl's maintainer lists this report as AI slop

Shown for comparison after analysis. The pipeline did not see this label.

ProveIt's finding

Needs a policy review

The code does what the report says, but curl's own policy may exclude it. A maintainer decides.

curl policy: Small memory leaks
Judgment withdrawn. The answer failed the evidence check.
See the withdrawn model reasoning

The following reasoning failed the citation check and does not support the final finding.

  • curl is a command-line tool that runs once and exits; the OS reclaims all memory on process termination
  • The project policy explicitly states: 'We do not consider a small memory leak a security problem' for long-living applications, and a CLI tool that exits is an even clearer case
  • The leak does not give an attacker any access, data, code execution, or denial of service they should not have
  • The allocation occurs once per option parsing and persists only until main() returns; there is no repeated allocation loop that could cause unbounded growth during a single run
  • The ASAN-detected leak of 2 bytes in 1 allocation is a one-time cleanup omission at program exit, not a security vulnerability
How this analysis ran 5 claims · 9 citations verified

Evidence check: the behavior is real; the project's policy section 'Small memory leaks' may exclude it

Checked against curl master on 2025-05-09 (cd7904f5a970). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.

1 · Grounding
grounded
no model · 11 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 2110 tokens · $0.0002
3 · Evidence
11 code snippets
real curl source at cd7904f5a970
4 · Judgment
Nemotron-3-Ultra-550b-a55b
21371 tokens · 14.2s · $0.0254
5 · Receipts
9 of 9 citations verified
every citation must point at code the judge was shown
Inspect the withdrawn draft reply

This draft belongs to the withdrawn judgment. It may contain unsupported claims.

Thank you for the report. The memory allocation you identified in getstr() (src/tool_getparam.c:57) does persist until program exit, but curl is a command-line tool that runs once and terminates. The operating system reclaims all process memory on exit, so this does not constitute a security vulnerability. Our policy explicitly states that small memory leaks are not considered security issues, especially for short-lived CLI tools. The ASAN detection is accurate for a one-time cleanup omission, but it does not enable any attack.

Inspect all claims and source code 5 claims · 11 code excerpts

This model judgment was withdrawn. The claim assessments below are preserved for inspection and may be wrong.

Report claims

C1flaw supported

strdup() is used without a corresponding free() before program termination, causing a memory leak

Read the reasoning

The code confirms strdup() is used in getstr() to allocate strings for config fields. The provided code snippets do not show a cleanup function that frees these allocations before main() returns. However, the leak only persists until process termination.

C2location supported

Line 2754 in src/tool_getparam.c, inside getstr() function

Read the reasoning

The report references line 2754 in getparameter(), but the provided code shows getstr() at lines 47-62 with strdup at line 57. Line numbers differ between versions, but the function and allocation site are correctly identified.

C3trigger supported

User-provided configuration values that reach getparameter() → parseconfig() → getstr()

Read the reasoning

User-provided configuration values from config files or command line reach getparameter() via parseconfig() and parse_args(), which then call getstr() for string-type options.

C4impact supported

Persistent heap allocation that is never freed, leading to uncontrolled heap growth

Read the reasoning

The allocated strings remain in the config structures until program exit. The ASAN output confirms a 2-byte leak. However, this is a one-time allocation per program run, not uncontrolled heap growth during execution.

C5reproduction supported

Run curl with ASAN_OPTIONS="detect_leaks=1:verbosity=2:malloc_context_size=50" ./curl -K <crash-file> to trigger the leak

Read the reasoning

The reproduction command uses AddressSanitizer with leak detection enabled, which would detect the allocation from strdup() in getstr() when processing a config file via -K flag.

Read the original report (excerpt)

Full report on HackerOne ↗

* in getparameter() via strdup() in tool_getparam.c > SIGSEGV Project: cURL File: src/tool_getparam.c Function: getparameter() → indirectly via getstr() Detected By: AddressSanitizer (ASan) Command Used: ASAN_OPTIONS="detect_leaks=1:verbosity=2:malloc_context_size=50" ./curl -K <crash-file> # Overview A memory leak vulnerability has been identified in Curl’s configuration handling within tool_getparam.c. The issue originates from improper memory management of dynamically allocated strings using strdup(), leading to a persistent allocation that is never freed. Leak occurs in a key parsing function that processes user input, and survives until program termination, violating memory safety expectations for clean exits or tools used in pipelines and fuzzing environments. The issue lies in allocations made for fields like config->range, config->useragent, etc., without corresponding calls to free() or a cleanup routine. Affected Component - File: tool_getparam.c - Function: getstr() - Location: Line 2754 - Bug Type: Memory Leak - Impact: The persistent allocation results in uncontrolled heap growth. While a memory leak alone does not directly enable arbitrary code execution, further analysis is required to assess whether heap fragmentation or manipulation could lead to memory corruption scenarios. ## Technical Details Issue Description The function getstr() is responsible for handling dynamically allocated strings used for various Curl parameters. If an existing string pointer is assigned a new value, it is properly freed before reallocation: static ParameterError getstr(char **str, const char *val, bool allowblank) { if(*str) { free(*str); *str = NULL; } However, when val is provided, strdup() is used to duplicate the string without ensuring proper memory cleanup later: if(val) { if(!allowblank && !val[0]) return PARAM_BLANK_STRING; *str = strdup(val); // Potential leak occurs here if(!*str) return PARAM_NO_MEM; } return PARAM_OK; } Since there is no corresponding free() before process termination, this leads to a direct memory leak, as confirmed by ASAN: ==7796==ERROR: LeakSanitizer: detected memory leaks Direct leak of 2 byte(s) in 1 object(s) allocated from: #0 0x55fa1dc2f19e in strdup (/home/og/test/afl-test/curl/build/src/curl+0xdf19e) #1 0x55fa1dca3e21 in getparameter /home/og/test/afl-test/curl/s …

Source code

src/tool_getparam.clines 1676–1836 · definition of getparameter (truncated)
1676ParameterError getparameter(const char *flag, /* f or -long-flag */
1677 const char *nextarg, /* NULL if unset */
1678 argv_item_t cleararg1,
1679 argv_item_t cleararg2,
1680 bool *usedarg, /* set to TRUE if the arg
1681 has been used */
1682 struct GlobalConfig *global,
1683 struct OperationConfig *config)
1684{
1685 const char *parse = NULL;
1686 bool longopt = FALSE;
1687 bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
1688 size_t nopts = 0; /* options processed in `flag`*/
1689 ParameterError err = PARAM_OK;
1690 bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
1691 by using --OPTION or --no-OPTION */
1692 bool nextalloc = FALSE; /* if nextarg is allocated */
1693 static const char *redir_protos[] = {
1694 "http",
1695 "https",
1696 "ftp",
1697 "ftps",
1698 NULL
1699 };
1700 const struct LongShort *a = NULL;
1701 curl_off_t value;
1702#ifdef HAVE_WRITABLE_ARGV
1703 argv_item_t clearthis = NULL;
1704#else
1705 (void)cleararg1;
1706 (void)cleararg2;
1707#endif
1708
1709 *usedarg = FALSE; /* default is that we do not use the arg */
1710
1711 if(('-' != flag[0]) || ('-' == flag[1])) {
1712 /* this should be a long name */
1713 const char *word = ('-' == flag[0]) ? flag + 2 : flag;
1714 bool noflagged = FALSE;
1715 bool expand = FALSE;
1716
1717 if(!strncmp(word, "no-", 3)) {
1718 /* disable this option but ignore the "no-" part when looking for it */
1719 word += 3;
1720 toggle = FALSE;
1721 noflagged = TRUE;
1722 }
1723 else if(!strncmp(word, "expand-", 7)) {
1724 /* variable expansions is to be done on the argument */
1725 word += 7;
1726 expand = TRUE;
1727 }
1728
1729 a = findlongopt(word);
1730 if(a) {
1731 longopt = TRUE;
1732 }
1733 else {
1734 err = PARAM_OPTION_UNKNOWN;
1735 goto error;
1736 }
1737 if(noflagged && (ARGTYPE(a->desc) != ARG_BOOL)) {
1738 /* --no- prefixed an option that is not boolean! */
1739 err = PARAM_NO_NOT_BOOLEAN;
1740 goto error;
1741 }
1742 else if(expand && nextarg) {
1743 struct dynbuf nbuf;
1744 bool replaced;
1745
1746 if((ARGTYPE(a->desc) != ARG_STRG) &&
1747 (ARGTYPE(a->desc) != ARG_FILE)) {
1748 /* --expand on an option that is not a string or a filename */
1749 err = PARAM_EXPAND_ERROR;
1750 goto error;
1751 }
1752 err = varexpand(global, nextarg, &nbuf, &replaced);
1753 if(err) {
1754 curlx_dyn_free(&nbuf);
1755 goto error;
1756 }
1757 if(replaced) {
1758 nextarg = curlx_dyn_ptr(&nbuf);
1759 nextalloc = TRUE;
1760 }
1761 }
1762 }
1763 else {
1764 flag++; /* prefixed with one dash, pass it */
1765 parse = flag;
1766 }
1767
1768 do {
1769 /* we can loop here if we have multiple single-letters */
1770 cmdline_t cmd;
1771
1772 if(!longopt && !a) {
1773 a = findshortopt(*parse);
1774 if(!a) {
1775 err = PARAM_OPTION_UNKNOWN;
1776 break;
1777 }
1778 }
1779 cmd = (cmdline_t)a->cmd;
1780 if(ARGTYPE(a->desc) >= ARG_STRG) {
1781 /* this option requires an extra parameter */
1782 if(!longopt && parse[1]) {
1783 nextarg = &parse[1]; /* this is the actual extra parameter */
1784 singleopt = TRUE; /* do not loop anymore after this */
1785#ifdef HAVE_WRITABLE_ARGV
1786 if(cleararg1)
1787 clearthis = &cleararg1[parse + 2 - flag];
1788#endif
1789 }
1790 else if(!nextarg) {
1791 err = PARAM_REQUIRES_PARAMETER;
1792 break;
1793 }
1794 else {
1795#ifdef HAVE_WRITABLE_ARGV
1796 if(cleararg2)
1797 clearthis = cleararg2;
1798#endif
1799 *usedarg = TRUE; /* mark it as used */
1800 }
1801
1802 if((ARGTYPE(a->desc) == ARG_FILE) &&
1803 (nextarg[0] == '-') && nextarg[1]) {
1804 /* if the filename looks like a command line option */
1805 warnf(global, "The filename argument '%s' looks like a flag.",
1806 nextarg);
1807 }
1808 else if(!strncmp("\xe2\x80\x9c", nextarg, 3)) {
1809 warnf(global, "The argument '%s' starts with a Unicode quote where "
1810 "maybe an ASCII \" was intended?",
1811 nextarg);
1812 }
1813 }
1814 else if((ARGTYPE(a->desc) == ARG_NONE) && !toggle) {
1815 err = PARAM_NO_PREFIX;
1816 break;
1817 }
1818 else if((a->desc & ARG_TLS) && !feature_ssl) {
1819 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1820 break;
1821 }
1822
1823 if(!nextarg)
1824 /* this is a precaution mostly to please scan-build, as all arguments
1825 that use nextarg should be marked as such and they will check that
1826 nextarg is set before continuing, but code analyzers are not always
1827 that aware of that state */
1828 nextarg = "";
1829
1830 switch(cmd) {
C3: getparameter() switch statement handles various options that call getstr() for string parameters
1831 case C_RANDOM_FILE: /* --random-file */
1832 case C_EGD_FILE: /* --egd-file */
1833 case C_NTLM_WB: /* --ntlm-wb */
1834 warnf(global, "--%s is deprecated and has no function anymore",
1835 a->lname);
1836 break;
src/tool_getparam.clines 47–62 · definition of getstr
47static ParameterError getstr(char **str, const char *val, bool allowblank)
C2: getstr() function definition starts at line 47
48{
49 if(*str) {
C1: getstr() frees previous *str at lines 49-51 before allocating new memory, but no cleanup function is shown in provided code that frees these strings at program exit
50 free(*str);
51 *str = NULL;
52 }
53 if(val) {
54 if(!allowblank && !val[0])
55 return PARAM_BLANK_STRING;
56
57 *str = strdup(val);
C1: getstr() calls strdup(val) at line 57, allocating memory that is assigned to *str
C2: strdup() call at line 57 inside getstr()
C4: strdup() allocates memory that persists in config struct fields
C5: strdup() allocation site detected by ASAN
58 if(!*str)
59 return PARAM_NO_MEM;
60 }
61 return PARAM_OK;
62}
src/tool_main.c@curl-8_13_0lines 238–300 · definition of main as in release curl-8_13_0; differs from master
238int main(int argc, char *argv[])
239#endif
240{
241 CURLcode result = CURLE_OK;
242 struct GlobalConfig global;
243 memset(&global, 0, sizeof(global));
244
245 tool_init_stderr();
246
247#if defined(_WIN32) && !defined(UNDER_CE)
248 /* Undocumented diagnostic option to list the full paths of all loaded
249 modules. This is purposely pre-init. */
250 if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) {
251 struct curl_slist *item, *head = GetLoadedModulePaths();
252 for(item = head; item; item = item->next)
253 printf("%s\n", item->data);
254 curl_slist_free_all(head);
255 return head ? 0 : 1;
256 }
257#endif
258#ifdef _WIN32
259 /* win32_init must be called before other init routines. */
260 result = win32_init();
261 if(result) {
262 errorf(&global, "(%d) Windows-specific init failed", result);
263 return (int)result;
264 }
265#endif
266
267 if(main_checkfds()) {
268 errorf(&global, "out of file descriptors");
269 return CURLE_FAILED_INIT;
270 }
271
272#if defined(HAVE_SIGNAL) && defined(SIGPIPE)
273 (void)signal(SIGPIPE, SIG_IGN);
274#endif
275
276 /* Initialize memory tracking */
277 memory_tracking_init();
278
279 /* Initialize the curl library - do not call any libcurl functions before
280 this point */
281 result = main_init(&global);
282 if(!result) {
283 /* Start our curl operation */
284 result = operate(&global, argc, argv);
285
286 /* Perform the main cleanup */
287 main_free(&global);
C4: main() calls main_free(&global) but its implementation is not shown in provided code
288 }
289
290#ifdef _WIN32
291 /* Flush buffers of all streams opened in write or update mode */
292 fflush(NULL);
293#endif
294
295#ifdef __VMS
296 vms_special_exit(result, vms_show);
297#else
298 return (int)result;
299#endif
300}
src/tool_parsecfg.clines 45–205 · definition of parseconfig (truncated)
45int parseconfig(const char *filename, struct GlobalConfig *global)
46{
47 FILE *file = NULL;
48 bool usedarg = FALSE;
49 int rc = 0;
50 struct OperationConfig *operation = global->last;
51 char *pathalloc = NULL;
52
53 if(!filename) {
54 /* NULL means load .curlrc from homedir! */
55 char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE);
56 if(curlrc) {
57 file = fopen(curlrc, FOPEN_READTEXT);
58 if(!file) {
59 free(curlrc);
60 return 1;
61 }
62 filename = pathalloc = curlrc;
63 }
64#if defined(_WIN32) && !defined(UNDER_CE)
65 else {
66 char *fullp;
67 /* check for .curlrc then _curlrc in the dir of the executable */
68 file = tool_execpath(".curlrc", &fullp);
69 if(!file)
70 file = tool_execpath("_curlrc", &fullp);
71 if(file)
72 /* this is the filename we read from */
73 filename = fullp;
74 }
75#endif
76 }
77 else {
78 if(strcmp(filename, "-"))
79 file = fopen(filename, FOPEN_READTEXT);
80 else
81 file = stdin;
82 }
83
84 if(file) {
85 char *line;
86 char *option;
87 char *param;
88 int lineno = 0;
89 bool dashed_option;
90 struct dynbuf buf;
91 bool fileerror = FALSE;
92 curlx_dyn_init(&buf, MAX_CONFIG_LINE_LENGTH);
93 DEBUGASSERT(filename);
94
95 while(!rc && my_get_line(file, &buf, &fileerror)) {
96 ParameterError res;
97 bool alloced_param = FALSE;
98 lineno++;
99 line = curlx_dyn_ptr(&buf);
100 if(!line) {
101 rc = 1; /* out of memory */
102 break;
103 }
104
105 /* the option keywords starts here */
106 option = line;
107
108 /* the option starts with a dash? */
109 dashed_option = (option[0] == '-');
110
111 while(*line && !ISBLANK(*line) && !ISSEP(*line, dashed_option))
112 line++;
113 /* ... and has ended here */
114
115 if(*line)
116 *line++ = '\0'; /* null-terminate, we have a local copy of the data */
117
118#ifdef DEBUG_CONFIG
119 fprintf(tool_stderr, "GOT: %s\n", option);
120#endif
121
122 /* pass spaces and separator(s) */
123 while(ISBLANK(*line) || ISSEP(*line, dashed_option))
124 line++;
125
126 /* the parameter starts here (unless quoted) */
127 if(*line == '\"') {
128 /* quoted parameter, do the quote dance */
129 line++;
130 param = malloc(strlen(line) + 1); /* parameter */
131 if(!param) {
132 /* out of memory */
133 rc = 1;
134 break;
135 }
136 alloced_param = TRUE;
137 (void)unslashquote(line, param);
138 }
139 else {
140 param = line; /* parameter starts here */
141 while(*line && !ISSPACE(*line)) /* stop also on CRLF */
142 line++;
143
144 if(*line) {
145 *line = '\0'; /* null-terminate */
146
147 /* to detect mistakes better, see if there is data following */
148 line++;
149 /* pass all spaces */
150 while(ISBLANK(*line))
151 line++;
152
153 switch(*line) {
154 case '\0':
155 case '\r':
156 case '\n':
157 case '#': /* comment */
158 break;
159 default:
160 warnf(operation->global, "%s:%d: warning: '%s' uses unquoted "
161 "whitespace", filename, lineno, option);
162 warnf(operation->global, "This may cause side-effects. "
163 "Consider using double quotes?");
164 }
165 }
166 if(!*param)
167 /* do this so getparameter can check for required parameters.
168 Otherwise it always thinks there is a parameter. */
169 param = NULL;
170 }
171
172#ifdef DEBUG_CONFIG
173 fprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
174#endif
175 res = getparameter(option, param, NULL, NULL,
C3: parseconfig() calls getparameter() at line 175 with user-provided config values
176 &usedarg, global, operation);
177 operation = global->last;
178
179 if(!res && param && *param && !usedarg)
180 /* we passed in a parameter that was not used! */
181 res = PARAM_GOT_EXTRA_PARAMETER;
182
183 if(res == PARAM_NEXT_OPERATION) {
184 if(operation->url_list && operation->url_list->url) {
185 /* Allocate the next config */
186 operation->next = malloc(sizeof(struct OperationConfig));
187 if(operation->next) {
188 /* Initialise the newly created config */
189 config_init(operation->next);
190
191 /* Set the global config pointer */
192 operation->next->global = global;
193
194 /* Update the last operation pointer */
195 global->last = operation->next;
196
197 /* Move onto the new config */
198 operation->next->prev = operation;
199 operation = operation->next;
200 }
201 else
202 res = PARAM_NO_MEM;
203 }
204 }
205
src/tool_getparam.c@curl-8_13_0lines 1678–1838 · definition of getparameter as in release curl-8_13_0; differs from master; commits that changed it since: d689bd915e src: rename curlx_safefree to tool_safefree | 255aac56f9 curlx: move into to curlx/ | a638828c88 TLS: add CURLOPT_SSL_SIGNATURE_ALGORITHMS and --sigalgs
Show 161 lines (not cited by the judge)
1678ParameterError getparameter(const char *flag, /* f or -long-flag */
1679 const char *nextarg, /* NULL if unset */
1680 argv_item_t cleararg1,
1681 argv_item_t cleararg2,
1682 bool *usedarg, /* set to TRUE if the arg
1683 has been used */
1684 struct GlobalConfig *global,
1685 struct OperationConfig *config)
1686{
1687 const char *parse = NULL;
1688 bool longopt = FALSE;
1689 bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */
1690 size_t nopts = 0; /* options processed in `flag`*/
1691 ParameterError err = PARAM_OK;
1692 bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled
1693 by using --OPTION or --no-OPTION */
1694 bool nextalloc = FALSE; /* if nextarg is allocated */
1695 static const char *redir_protos[] = {
1696 "http",
1697 "https",
1698 "ftp",
1699 "ftps",
1700 NULL
1701 };
1702 const struct LongShort *a = NULL;
1703 curl_off_t value;
1704#ifdef HAVE_WRITABLE_ARGV
1705 argv_item_t clearthis = NULL;
1706#else
1707 (void)cleararg1;
1708 (void)cleararg2;
1709#endif
1710
1711 *usedarg = FALSE; /* default is that we do not use the arg */
1712
1713 if(('-' != flag[0]) || ('-' == flag[1])) {
1714 /* this should be a long name */
1715 const char *word = ('-' == flag[0]) ? flag + 2 : flag;
1716 bool noflagged = FALSE;
1717 bool expand = FALSE;
1718
1719 if(!strncmp(word, "no-", 3)) {
1720 /* disable this option but ignore the "no-" part when looking for it */
1721 word += 3;
1722 toggle = FALSE;
1723 noflagged = TRUE;
1724 }
1725 else if(!strncmp(word, "expand-", 7)) {
1726 /* variable expansions is to be done on the argument */
1727 word += 7;
1728 expand = TRUE;
1729 }
1730
1731 a = findlongopt(word);
1732 if(a) {
1733 longopt = TRUE;
1734 }
1735 else {
1736 err = PARAM_OPTION_UNKNOWN;
1737 goto error;
1738 }
1739 if(noflagged && (ARGTYPE(a->desc) != ARG_BOOL)) {
1740 /* --no- prefixed an option that is not boolean! */
1741 err = PARAM_NO_NOT_BOOLEAN;
1742 goto error;
1743 }
1744 else if(expand && nextarg) {
1745 struct curlx_dynbuf nbuf;
1746 bool replaced;
1747
1748 if((ARGTYPE(a->desc) != ARG_STRG) &&
1749 (ARGTYPE(a->desc) != ARG_FILE)) {
1750 /* --expand on an option that is not a string or a filename */
1751 err = PARAM_EXPAND_ERROR;
1752 goto error;
1753 }
1754 err = varexpand(global, nextarg, &nbuf, &replaced);
1755 if(err) {
1756 curlx_dyn_free(&nbuf);
1757 goto error;
1758 }
1759 if(replaced) {
1760 nextarg = curlx_dyn_ptr(&nbuf);
1761 nextalloc = TRUE;
1762 }
1763 }
1764 }
1765 else {
1766 flag++; /* prefixed with one dash, pass it */
1767 parse = flag;
1768 }
1769
1770 do {
1771 /* we can loop here if we have multiple single-letters */
1772 cmdline_t cmd;
1773
1774 if(!longopt && !a) {
1775 a = findshortopt(*parse);
1776 if(!a) {
1777 err = PARAM_OPTION_UNKNOWN;
1778 break;
1779 }
1780 }
1781 cmd = (cmdline_t)a->cmd;
1782 if(ARGTYPE(a->desc) >= ARG_STRG) {
1783 /* this option requires an extra parameter */
1784 if(!longopt && parse[1]) {
1785 nextarg = &parse[1]; /* this is the actual extra parameter */
1786 singleopt = TRUE; /* do not loop anymore after this */
1787#ifdef HAVE_WRITABLE_ARGV
1788 clearthis = &cleararg1[parse + 2 - flag];
1789#endif
1790 }
1791 else if(!nextarg) {
1792 err = PARAM_REQUIRES_PARAMETER;
1793 break;
1794 }
1795 else {
1796#ifdef HAVE_WRITABLE_ARGV
1797 clearthis = cleararg2;
1798#endif
1799 *usedarg = TRUE; /* mark it as used */
1800 }
1801
1802 if((ARGTYPE(a->desc) == ARG_FILE) &&
1803 (nextarg[0] == '-') && nextarg[1]) {
1804 /* if the filename looks like a command line option */
1805 warnf(global, "The filename argument '%s' looks like a flag.",
1806 nextarg);
1807 }
1808 else if(!strncmp("\xe2\x80\x9c", nextarg, 3)) {
1809 warnf(global, "The argument '%s' starts with a Unicode quote where "
1810 "maybe an ASCII \" was intended?",
1811 nextarg);
1812 }
1813 }
1814 else if((ARGTYPE(a->desc) == ARG_NONE) && !toggle) {
1815 err = PARAM_NO_PREFIX;
1816 break;
1817 }
1818 else if((a->desc & ARG_TLS) && !feature_ssl) {
1819 err = PARAM_LIBCURL_DOESNT_SUPPORT;
1820 break;
1821 }
1822
1823 if(!nextarg)
1824 /* this is a precaution mostly to please scan-build, as all arguments
1825 that use nextarg should be marked as such and they will check that
1826 nextarg is set before continuing, but code analyzers are not always
1827 that aware of that state */
1828 nextarg = "";
1829
1830 switch(cmd) {
1831 case C_RANDOM_FILE: /* --random-file */
1832 case C_EGD_FILE: /* --egd-file */
1833 case C_NTLM_WB: /* --ntlm-wb */
1834 warnf(global, "--%s is deprecated and has no function anymore",
1835 a->lname);
1836 break;
1837 case C_DNS_IPV4_ADDR: /* --dns-ipv4-addr */
1838 if(!curlinfo->ares_num) /* c-ares is needed for this */
src/curlinfo.clines 243–254 · definition of main
Show 12 lines (not cited by the judge)
243int main(int argc, char **argv)
244{
245 int i;
246
247 (void) argc;
248 (void) argv;
249
250 for(i = 0; disabled[i]; i++)
251 printf("%s\n", disabled[i]);
252
253 return 0;
254}
src/tool_operate.clines 3153–3295 · definition of operate
Show 143 lines (not cited by the judge)
3153CURLcode operate(struct GlobalConfig *global, int argc, argv_item_t argv[])
3154{
3155 CURLcode result = CURLE_OK;
3156 const char *first_arg;
3157#ifdef UNDER_CE
3158 first_arg = argc > 1 ? strdup(argv[1]) : NULL;
3159#else
3160 first_arg = argc > 1 ? convert_tchar_to_UTF8(argv[1]) : NULL;
3161#endif
3162
3163#ifdef HAVE_SETLOCALE
3164 /* Override locale for number parsing (only) */
3165 setlocale(LC_ALL, "");
3166 setlocale(LC_NUMERIC, "C");
3167#endif
3168
3169 /* Parse .curlrc if necessary */
3170 if((argc == 1) ||
3171 (first_arg && strncmp(first_arg, "-q", 2) &&
3172 strcmp(first_arg, "--disable"))) {
3173 parseconfig(NULL, global); /* ignore possible failure */
3174
3175 /* If we had no arguments then make sure a url was specified in .curlrc */
3176 if((argc < 2) && (!global->first->url_list)) {
3177 helpf(tool_stderr, NULL);
3178 result = CURLE_FAILED_INIT;
3179 }
3180 }
3181
3182 unicodefree(first_arg);
3183
3184 if(!result) {
3185 /* Parse the command line arguments */
3186 ParameterError res = parse_args(global, argc, argv);
3187 if(res) {
3188 result = CURLE_OK;
3189
3190 /* Check if we were asked for the help */
3191 if(res == PARAM_HELP_REQUESTED)
3192 tool_help(global->help_category);
3193 /* Check if we were asked for the manual */
3194 else if(res == PARAM_MANUAL_REQUESTED) {
3195#ifdef USE_MANUAL
3196 hugehelp();
3197#else
3198 puts("built-in manual was disabled at build-time");
3199#endif
3200 }
3201 /* Check if we were asked for the version information */
3202 else if(res == PARAM_VERSION_INFO_REQUESTED)
3203 tool_version_info();
3204 /* Check if we were asked to list the SSL engines */
3205 else if(res == PARAM_ENGINES_REQUESTED)
3206 tool_list_engines();
3207 /* Check if we were asked to dump the embedded CA bundle */
3208 else if(res == PARAM_CA_EMBED_REQUESTED) {
3209#ifdef CURL_CA_EMBED
3210 printf("%s", curl_ca_embed);
3211#endif
3212 }
3213 else if(res == PARAM_LIBCURL_UNSUPPORTED_PROTOCOL)
3214 result = CURLE_UNSUPPORTED_PROTOCOL;
3215 else if(res == PARAM_READ_ERROR)
3216 result = CURLE_READ_ERROR;
3217 else
3218 result = CURLE_FAILED_INIT;
3219 }
3220 else {
3221 if(global->libcurl) {
3222 /* Initialise the libcurl source output */
3223 result = easysrc_init();
3224 }
3225
3226 /* Perform the main operations */
3227 if(!result) {
3228 size_t count = 0;
3229 struct OperationConfig *operation = global->first;
3230 CURLSH *share = curl_share_init();
3231 if(!share) {
3232 if(global->libcurl) {
3233 /* Cleanup the libcurl source output */
3234 easysrc_cleanup();
3235 }
3236 result = CURLE_OUT_OF_MEMORY;
3237 }
3238
3239 if(!result) {
3240 curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
3241 curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
3242 curl_share_setopt(share, CURLSHOPT_SHARE,
3243 CURL_LOCK_DATA_SSL_SESSION);
3244 /* Running parallel, use the multi connection cache */
3245 if(!global->parallel)
3246 curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
3247 curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL);
3248 curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_HSTS);
3249
3250 if(global->ssl_sessions && feature_ssls_export)
3251 result = tool_ssls_load(global, global->first, share,
3252 global->ssl_sessions);
3253
3254 if(!result) {
3255 /* Get the required arguments for each operation */
3256 do {
3257 result = get_args(operation, count++);
3258
3259 operation = operation->next;
3260 } while(!result && operation);
3261
3262 /* Set the current operation pointer */
3263 global->current = global->first;
3264
3265 /* now run! */
3266 result = run_all_transfers(global, share, result);
3267
3268 if(global->ssl_sessions && feature_ssls_export) {
3269 CURLcode r2 = tool_ssls_save(global, global->first, share,
3270 global->ssl_sessions);
3271 if(r2 && !result)
3272 result = r2;
3273 }
3274 }
3275
3276 curl_share_cleanup(share);
3277 if(global->libcurl) {
3278 /* Cleanup the libcurl source output */
3279 easysrc_cleanup();
3280
3281 /* Dump the libcurl code if previously enabled */
3282 dumpeasysrc(global);
3283 }
3284 }
3285 }
3286 else
3287 errorf(global, "out of memory");
3288 }
3289 }
3290
3291 varcleanup(global);
3292 curl_free(global->knownhosts);
3293
3294 return result;
3295}
src/tool_getparam.clines 2988–3092 · definition of parse_args
Show 105 lines (not cited by the judge)
2988ParameterError parse_args(struct GlobalConfig *global, int argc,
2989 argv_item_t argv[])
2990{
2991 int i;
2992 bool stillflags;
2993 const char *orig_opt = NULL;
2994 ParameterError result = PARAM_OK;
2995 struct OperationConfig *config = global->first;
2996
2997 for(i = 1, stillflags = TRUE; i < argc && !result; i++) {
2998 orig_opt = convert_tchar_to_UTF8(argv[i]);
2999 if(!orig_opt)
3000 return PARAM_NO_MEM;
3001
3002 if(stillflags && ('-' == orig_opt[0])) {
3003 bool passarg;
3004
3005 if(!strcmp("--", orig_opt))
3006 /* This indicates the end of the flags and thus enables the
3007 following (URL) argument to start with -. */
3008 stillflags = FALSE;
3009 else {
3010 const char *nextarg = NULL;
3011 if(i < (argc - 1)) {
3012 nextarg = convert_tchar_to_UTF8(argv[i + 1]);
3013 if(!nextarg) {
3014 unicodefree(orig_opt);
3015 return PARAM_NO_MEM;
3016 }
3017 }
3018
3019 result = getparameter(orig_opt, nextarg, argv[i], argv[i + 1],
3020 &passarg, global, config);
3021
3022 unicodefree(nextarg);
3023 config = global->last;
3024 if(result == PARAM_NEXT_OPERATION) {
3025 /* Reset result as PARAM_NEXT_OPERATION is only used here and not
3026 returned from this function */
3027 result = PARAM_OK;
3028
3029 if(config->url_list && config->url_list->url) {
3030 /* Allocate the next config */
3031 config->next = malloc(sizeof(struct OperationConfig));
3032 if(config->next) {
3033 /* Initialise the newly created config */
3034 config_init(config->next);
3035
3036 /* Set the global config pointer */
3037 config->next->global = global;
3038
3039 /* Update the last config pointer */
3040 global->last = config->next;
3041
3042 /* Move onto the new config */
3043 config->next->prev = config;
3044 config = config->next;
3045 }
3046 else
3047 result = PARAM_NO_MEM;
3048 }
3049 else {
3050 errorf(global, "missing URL before --next");
3051 result = PARAM_BAD_USE;
3052 }
3053 }
3054 else if(!result && passarg)
3055 i++; /* we are supposed to skip this */
3056 }
3057 }
3058 else {
3059 bool used;
3060
3061 /* Just add the URL please */
3062 result = getparameter("--url", orig_opt, NULL, NULL,
3063 &used, global, config);
3064 }
3065
3066 if(!result) {
3067 unicodefree(orig_opt);
3068 orig_opt = NULL;
3069 }
3070 }
3071
3072 if(!result && config->content_disposition) {
3073 if(config->resume_from_current)
3074 result = PARAM_CONTDISP_RESUME_FROM;
3075 }
3076
3077 if(result && result != PARAM_HELP_REQUESTED &&
3078 result != PARAM_MANUAL_REQUESTED &&
3079 result != PARAM_VERSION_INFO_REQUESTED &&
3080 result != PARAM_ENGINES_REQUESTED &&
3081 result != PARAM_CA_EMBED_REQUESTED) {
3082 const char *reason = param2text(result);
3083
3084 if(orig_opt && strcmp(":", orig_opt))
3085 helpf(tool_stderr, "option %s: %s", orig_opt, reason);
3086 else
3087 helpf(tool_stderr, "%s", reason);
3088 }
3089
3090 unicodefree(orig_opt);
3091 return result;
3092}
src/tool_getparam.c@curl-8_13_0lines 2985–3087 · definition of parse_args as in release curl-8_13_0; differs from master; commits that changed it since: 1c6fc0cd2b curlx: simplify the curlx_unicodefree macro
Show 103 lines (not cited by the judge)
2985ParameterError parse_args(struct GlobalConfig *global, int argc,
2986 argv_item_t argv[])
2987{
2988 int i;
2989 bool stillflags;
2990 const char *orig_opt = NULL;
2991 ParameterError result = PARAM_OK;
2992 struct OperationConfig *config = global->first;
2993
2994 for(i = 1, stillflags = TRUE; i < argc && !result; i++) {
2995 orig_opt = convert_tchar_to_UTF8(argv[i]);
2996 if(!orig_opt)
2997 return PARAM_NO_MEM;
2998
2999 if(stillflags && ('-' == orig_opt[0])) {
3000 bool passarg;
3001
3002 if(!strcmp("--", orig_opt))
3003 /* This indicates the end of the flags and thus enables the
3004 following (URL) argument to start with -. */
3005 stillflags = FALSE;
3006 else {
3007 const char *nextarg = NULL;
3008 if(i < (argc - 1)) {
3009 nextarg = convert_tchar_to_UTF8(argv[i + 1]);
3010 if(!nextarg) {
3011 unicodefree(orig_opt);
3012 return PARAM_NO_MEM;
3013 }
3014 }
3015
3016 result = getparameter(orig_opt, nextarg, argv[i], argv[i + 1],
3017 &passarg, global, config);
3018
3019 unicodefree(nextarg);
3020 config = global->last;
3021 if(result == PARAM_NEXT_OPERATION) {
3022 /* Reset result as PARAM_NEXT_OPERATION is only used here and not
3023 returned from this function */
3024 result = PARAM_OK;
3025
3026 if(config->url_list && config->url_list->url) {
3027 /* Allocate the next config */
3028 config->next = malloc(sizeof(struct OperationConfig));
3029 if(config->next) {
3030 /* Initialise the newly created config */
3031 config_init(config->next);
3032
3033 /* Set the global config pointer */
3034 config->next->global = global;
3035
3036 /* Update the last config pointer */
3037 global->last = config->next;
3038
3039 /* Move onto the new config */
3040 config->next->prev = config;
3041 config = config->next;
3042 }
3043 else
3044 result = PARAM_NO_MEM;
3045 }
3046 else {
3047 errorf(global, "missing URL before --next");
3048 result = PARAM_BAD_USE;
3049 }
3050 }
3051 else if(!result && passarg)
3052 i++; /* we are supposed to skip this */
3053 }
3054 }
3055 else {
3056 bool used;
3057
3058 /* Just add the URL please */
3059 result = getparameter("--url", orig_opt, NULL, NULL,
3060 &used, global, config);
3061 }
3062
3063 if(!result)
3064 unicodefree(orig_opt);
3065 }
3066
3067 if(!result && config->content_disposition) {
3068 if(config->resume_from_current)
3069 result = PARAM_CONTDISP_RESUME_FROM;
3070 }
3071
3072 if(result && result != PARAM_HELP_REQUESTED &&
3073 result != PARAM_MANUAL_REQUESTED &&
3074 result != PARAM_VERSION_INFO_REQUESTED &&
3075 result != PARAM_ENGINES_REQUESTED &&
3076 result != PARAM_CA_EMBED_REQUESTED) {
3077 const char *reason = param2text(result);
3078
3079 if(orig_opt && strcmp(":", orig_opt))
3080 helpf(tool_stderr, "option %s: %s", orig_opt, reason);
3081 else
3082 helpf(tool_stderr, "%s", reason);
3083 }
3084
3085 unicodefree(orig_opt);
3086 return result;
3087}
src/tool_parsecfg.c@curl-8_13_0lines 48–208 · definition of parseconfig as in release curl-8_13_0; differs from master; commits that changed it since: d689bd915e src: rename curlx_safefree to tool_safefree | 255aac56f9 curlx: move into to curlx/
Show 161 lines (not cited by the judge)
48int parseconfig(const char *filename, struct GlobalConfig *global)
49{
50 FILE *file = NULL;
51 bool usedarg = FALSE;
52 int rc = 0;
53 struct OperationConfig *operation = global->last;
54 char *pathalloc = NULL;
55
56 if(!filename) {
57 /* NULL means load .curlrc from homedir! */
58 char *curlrc = findfile(".curlrc", CURLRC_DOTSCORE);
59 if(curlrc) {
60 file = fopen(curlrc, FOPEN_READTEXT);
61 if(!file) {
62 free(curlrc);
63 return 1;
64 }
65 filename = pathalloc = curlrc;
66 }
67#if defined(_WIN32) && !defined(UNDER_CE)
68 else {
69 char *fullp;
70 /* check for .curlrc then _curlrc in the dir of the executable */
71 file = tool_execpath(".curlrc", &fullp);
72 if(!file)
73 file = tool_execpath("_curlrc", &fullp);
74 if(file)
75 /* this is the filename we read from */
76 filename = fullp;
77 }
78#endif
79 }
80 else {
81 if(strcmp(filename, "-"))
82 file = fopen(filename, FOPEN_READTEXT);
83 else
84 file = stdin;
85 }
86
87 if(file) {
88 char *line;
89 char *option;
90 char *param;
91 int lineno = 0;
92 bool dashed_option;
93 struct curlx_dynbuf buf;
94 bool fileerror = FALSE;
95 curlx_dyn_init(&buf, MAX_CONFIG_LINE_LENGTH);
96 DEBUGASSERT(filename);
97
98 while(!rc && my_get_line(file, &buf, &fileerror)) {
99 ParameterError res;
100 bool alloced_param = FALSE;
101 lineno++;
102 line = curlx_dyn_ptr(&buf);
103 if(!line) {
104 rc = 1; /* out of memory */
105 break;
106 }
107
108 /* the option keywords starts here */
109 option = line;
110
111 /* the option starts with a dash? */
112 dashed_option = (option[0] == '-');
113
114 while(*line && !ISBLANK(*line) && !ISSEP(*line, dashed_option))
115 line++;
116 /* ... and has ended here */
117
118 if(*line)
119 *line++ = '\0'; /* null-terminate, we have a local copy of the data */
120
121#ifdef DEBUG_CONFIG
122 fprintf(tool_stderr, "GOT: %s\n", option);
123#endif
124
125 /* pass spaces and separator(s) */
126 while(ISBLANK(*line) || ISSEP(*line, dashed_option))
127 line++;
128
129 /* the parameter starts here (unless quoted) */
130 if(*line == '\"') {
131 /* quoted parameter, do the quote dance */
132 line++;
133 param = malloc(strlen(line) + 1); /* parameter */
134 if(!param) {
135 /* out of memory */
136 rc = 1;
137 break;
138 }
139 alloced_param = TRUE;
140 (void)unslashquote(line, param);
141 }
142 else {
143 param = line; /* parameter starts here */
144 while(*line && !ISSPACE(*line)) /* stop also on CRLF */
145 line++;
146
147 if(*line) {
148 *line = '\0'; /* null-terminate */
149
150 /* to detect mistakes better, see if there is data following */
151 line++;
152 /* pass all spaces */
153 while(ISBLANK(*line))
154 line++;
155
156 switch(*line) {
157 case '\0':
158 case '\r':
159 case '\n':
160 case '#': /* comment */
161 break;
162 default:
163 warnf(operation->global, "%s:%d: warning: '%s' uses unquoted "
164 "whitespace", filename, lineno, option);
165 warnf(operation->global, "This may cause side-effects. "
166 "Consider using double quotes?");
167 }
168 }
169 if(!*param)
170 /* do this so getparameter can check for required parameters.
171 Otherwise it always thinks there is a parameter. */
172 param = NULL;
173 }
174
175#ifdef DEBUG_CONFIG
176 fprintf(tool_stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
177#endif
178 res = getparameter(option, param, NULL, NULL,
179 &usedarg, global, operation);
180 operation = global->last;
181
182 if(!res && param && *param && !usedarg)
183 /* we passed in a parameter that was not used! */
184 res = PARAM_GOT_EXTRA_PARAMETER;
185
186 if(res == PARAM_NEXT_OPERATION) {
187 if(operation->url_list && operation->url_list->url) {
188 /* Allocate the next config */
189 operation->next = malloc(sizeof(struct OperationConfig));
190 if(operation->next) {
191 /* Initialise the newly created config */
192 config_init(operation->next);
193
194 /* Set the global config pointer */
195 operation->next->global = global;
196
197 /* Update the last operation pointer */
198 global->last = operation->next;
199
200 /* Move onto the new config */
201 operation->next->prev = operation;
202 operation = operation->next;
203 }
204 else
205 res = PARAM_NO_MEM;
206 }
207 }
208
lib/curl_memory.hlines 141–141 · definition of strdup
Show 1 lines (not cited by the judge)
141#define strdup(ptr) Curl_cstrdup(ptr)