fuzz coverage

Coverage Report

Created: 2025-10-29 15:27

/Users/eugenesiegel/btc/bitcoin/src/common/args.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2023-present The Bitcoin Core developers
2
// Distributed under the MIT software license, see the accompanying
3
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5
#ifndef BITCOIN_COMMON_ARGS_H
6
#define BITCOIN_COMMON_ARGS_H
7
8
#include <common/settings.h>
9
#include <compat/compat.h>
10
#include <sync.h>
11
#include <util/chaintype.h>
12
#include <util/fs.h>
13
14
#include <cstdint>
15
#include <iosfwd>
16
#include <list>
17
#include <map>
18
#include <optional>
19
#include <set>
20
#include <string>
21
#include <variant>
22
#include <vector>
23
24
class ArgsManager;
25
26
extern const char * const BITCOIN_CONF_FILENAME;
27
extern const char * const BITCOIN_SETTINGS_FILENAME;
28
29
// Return true if -datadir option points to a valid directory or is not specified.
30
bool CheckDataDirOption(const ArgsManager& args);
31
32
/**
33
 * Most paths passed as configuration arguments are treated as relative to
34
 * the datadir if they are not absolute.
35
 *
36
 * @param args Parsed arguments and settings.
37
 * @param path The path to be conditionally prefixed with datadir.
38
 * @param net_specific Use network specific datadir variant
39
 * @return The normalized path.
40
 */
41
fs::path AbsPathForConfigVal(const ArgsManager& args, const fs::path& path, bool net_specific = true);
42
43
inline bool IsSwitchChar(char c)
44
0
{
45
#ifdef WIN32
46
    return c == '-' || c == '/';
47
#else
48
0
    return c == '-';
49
0
#endif
50
0
}
51
52
enum class OptionsCategory {
53
    OPTIONS,
54
    CONNECTION,
55
    WALLET,
56
    WALLET_DEBUG_TEST,
57
    ZMQ,
58
    DEBUG_TEST,
59
    CHAINPARAMS,
60
    NODE_RELAY,
61
    BLOCK_CREATION,
62
    RPC,
63
    GUI,
64
    COMMANDS,
65
    REGISTER_COMMANDS,
66
    CLI_COMMANDS,
67
    IPC,
68
69
    HIDDEN // Always the last option to avoid printing these in the help
70
};
71
72
struct KeyInfo {
73
    std::string name;
74
    std::string section;
75
    bool negated{false};
76
};
77
78
KeyInfo InterpretKey(std::string key);
79
80
std::optional<common::SettingsValue> InterpretValue(const KeyInfo& key, const std::string* value,
81
                                                         unsigned int flags, std::string& error);
82
83
struct SectionInfo {
84
    std::string m_name;
85
    std::string m_file;
86
    int m_line;
87
};
88
89
std::string SettingToString(const common::SettingsValue&, const std::string&);
90
std::optional<std::string> SettingToString(const common::SettingsValue&);
91
92
int64_t SettingToInt(const common::SettingsValue&, int64_t);
93
std::optional<int64_t> SettingToInt(const common::SettingsValue&);
94
95
bool SettingToBool(const common::SettingsValue&, bool);
96
std::optional<bool> SettingToBool(const common::SettingsValue&);
97
98
class ArgsManager
99
{
100
public:
101
    /**
102
     * Flags controlling how config and command line arguments are validated and
103
     * interpreted.
104
     */
105
    enum Flags : uint32_t {
106
        ALLOW_ANY = 0x01,         //!< disable validation
107
        // ALLOW_BOOL = 0x02,     //!< unimplemented, draft implementation in #16545
108
        // ALLOW_INT = 0x04,      //!< unimplemented, draft implementation in #16545
109
        // ALLOW_STRING = 0x08,   //!< unimplemented, draft implementation in #16545
110
        // ALLOW_LIST = 0x10,     //!< unimplemented, draft implementation in #16545
111
        DISALLOW_NEGATION = 0x20, //!< disallow -nofoo syntax
112
        DISALLOW_ELISION = 0x40,  //!< disallow -foo syntax that doesn't assign any value
113
114
        DEBUG_ONLY = 0x100,
115
        /* Some options would cause cross-contamination if values for
116
         * mainnet were used while running on regtest/testnet (or vice-versa).
117
         * Setting them as NETWORK_ONLY ensures that sharing a config file
118
         * between mainnet and regtest/testnet won't cause problems due to these
119
         * parameters by accident. */
120
        NETWORK_ONLY = 0x200,
121
        // This argument's value is sensitive (such as a password).
122
        SENSITIVE = 0x400,
123
        COMMAND = 0x800,
124
    };
125
126
protected:
127
    struct Arg
128
    {
129
        std::string m_help_param;
130
        std::string m_help_text;
131
        unsigned int m_flags;
132
    };
133
134
    mutable RecursiveMutex cs_args;
135
    common::Settings m_settings GUARDED_BY(cs_args);
136
    std::vector<std::string> m_command GUARDED_BY(cs_args);
137
    std::string m_network GUARDED_BY(cs_args);
138
    std::set<std::string> m_network_only_args GUARDED_BY(cs_args);
139
    std::map<OptionsCategory, std::map<std::string, Arg>> m_available_args GUARDED_BY(cs_args);
140
    std::optional<unsigned int> m_default_flags GUARDED_BY(cs_args){};
141
    bool m_accept_any_command GUARDED_BY(cs_args){true};
142
    std::list<SectionInfo> m_config_sections GUARDED_BY(cs_args);
143
    std::optional<fs::path> m_config_path GUARDED_BY(cs_args);
144
    mutable fs::path m_cached_blocks_path GUARDED_BY(cs_args);
145
    mutable fs::path m_cached_datadir_path GUARDED_BY(cs_args);
146
    mutable fs::path m_cached_network_datadir_path GUARDED_BY(cs_args);
147
148
    [[nodiscard]] bool ReadConfigStream(std::istream& stream, const std::string& filepath, std::string& error, bool ignore_invalid_keys = false);
149
150
    /**
151
     * Returns true if settings values from the default section should be used,
152
     * depending on the current network and whether the setting is
153
     * network-specific.
154
     */
155
    bool UseDefaultSection(const std::string& arg) const EXCLUSIVE_LOCKS_REQUIRED(cs_args);
156
157
 public:
158
    /**
159
     * Get setting value.
160
     *
161
     * Result will be null if setting was unset, true if "-setting" argument was passed
162
     * false if "-nosetting" argument was passed, and a string if a "-setting=value"
163
     * argument was passed.
164
     */
165
    common::SettingsValue GetSetting(const std::string& arg) const;
166
167
    /**
168
     * Get list of setting values.
169
     */
170
    std::vector<common::SettingsValue> GetSettingsList(const std::string& arg) const;
171
172
    ArgsManager();
173
    ~ArgsManager();
174
175
    /**
176
     * Select the network in use
177
     */
178
    void SelectConfigNetwork(const std::string& network);
179
180
    [[nodiscard]] bool ParseParameters(int argc, const char* const argv[], std::string& error);
181
182
    /**
183
     * Return config file path (read-only)
184
     */
185
    fs::path GetConfigFilePath() const;
186
    void SetConfigFilePath(fs::path);
187
    [[nodiscard]] bool ReadConfigFiles(std::string& error, bool ignore_invalid_keys = false);
188
189
    /**
190
     * Log warnings for options in m_section_only_args when
191
     * they are specified in the default section but not overridden
192
     * on the command line or in a network-specific section in the
193
     * config file.
194
     */
195
    std::set<std::string> GetUnsuitableSectionOnlyArgs() const;
196
197
    /**
198
     * Log warnings for unrecognized section names in the config file.
199
     */
200
    std::list<SectionInfo> GetUnrecognizedSections() const;
201
202
    struct Command {
203
        /** The command (if one has been registered with AddCommand), or empty */
204
        std::string command;
205
        /**
206
         * If command is non-empty: Any args that followed it
207
         * If command is empty: The unregistered command and any args that followed it
208
         */
209
        std::vector<std::string> args;
210
    };
211
    /**
212
     * Get the command and command args (returns std::nullopt if no command provided)
213
     */
214
    std::optional<const Command> GetCommand() const;
215
216
    /**
217
     * Get blocks directory path
218
     *
219
     * @return Blocks path which is network specific
220
     */
221
    fs::path GetBlocksDirPath() const;
222
223
    /**
224
     * Get data directory path
225
     *
226
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
227
     */
228
153k
    fs::path GetDataDirBase() const { return GetDataDir(false); }
229
230
    /**
231
     * Get data directory path with appended network identifier
232
     *
233
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
234
     */
235
205k
    fs::path GetDataDirNet() const { return GetDataDir(true); }
236
237
    /**
238
     * Clear cached directory paths
239
     */
240
    void ClearPathCache();
241
242
    /**
243
     * Return a vector of strings of the given argument
244
     *
245
     * @param strArg Argument to get (e.g. "-foo")
246
     * @return command-line arguments
247
     */
248
    std::vector<std::string> GetArgs(const std::string& strArg) const;
249
250
    /**
251
     * Return true if the given argument has been manually set
252
     *
253
     * @param strArg Argument to get (e.g. "-foo")
254
     * @return true if the argument has been set
255
     */
256
    bool IsArgSet(const std::string& strArg) const;
257
258
    /**
259
     * Return true if the argument was originally passed as a negated option,
260
     * i.e. -nofoo.
261
     *
262
     * @param strArg Argument to get (e.g. "-foo")
263
     * @return true if the argument was passed negated
264
     */
265
    bool IsArgNegated(const std::string& strArg) const;
266
267
    /**
268
     * Return string argument or default value
269
     *
270
     * @param strArg Argument to get (e.g. "-foo")
271
     * @param strDefault (e.g. "1")
272
     * @return command-line argument or default value
273
     */
274
    std::string GetArg(const std::string& strArg, const std::string& strDefault) const;
275
    std::optional<std::string> GetArg(const std::string& strArg) const;
276
277
    /**
278
     * Return path argument or default value
279
     *
280
     * @param arg Argument to get a path from (e.g., "-datadir", "-blocksdir" or "-walletdir")
281
     * @param default_value Optional default value to return instead of the empty path.
282
     * @return normalized path if argument is set, with redundant "." and ".."
283
     * path components and trailing separators removed (see patharg unit test
284
     * for examples or implementation for details). If argument is empty or not
285
     * set, default_value is returned unchanged.
286
     */
287
    fs::path GetPathArg(std::string arg, const fs::path& default_value = {}) const;
288
289
    /**
290
     * Return integer argument or default value
291
     *
292
     * @param strArg Argument to get (e.g. "-foo")
293
     * @param nDefault (e.g. 1)
294
     * @return command-line argument (0 if invalid number) or default value
295
     */
296
    int64_t GetIntArg(const std::string& strArg, int64_t nDefault) const;
297
    std::optional<int64_t> GetIntArg(const std::string& strArg) const;
298
299
    /**
300
     * Return boolean argument or default value
301
     *
302
     * @param strArg Argument to get (e.g. "-foo")
303
     * @param fDefault (true or false)
304
     * @return command-line argument or default value
305
     */
306
    bool GetBoolArg(const std::string& strArg, bool fDefault) const;
307
    std::optional<bool> GetBoolArg(const std::string& strArg) const;
308
309
    /**
310
     * Set an argument if it doesn't already have a value
311
     *
312
     * @param strArg Argument to set (e.g. "-foo")
313
     * @param strValue Value (e.g. "1")
314
     * @return true if argument gets set, false if it already had a value
315
     */
316
    bool SoftSetArg(const std::string& strArg, const std::string& strValue);
317
318
    /**
319
     * Set a boolean argument if it doesn't already have a value
320
     *
321
     * @param strArg Argument to set (e.g. "-foo")
322
     * @param fValue Value (e.g. false)
323
     * @return true if argument gets set, false if it already had a value
324
     */
325
    bool SoftSetBoolArg(const std::string& strArg, bool fValue);
326
327
    // Forces an arg setting. Called by SoftSetArg() if the arg hasn't already
328
    // been set. Also called directly in testing.
329
    void ForceSetArg(const std::string& strArg, const std::string& strValue);
330
331
    /**
332
     * Returns the appropriate chain type from the program arguments.
333
     * @return ChainType::MAIN by default; raises runtime error if an invalid
334
     * combination, or unknown chain is given.
335
     */
336
    ChainType GetChainType() const;
337
338
    /**
339
     * Returns the appropriate chain type string from the program arguments.
340
     * @return ChainType::MAIN string by default; raises runtime error if an
341
     * invalid combination is given.
342
     */
343
    std::string GetChainTypeString() const;
344
345
    /**
346
     * Add argument
347
     */
348
    void AddArg(const std::string& name, const std::string& help, unsigned int flags, const OptionsCategory& cat);
349
350
    /**
351
     * Add subcommand
352
     */
353
    void AddCommand(const std::string& cmd, const std::string& help);
354
355
    /**
356
     * Add many hidden arguments
357
     */
358
    void AddHiddenArgs(const std::vector<std::string>& args);
359
360
    /**
361
     * Clear available arguments
362
     */
363
    void ClearArgs();
364
365
    /**
366
     * Check CLI command args
367
     *
368
     * @throws std::runtime_error when multiple CLI_COMMAND arguments are specified
369
     */
370
    void CheckMultipleCLIArgs() const;
371
372
    /**
373
     * Get the help string
374
     */
375
    std::string GetHelpMessage() const;
376
377
    /**
378
     * Return Flags for known arg.
379
     * Return default flags for unknown arg.
380
     */
381
    std::optional<unsigned int> GetArgFlags(const std::string& name) const;
382
383
    /**
384
     * Set default flags to return for an unknown arg.
385
     */
386
    void SetDefaultFlags(std::optional<unsigned int>);
387
388
    /**
389
     * Get settings file path, or return false if read-write settings were
390
     * disabled with -nosettings.
391
     */
392
    bool GetSettingsPath(fs::path* filepath = nullptr, bool temp = false, bool backup = false) const;
393
394
    /**
395
     * Read settings file. Push errors to vector, or log them if null.
396
     */
397
    bool ReadSettingsFile(std::vector<std::string>* errors = nullptr);
398
399
    /**
400
     * Write settings file or backup settings file. Push errors to vector, or
401
     * log them if null.
402
     */
403
    bool WriteSettingsFile(std::vector<std::string>* errors = nullptr, bool backup = false) const;
404
405
    /**
406
     * Get current setting from config file or read/write settings file,
407
     * ignoring nonpersistent command line or forced settings values.
408
     */
409
    common::SettingsValue GetPersistentSetting(const std::string& name) const;
410
411
    /**
412
     * Access settings with lock held.
413
     */
414
    template <typename Fn>
415
    void LockSettings(Fn&& fn)
416
0
    {
417
0
        LOCK(cs_args);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
        LOCK(cs_args);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
        LOCK(cs_args);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
        LOCK(cs_args);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
        LOCK(cs_args);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
        LOCK(cs_args);
Line
Count
Source
259
0
#define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__)
Line
Count
Source
11
0
#define UNIQUE_NAME(name) PASTE2(name, __COUNTER__)
Line
Count
Source
9
0
#define PASTE2(x, y) PASTE(x, y)
Line
Count
Source
8
0
#define PASTE(x, y) x ## y
418
0
        fn(m_settings);
419
0
    }
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_18NodeImpl16isSettingIgnoredERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_18NodeImpl15updateRwSettingERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERK8UniValueEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_18NodeImpl12forceSettingERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERK8UniValueEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_18NodeImpl13resetSettingsEvEUlRN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_19ChainImpl12getRwSettingERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEUlRKN6common8SettingsEE_EEvOT_
Unexecuted instantiation: interfaces.cpp:_ZN11ArgsManager12LockSettingsIZN4node12_GLOBAL__N_19ChainImpl15updateRwSettingERKNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEERKNS4_8functionIFNS4_8optionalIN10interfaces14SettingsActionEEER8UniValueEEEEUlRN6common8SettingsEE_EEvOT_
420
421
    /**
422
     * Log the config file options and the command line arguments,
423
     * useful for troubleshooting.
424
     */
425
    void LogArgs() const;
426
427
private:
428
    /**
429
     * Get data directory path
430
     *
431
     * @param net_specific Append network identifier to the returned path
432
     * @return Absolute path on success, otherwise an empty path when a non-directory path would be returned
433
     */
434
    fs::path GetDataDir(bool net_specific) const;
435
436
    /**
437
     * Return -regtest/-signet/-testnet/-testnet4/-chain= setting as a ChainType enum if a
438
     * recognized chain type was set, or as a string if an unrecognized chain
439
     * name was set. Raise an exception if an invalid combination of flags was
440
     * provided.
441
     */
442
    std::variant<ChainType, std::string> GetChainArg() const;
443
444
    // Helper function for LogArgs().
445
    void logArgsPrefix(
446
        const std::string& prefix,
447
        const std::string& section,
448
        const std::map<std::string, std::vector<common::SettingsValue>>& args) const;
449
};
450
451
extern ArgsManager gArgs;
452
453
/**
454
 * @return true if help has been requested via a command-line arg
455
 */
456
bool HelpRequested(const ArgsManager& args);
457
458
/** Add help options to the args manager */
459
void SetupHelpOptions(ArgsManager& args);
460
461
extern const std::vector<std::string> TEST_OPTIONS_DOC;
462
463
/** Checks if a particular test option is present in -test command-line arg options */
464
bool HasTestOption(const ArgsManager& args, const std::string& test_option);
465
466
/**
467
 * Format a string to be used as group of options in help messages
468
 *
469
 * @param message Group name (e.g. "RPC server options:")
470
 * @return the formatted string
471
 */
472
std::string HelpMessageGroup(const std::string& message);
473
474
/**
475
 * Format a string to be used as option description in help messages
476
 *
477
 * @param option Option message (e.g. "-rpcuser=<user>")
478
 * @param message Option description (e.g. "Username for JSON-RPC connections")
479
 * @return the formatted string
480
 */
481
std::string HelpMessageOpt(const std::string& option, const std::string& message);
482
483
namespace common {
484
#ifdef WIN32
485
class WinCmdLineArgs
486
{
487
public:
488
    WinCmdLineArgs();
489
    ~WinCmdLineArgs();
490
    std::pair<int, char**> get();
491
492
private:
493
    int argc;
494
    char** argv;
495
    std::vector<std::string> args;
496
};
497
#endif
498
} // namespace common
499
500
#endif // BITCOIN_COMMON_ARGS_H