/src/curl_fuzzer/full_coverage/public_api.cc
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) Max Dymond, <cmeister2@gmail.com>, et al. |
3 | | * |
4 | | * SPDX-License-Identifier: curl |
5 | | */ |
6 | | |
7 | | #include "full_coverage/public_api.h" |
8 | | |
9 | | #include <cstdarg> |
10 | | #include <cstdio> |
11 | | |
12 | | #include <curl/curl.h> |
13 | | #include <curl/mprintf.h> |
14 | | |
15 | | namespace full_coverage { |
16 | | namespace { |
17 | | |
18 | | /** Reuse a valid argument list across the public va_list formatting APIs. */ |
19 | | void ExerciseVariadicFormatting(FILE *stream, const char *format, ...) |
20 | 0 | { |
21 | 0 | char buffer[4096]; |
22 | 0 | va_list args; |
23 | 0 | va_start(args, format); |
24 | 0 | va_list copy; |
25 | 0 | va_copy(copy, args); |
26 | 0 | curl_mvsnprintf(buffer, sizeof(buffer), format, copy); |
27 | 0 | va_end(copy); |
28 | 0 | va_copy(copy, args); |
29 | 0 | curl_mvsnprintf(buffer, 1, format, copy); |
30 | 0 | va_end(copy); |
31 | 0 | va_copy(copy, args); |
32 | 0 | curl_mvsprintf(buffer, format, copy); |
33 | 0 | va_end(copy); |
34 | 0 | va_copy(copy, args); |
35 | 0 | curl_free(curl_mvaprintf(format, copy)); |
36 | 0 | va_end(copy); |
37 | 0 | if(stream) { |
38 | 0 | va_copy(copy, args); |
39 | 0 | curl_mvfprintf(stream, format, copy); |
40 | 0 | va_end(copy); |
41 | 0 | } |
42 | 0 | va_end(args); |
43 | 0 | } |
44 | | |
45 | | /** Exercise the stdout va_list wrapper with an empty formatted result. */ |
46 | | void ExerciseVariadicStdout(const char *format, ...) |
47 | 0 | { |
48 | 0 | va_list args; |
49 | 0 | va_start(args, format); |
50 | 0 | curl_mvprintf(format, args); |
51 | 0 | va_end(args); |
52 | 0 | } |
53 | | |
54 | | /** Consume the in-memory serialization produced by the legacy form API. */ |
55 | | size_t DiscardFormData(void *, const char *, size_t length) |
56 | 0 | { |
57 | 0 | return length; |
58 | 0 | } |
59 | | |
60 | | /** Keep deprecated, still-supported form helpers reachable in profiling. */ |
61 | | void ExerciseLegacyForms() |
62 | 0 | { |
63 | 0 | curl_httppost *first = nullptr; |
64 | 0 | curl_httppost *last = nullptr; |
65 | 0 | curl_formadd(&first, &last, CURLFORM_COPYNAME, "field", |
66 | 0 | CURLFORM_COPYCONTENTS, "value", CURLFORM_END); |
67 | 0 | const char contents[] = "file contents"; |
68 | 0 | curl_formadd(&first, &last, CURLFORM_COPYNAME, "attachment", |
69 | 0 | CURLFORM_BUFFER, "example.txt", CURLFORM_BUFFERPTR, contents, |
70 | 0 | CURLFORM_BUFFERLENGTH, static_cast<long>(sizeof(contents) - 1), |
71 | 0 | CURLFORM_CONTENTTYPE, "text/plain", CURLFORM_END); |
72 | 0 | curl_forms fields[] = { |
73 | 0 | {CURLFORM_COPYNAME, "array-field"}, |
74 | 0 | {CURLFORM_COPYCONTENTS, "array-value"}, |
75 | 0 | {CURLFORM_END, nullptr}}; |
76 | 0 | curl_formadd(&first, &last, CURLFORM_ARRAY, fields, CURLFORM_END); |
77 | | // Multiple files in one field create the legacy API's subordinate chain. |
78 | | // /dev/null supplies a deterministic, empty local file for serialization. |
79 | 0 | curl_formadd(&first, &last, CURLFORM_COPYNAME, "empty-files", |
80 | 0 | CURLFORM_FILE, "/dev/null", CURLFORM_CONTENTTYPE, "text/plain", |
81 | 0 | CURLFORM_FILE, "/dev/null", CURLFORM_FILENAME, "empty.txt", |
82 | 0 | CURLFORM_END); |
83 | | |
84 | | // A name containing NUL bytes is documented as invalid. Put it on the last |
85 | | // of three files so rejection cleans up both copied fields and a partially |
86 | | // constructed subordinate chain, while preserving the previously added form. |
87 | 0 | char invalid_name[] = {'a', '\0', 'b'}; |
88 | 0 | curl_formadd(&first, &last, CURLFORM_COPYNAME, "invalid-files", |
89 | 0 | CURLFORM_FILE, "/dev/null", CURLFORM_FILE, "/dev/null", |
90 | 0 | CURLFORM_FILE, "/dev/null", CURLFORM_COPYNAME, invalid_name, |
91 | 0 | CURLFORM_NAMELENGTH, static_cast<long>(sizeof(invalid_name)), |
92 | 0 | CURLFORM_END); |
93 | 0 | if(first) |
94 | 0 | curl_formget(first, nullptr, DiscardFormData); |
95 | 0 | curl_formfree(first); |
96 | 0 | curl_formfree(nullptr); |
97 | 0 | } |
98 | | |
99 | | } // namespace |
100 | | |
101 | | void ExercisePublicApiCoverage() |
102 | 0 | { |
103 | 0 | if(curl_global_init(CURL_GLOBAL_DEFAULT) != CURLE_OK) |
104 | 0 | return; |
105 | | |
106 | 0 | char buffer[4096]; |
107 | 0 | curl_msnprintf(buffer, sizeof(buffer), |
108 | 0 | "%+08d %i %u %#o %#x %#X %ld %lu %lld %llu %%", |
109 | 0 | -42, 0, 42U, 42U, 42U, 42U, -42L, 42UL, -42LL, 42ULL); |
110 | 0 | curl_msnprintf(buffer, sizeof(buffer), "%*.*s %c %p", |
111 | 0 | -12, 4, "example", 'x', static_cast<void *>(buffer)); |
112 | 0 | curl_msnprintf(buffer, sizeof(buffer), "%+.3f %.2e %g %G", |
113 | 0 | 1.25, -1.25, 0.00125, 12500.0); |
114 | 0 | curl_msnprintf(buffer, 1, "%s", "truncated"); |
115 | 0 | curl_msnprintf(buffer, 0, "%s", "zero-capacity"); |
116 | 0 | curl_msprintf(buffer, "%s:%d", "value", 42); |
117 | 0 | curl_free(curl_maprintf("%2$s:%1$d", 42, "position")); |
118 | | // The stdout wrappers remain quiet while covering their public entrypoints. |
119 | 0 | curl_mprintf("%s", ""); |
120 | 0 | ExerciseVariadicStdout("%s", ""); |
121 | |
|
122 | 0 | FILE *stream = std::tmpfile(); |
123 | 0 | if(stream) |
124 | 0 | curl_mfprintf(stream, "%s:%d", "stream", 42); |
125 | 0 | ExerciseVariadicFormatting(stream, "%s:%+08d:%.2f", "variadic", -42, 1.25); |
126 | 0 | if(stream) |
127 | 0 | std::fclose(stream); |
128 | |
|
129 | 0 | ExerciseLegacyForms(); |
130 | 0 | curl_global_cleanup(); |
131 | 0 | } |
132 | | |
133 | | } // namespace full_coverage |