/work/obj-fuzz/dist/include/mozilla/CmdLineAndEnvUtils.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef mozilla_CmdLineAndEnvUtils_h |
8 | | #define mozilla_CmdLineAndEnvUtils_h |
9 | | |
10 | | // NB: This code may be used outside of xul and thus must not depend on XPCOM |
11 | | |
12 | | #if defined(MOZILLA_INTERNAL_API) |
13 | | #include "prenv.h" |
14 | | #include "prprf.h" |
15 | | #include <string.h> |
16 | | #elif defined(XP_WIN) |
17 | | #include <stdlib.h> |
18 | | #endif |
19 | | |
20 | | #if defined(XP_WIN) |
21 | | #include "mozilla/Move.h" |
22 | | #include "mozilla/UniquePtr.h" |
23 | | #include "mozilla/Vector.h" |
24 | | |
25 | | #include <wchar.h> |
26 | | #include <windows.h> |
27 | | #endif // defined(XP_WIN) |
28 | | |
29 | | #include "mozilla/MemoryChecking.h" |
30 | | #include "mozilla/TypedEnumBits.h" |
31 | | |
32 | | #include <ctype.h> |
33 | | #include <stdint.h> |
34 | | |
35 | | // Undo X11/X.h's definition of None |
36 | | #undef None |
37 | | |
38 | | namespace mozilla { |
39 | | |
40 | | enum ArgResult { |
41 | | ARG_NONE = 0, |
42 | | ARG_FOUND = 1, |
43 | | ARG_BAD = 2 // you wanted a param, but there isn't one |
44 | | }; |
45 | | |
46 | | template <typename CharT> |
47 | | inline void |
48 | | RemoveArg(int& argc, CharT **argv) |
49 | 0 | { |
50 | 0 | do { |
51 | 0 | *argv = *(argv + 1); |
52 | 0 | ++argv; |
53 | 0 | } while (*argv); |
54 | 0 |
|
55 | 0 | --argc; |
56 | 0 | } |
57 | | |
58 | | namespace internal { |
59 | | |
60 | | template <typename FuncT, typename CharT> |
61 | | static inline bool |
62 | | strimatch(FuncT aToLowerFn, const CharT* lowerstr, const CharT* mixedstr) |
63 | 126 | { |
64 | 129 | while(*lowerstr) { |
65 | 129 | if (!*mixedstr) return false; // mixedstr is shorter |
66 | 129 | if (static_cast<CharT>(aToLowerFn(*mixedstr)) != *lowerstr) return false; // no match |
67 | 3 | |
68 | 3 | ++lowerstr; |
69 | 3 | ++mixedstr; |
70 | 3 | } |
71 | 126 | |
72 | 126 | if (*mixedstr) return false; // lowerstr is shorter |
73 | 0 | |
74 | 0 | return true; |
75 | 0 | } nsAppRunner.cpp:bool mozilla::internal::strimatch<int (*)(int), char>(int (*)(int), char const*, char const*) Line | Count | Source | 63 | 126 | { | 64 | 129 | while(*lowerstr) { | 65 | 129 | if (!*mixedstr) return false; // mixedstr is shorter | 66 | 129 | if (static_cast<CharT>(aToLowerFn(*mixedstr)) != *lowerstr) return false; // no match | 67 | 3 | | 68 | 3 | ++lowerstr; | 69 | 3 | ++mixedstr; | 70 | 3 | } | 71 | 126 | | 72 | 126 | if (*mixedstr) return false; // lowerstr is shorter | 73 | 0 | | 74 | 0 | return true; | 75 | 0 | } |
Unexecuted instantiation: nsAppRunner.cpp:bool mozilla::internal::strimatch<unsigned int (*)(unsigned int), wchar_t>(unsigned int (*)(unsigned int), wchar_t const*, wchar_t const*) |
76 | | |
77 | | } // namespace internal |
78 | | |
79 | | inline bool |
80 | | strimatch(const char* lowerstr, const char* mixedstr) |
81 | 126 | { |
82 | 126 | return internal::strimatch(&tolower, lowerstr, mixedstr); |
83 | 126 | } |
84 | | |
85 | | inline bool |
86 | | strimatch(const wchar_t* lowerstr, const wchar_t* mixedstr) |
87 | 0 | { |
88 | 0 | return internal::strimatch(&towlower, lowerstr, mixedstr); |
89 | 0 | } |
90 | | |
91 | | enum class FlagLiteral |
92 | | { |
93 | | osint, |
94 | | safemode |
95 | | }; |
96 | | |
97 | | template <typename CharT, FlagLiteral Literal> |
98 | | inline const CharT* GetLiteral(); |
99 | | |
100 | | #define DECLARE_FLAG_LITERAL(enum_name, literal) \ |
101 | | template <> inline \ |
102 | | const char* GetLiteral<char, FlagLiteral::enum_name>() \ |
103 | 3 | { \ |
104 | 3 | return literal; \ |
105 | 3 | } \ Unexecuted instantiation: char const* mozilla::GetLiteral<char, (mozilla::FlagLiteral)0>() char const* mozilla::GetLiteral<char, (mozilla::FlagLiteral)1>() Line | Count | Source | 103 | 3 | { \ | 104 | 3 | return literal; \ | 105 | 3 | } \ |
|
106 | | \ |
107 | | template <> inline \ |
108 | | const wchar_t* GetLiteral<wchar_t, FlagLiteral::enum_name>() \ |
109 | 0 | { \ |
110 | 0 | return L##literal; \ |
111 | 0 | } Unexecuted instantiation: wchar_t const* mozilla::GetLiteral<wchar_t, (mozilla::FlagLiteral)0>() Unexecuted instantiation: wchar_t const* mozilla::GetLiteral<wchar_t, (mozilla::FlagLiteral)1>() |
112 | | |
113 | | DECLARE_FLAG_LITERAL(osint, "osint") |
114 | | DECLARE_FLAG_LITERAL(safemode, "safe-mode") |
115 | | |
116 | | enum class CheckArgFlag : uint32_t |
117 | | { |
118 | | None = 0, |
119 | | CheckOSInt = (1 << 0), // Retrun ARG_BAD if osint arg is also present. |
120 | | RemoveArg = (1 << 1) // Remove the argument from the argv array. |
121 | | }; |
122 | | |
123 | | MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CheckArgFlag) |
124 | | |
125 | | /** |
126 | | * Check for a commandline flag. If the flag takes a parameter, the |
127 | | * parameter is returned in aParam. Flags may be in the form -arg or |
128 | | * --arg (or /arg on win32). |
129 | | * |
130 | | * @param aArgc The argc value. |
131 | | * @param aArgv The original argv. |
132 | | * @param aArg the parameter to check. Must be lowercase. |
133 | | * @param aParam if non-null, the -arg <data> will be stored in this pointer. |
134 | | * This is *not* allocated, but rather a pointer to the argv data. |
135 | | * @param aFlags Flags @see CheckArgFlag |
136 | | */ |
137 | | template <typename CharT> |
138 | | inline ArgResult |
139 | | CheckArg(int& aArgc, CharT** aArgv, const CharT* aArg, const CharT **aParam, |
140 | | CheckArgFlag aFlags) |
141 | 42 | { |
142 | 42 | MOZ_ASSERT(aArgv && aArg); |
143 | 42 | |
144 | 42 | CharT **curarg = aArgv + 1; // skip argv[0] |
145 | 42 | ArgResult ar = ARG_NONE; |
146 | 42 | |
147 | 210 | while (*curarg) { |
148 | 168 | CharT *arg = curarg[0]; |
149 | 168 | |
150 | 168 | if (arg[0] == '-' |
151 | | #if defined(XP_WIN) |
152 | | || *arg == '/' |
153 | | #endif |
154 | 126 | ) { |
155 | 126 | ++arg; |
156 | 126 | |
157 | 126 | if (*arg == '-') { |
158 | 0 | ++arg; |
159 | 0 | } |
160 | 126 | |
161 | 126 | if (strimatch(aArg, arg)) { |
162 | 0 | if (aFlags & CheckArgFlag::RemoveArg) { |
163 | 0 | RemoveArg(aArgc, curarg); |
164 | 0 | } else { |
165 | 0 | ++curarg; |
166 | 0 | } |
167 | 0 |
|
168 | 0 | if (!aParam) { |
169 | 0 | ar = ARG_FOUND; |
170 | 0 | break; |
171 | 0 | } |
172 | 0 | |
173 | 0 | if (*curarg) { |
174 | 0 | if (**curarg == '-' |
175 | | #if defined(XP_WIN) |
176 | | || **curarg == '/' |
177 | | #endif |
178 | 0 | ) { |
179 | 0 | return ARG_BAD; |
180 | 0 | } |
181 | 0 | |
182 | 0 | *aParam = *curarg; |
183 | 0 |
|
184 | 0 | if (aFlags & CheckArgFlag::RemoveArg) { |
185 | 0 | RemoveArg(aArgc, curarg); |
186 | 0 | } |
187 | 0 |
|
188 | 0 | ar = ARG_FOUND; |
189 | 0 | break; |
190 | 0 | } |
191 | 0 |
|
192 | 0 | return ARG_BAD; |
193 | 0 | } |
194 | 126 | } |
195 | 168 | |
196 | 168 | ++curarg; |
197 | 168 | } |
198 | 42 | |
199 | 42 | if ((aFlags & CheckArgFlag::CheckOSInt) && ar == ARG_FOUND) { |
200 | 0 | ArgResult arOSInt = CheckArg(aArgc, aArgv, |
201 | 0 | GetLiteral<CharT, FlagLiteral::osint>(), |
202 | 0 | static_cast<const CharT**>(nullptr), |
203 | 0 | CheckArgFlag::None); |
204 | 0 | if (arOSInt == ARG_FOUND) { |
205 | 0 | ar = ARG_BAD; |
206 | 0 | #if defined(MOZILLA_INTERNAL_API) |
207 | 0 | PR_fprintf(PR_STDERR, "Error: argument --osint is invalid\n"); |
208 | 0 | #endif // defined(MOZILLA_INTERNAL_API) |
209 | 0 | } |
210 | 0 | } |
211 | 42 | |
212 | 42 | return ar; |
213 | 42 | } |
214 | | |
215 | | #if defined(XP_WIN) |
216 | | |
217 | | namespace internal { |
218 | | |
219 | | /** |
220 | | * Get the length that the string will take and takes into account the |
221 | | * additional length if the string needs to be quoted and if characters need to |
222 | | * be escaped. |
223 | | */ |
224 | | inline int |
225 | | ArgStrLen(const wchar_t *s) |
226 | | { |
227 | | int backslashes = 0; |
228 | | int i = wcslen(s); |
229 | | bool hasDoubleQuote = wcschr(s, L'"') != nullptr; |
230 | | // Only add doublequotes if the string contains a space or a tab |
231 | | bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; |
232 | | |
233 | | if (addDoubleQuotes) { |
234 | | i += 2; // initial and final duoblequote |
235 | | } |
236 | | |
237 | | if (hasDoubleQuote) { |
238 | | while (*s) { |
239 | | if (*s == '\\') { |
240 | | ++backslashes; |
241 | | } else { |
242 | | if (*s == '"') { |
243 | | // Escape the doublequote and all backslashes preceding the doublequote |
244 | | i += backslashes + 1; |
245 | | } |
246 | | |
247 | | backslashes = 0; |
248 | | } |
249 | | |
250 | | ++s; |
251 | | } |
252 | | } |
253 | | |
254 | | return i; |
255 | | } |
256 | | |
257 | | /** |
258 | | * Copy string "s" to string "d", quoting the argument as appropriate and |
259 | | * escaping doublequotes along with any backslashes that immediately precede |
260 | | * doublequotes. |
261 | | * The CRT parses this to retrieve the original argc/argv that we meant, |
262 | | * see STDARGV.C in the MSVC CRT sources. |
263 | | * |
264 | | * @return the end of the string |
265 | | */ |
266 | | inline wchar_t* |
267 | | ArgToString(wchar_t *d, const wchar_t *s) |
268 | | { |
269 | | int backslashes = 0; |
270 | | bool hasDoubleQuote = wcschr(s, L'"') != nullptr; |
271 | | // Only add doublequotes if the string contains a space or a tab |
272 | | bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr; |
273 | | |
274 | | if (addDoubleQuotes) { |
275 | | *d = '"'; // initial doublequote |
276 | | ++d; |
277 | | } |
278 | | |
279 | | if (hasDoubleQuote) { |
280 | | int i; |
281 | | while (*s) { |
282 | | if (*s == '\\') { |
283 | | ++backslashes; |
284 | | } else { |
285 | | if (*s == '"') { |
286 | | // Escape the doublequote and all backslashes preceding the doublequote |
287 | | for (i = 0; i <= backslashes; ++i) { |
288 | | *d = '\\'; |
289 | | ++d; |
290 | | } |
291 | | } |
292 | | |
293 | | backslashes = 0; |
294 | | } |
295 | | |
296 | | *d = *s; |
297 | | ++d; ++s; |
298 | | } |
299 | | } else { |
300 | | wcscpy(d, s); |
301 | | d += wcslen(s); |
302 | | } |
303 | | |
304 | | if (addDoubleQuotes) { |
305 | | *d = '"'; // final doublequote |
306 | | ++d; |
307 | | } |
308 | | |
309 | | return d; |
310 | | } |
311 | | |
312 | | } // namespace internal |
313 | | |
314 | | /** |
315 | | * Creates a command line from a list of arguments. |
316 | | */ |
317 | | inline UniquePtr<wchar_t[]> |
318 | | MakeCommandLine(int argc, wchar_t **argv) |
319 | | { |
320 | | int i; |
321 | | int len = 0; |
322 | | |
323 | | // The + 1 of the last argument handles the allocation for null termination |
324 | | for (i = 0; i < argc; ++i) { |
325 | | len += internal::ArgStrLen(argv[i]) + 1; |
326 | | } |
327 | | |
328 | | // Protect against callers that pass 0 arguments |
329 | | if (len == 0) { |
330 | | len = 1; |
331 | | } |
332 | | |
333 | | auto s = MakeUnique<wchar_t[]>(len); |
334 | | if (!s) { |
335 | | return s; |
336 | | } |
337 | | |
338 | | wchar_t *c = s.get(); |
339 | | for (i = 0; i < argc; ++i) { |
340 | | c = internal::ArgToString(c, argv[i]); |
341 | | if (i + 1 != argc) { |
342 | | *c = ' '; |
343 | | ++c; |
344 | | } |
345 | | } |
346 | | |
347 | | *c = '\0'; |
348 | | |
349 | | return s; |
350 | | } |
351 | | |
352 | | inline bool |
353 | | SetArgv0ToFullBinaryPath(wchar_t* aArgv[]) |
354 | | { |
355 | | if (!aArgv) { |
356 | | return false; |
357 | | } |
358 | | |
359 | | DWORD bufLen = MAX_PATH; |
360 | | mozilla::UniquePtr<wchar_t[]> buf; |
361 | | DWORD retLen; |
362 | | |
363 | | while (true) { |
364 | | buf = mozilla::MakeUnique<wchar_t[]>(bufLen); |
365 | | retLen = ::GetModuleFileNameW(nullptr, buf.get(), bufLen); |
366 | | if (!retLen) { |
367 | | return false; |
368 | | } |
369 | | |
370 | | if (retLen == bufLen && ::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { |
371 | | bufLen *= 2; |
372 | | continue; |
373 | | } |
374 | | |
375 | | break; |
376 | | } |
377 | | |
378 | | // Upon success, retLen *excludes* the null character |
379 | | ++retLen; |
380 | | |
381 | | // Since we're likely to have a bunch of unused space in buf, let's reallocate |
382 | | // a string to the actual size of the file name. |
383 | | auto newArgv_0 = mozilla::MakeUnique<wchar_t[]>(retLen); |
384 | | if (wcscpy_s(newArgv_0.get(), retLen, buf.get())) { |
385 | | return false; |
386 | | } |
387 | | |
388 | | // We intentionally leak newArgv_0 into argv[0] |
389 | | aArgv[0] = newArgv_0.release(); |
390 | | MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(aArgv[0]); |
391 | | return true; |
392 | | } |
393 | | |
394 | | #endif // defined(XP_WIN) |
395 | | |
396 | | // Save literal putenv string to environment variable. |
397 | | inline void |
398 | | SaveToEnv(const char *aEnvString) |
399 | 6 | { |
400 | 6 | #if defined(MOZILLA_INTERNAL_API) |
401 | 6 | char *expr = strdup(aEnvString); |
402 | 6 | if (expr) { |
403 | 6 | PR_SetEnv(expr); |
404 | 6 | } |
405 | 6 | |
406 | 6 | // We intentionally leak |expr| here since it is required by PR_SetEnv. |
407 | 6 | MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr); |
408 | | #elif defined(XP_WIN) |
409 | | // This is the same as the NSPR implementation |
410 | | // (Note that we don't need to do a strdup for this case; the CRT makes a copy) |
411 | | _putenv(aEnvString); |
412 | | #else |
413 | | #error "Not implemented for this configuration" |
414 | | #endif |
415 | | } |
416 | | |
417 | | inline bool |
418 | | EnvHasValue(const char* aVarName) |
419 | 6 | { |
420 | 6 | #if defined(MOZILLA_INTERNAL_API) |
421 | 6 | const char* val = PR_GetEnv(aVarName); |
422 | 6 | return val && *val; |
423 | | #elif defined(XP_WIN) |
424 | | // This is the same as the NSPR implementation |
425 | | const char* val = getenv(aVarName); |
426 | | return val && *val; |
427 | | #else |
428 | | #error "Not implemented for this configuration" |
429 | | #endif |
430 | | } |
431 | | |
432 | | } // namespace mozilla |
433 | | |
434 | | #endif // mozilla_CmdLineAndEnvUtils_h |