Bitcoin Core Fuzz Coverage Report

Coverage Report

Created: 2026-03-24 13:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/logging.h
Line
Count
Source
1
// Copyright (c) 2009-2010 Satoshi Nakamoto
2
// Copyright (c) 2009-present The Bitcoin Core developers
3
// Distributed under the MIT software license, see the accompanying
4
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6
#ifndef BITCOIN_LOGGING_H
7
#define BITCOIN_LOGGING_H
8
9
#include <crypto/siphash.h>
10
#include <logging/categories.h> // IWYU pragma: export
11
#include <threadsafety.h>
12
#include <util/fs.h>
13
#include <util/log.h> // IWYU pragma: export
14
#include <util/string.h>
15
#include <util/time.h>
16
17
#include <atomic>
18
#include <cstdint>
19
#include <cstring>
20
#include <functional>
21
#include <list>
22
#include <memory>
23
#include <string>
24
#include <unordered_map>
25
#include <vector>
26
27
static const bool DEFAULT_LOGTIMEMICROS = false;
28
static const bool DEFAULT_LOGIPS        = false;
29
static const bool DEFAULT_LOGTIMESTAMPS = true;
30
static const bool DEFAULT_LOGTHREADNAMES = false;
31
static const bool DEFAULT_LOGSOURCELOCATIONS = false;
32
static constexpr bool DEFAULT_LOGLEVELALWAYS = false;
33
extern const char * const DEFAULT_DEBUGLOGFILE;
34
35
extern bool fLogIPs;
36
37
struct SourceLocationEqual {
38
    bool operator()(const SourceLocation& lhs, const SourceLocation& rhs) const noexcept
39
0
    {
40
0
        return lhs.line() == rhs.line() && std::string_view(lhs.file_name()) == std::string_view(rhs.file_name());
41
0
    }
42
};
43
44
struct SourceLocationHasher {
45
    size_t operator()(const SourceLocation& s) const noexcept
46
0
    {
47
        // Use CSipHasher(0, 0) as a simple way to get uniform distribution.
48
0
        return size_t(CSipHasher(0, 0)
49
0
                      .Write(s.line())
50
0
                      .Write(MakeUCharSpan(std::string_view{s.file_name()}))
51
0
                      .Finalize());
52
0
    }
53
};
54
55
struct LogCategory {
56
    std::string category;
57
    bool active;
58
};
59
60
namespace BCLog {
61
    constexpr auto DEFAULT_LOG_LEVEL{Level::Debug};
62
    constexpr size_t DEFAULT_MAX_LOG_BUFFER{1'000'000}; // buffer up to 1MB of log data prior to StartLogging
63
    constexpr uint64_t RATELIMIT_MAX_BYTES{1024 * 1024}; // maximum number of bytes per source location that can be logged within the RATELIMIT_WINDOW
64
    constexpr auto RATELIMIT_WINDOW{1h}; // time window after which log ratelimit stats are reset
65
    constexpr bool DEFAULT_LOGRATELIMIT{true};
66
67
    //! Fixed window rate limiter for logging.
68
    class LogRateLimiter
69
    {
70
    public:
71
        //! Keeps track of an individual source location and how many available bytes are left for logging from it.
72
        struct Stats {
73
            //! Remaining bytes
74
            uint64_t m_available_bytes;
75
            //! Number of bytes that were consumed but didn't fit in the available bytes.
76
            uint64_t m_dropped_bytes{0};
77
78
0
            Stats(uint64_t max_bytes) : m_available_bytes{max_bytes} {}
79
            //! Updates internal accounting and returns true if enough available_bytes were remaining
80
            bool Consume(uint64_t bytes);
81
        };
82
83
    private:
84
        mutable StdMutex m_mutex;
85
86
        //! Stats for each source location that has attempted to log something.
87
        std::unordered_map<SourceLocation, Stats, SourceLocationHasher, SourceLocationEqual> m_source_locations GUARDED_BY(m_mutex);
88
        //! Whether any log locations are suppressed. Cached view on m_source_locations for performance reasons.
89
        std::atomic<bool> m_suppression_active{false};
90
        LogRateLimiter(uint64_t max_bytes, std::chrono::seconds reset_window);
91
92
    public:
93
        using SchedulerFunction = std::function<void(std::function<void()>, std::chrono::milliseconds)>;
94
        /**
95
         * @param scheduler_func    Callable object used to schedule resetting the window. The first
96
         *                          parameter is the function to be executed, and the second is the
97
         *                          reset_window interval.
98
         * @param max_bytes         Maximum number of bytes that can be logged for each source
99
         *                          location.
100
         * @param reset_window      Time window after which the stats are reset.
101
         */
102
        static std::shared_ptr<LogRateLimiter> Create(
103
            SchedulerFunction&& scheduler_func,
104
            uint64_t max_bytes,
105
            std::chrono::seconds reset_window);
106
        //! Maximum number of bytes logged per location per window.
107
        const uint64_t m_max_bytes;
108
        //! Interval after which the window is reset.
109
        const std::chrono::seconds m_reset_window;
110
        //! Suppression status of a source log location.
111
        enum class Status {
112
            UNSUPPRESSED,     // string fits within the limit
113
            NEWLY_SUPPRESSED, // suppression has started since this string
114
            STILL_SUPPRESSED, // suppression is still ongoing
115
        };
116
        //! Consumes `source_loc`'s available bytes corresponding to the size of the (formatted)
117
        //! `str` and returns its status.
118
        [[nodiscard]] Status Consume(
119
            const SourceLocation& source_loc,
120
            const std::string& str) EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
121
        //! Resets all usage to zero. Called periodically by the scheduler.
122
        void Reset() EXCLUSIVE_LOCKS_REQUIRED(!m_mutex);
123
        //! Returns true if any log locations are currently being suppressed.
124
0
        bool SuppressionsActive() const { return m_suppression_active; }
125
    };
126
127
    class Logger
128
    {
129
    public:
130
        struct BufferedLog {
131
            SystemClock::time_point now;
132
            std::chrono::seconds mocktime;
133
            std::string str, threadname;
134
            SourceLocation source_loc;
135
            LogFlags category;
136
            Level level;
137
        };
138
139
    private:
140
        mutable StdMutex m_cs; // Can not use Mutex from sync.h because in debug mode it would cause a deadlock when a potential deadlock was detected
141
142
        FILE* m_fileout GUARDED_BY(m_cs) = nullptr;
143
        std::list<BufferedLog> m_msgs_before_open GUARDED_BY(m_cs);
144
        bool m_buffering GUARDED_BY(m_cs) = true; //!< Buffer messages before logging can be started.
145
        size_t m_max_buffer_memusage GUARDED_BY(m_cs){DEFAULT_MAX_LOG_BUFFER};
146
        size_t m_cur_buffer_memusage GUARDED_BY(m_cs){0};
147
        size_t m_buffer_lines_discarded GUARDED_BY(m_cs){0};
148
149
        //! Manages the rate limiting of each log location.
150
        std::shared_ptr<LogRateLimiter> m_limiter GUARDED_BY(m_cs);
151
152
        //! Category-specific log level. Overrides `m_log_level`.
153
        std::unordered_map<LogFlags, Level> m_category_log_levels GUARDED_BY(m_cs);
154
155
        //! If there is no category-specific log level, all logs with a severity
156
        //! level lower than `m_log_level` will be ignored.
157
        std::atomic<Level> m_log_level{DEFAULT_LOG_LEVEL};
158
159
        /** Log categories bitfield. */
160
        std::atomic<CategoryMask> m_categories{BCLog::NONE};
161
162
        void FormatLogStrInPlace(std::string& str, LogFlags category, Level level, const SourceLocation& source_loc, std::string_view threadname, SystemClock::time_point now, std::chrono::seconds mocktime) const;
163
164
        std::string LogTimestampStr(SystemClock::time_point now, std::chrono::seconds mocktime) const;
165
166
        /** Slots that connect to the print signal */
167
        std::list<std::function<void(const std::string&)>> m_print_callbacks GUARDED_BY(m_cs) {};
168
169
        /** Send a string to the log output (internal) */
170
        void LogPrintStr_(std::string_view str, SourceLocation&& source_loc, BCLog::LogFlags category, BCLog::Level level, bool should_ratelimit)
171
            EXCLUSIVE_LOCKS_REQUIRED(m_cs);
172
173
        std::string GetLogPrefix(LogFlags category, Level level) const;
174
175
    public:
176
        bool m_print_to_console = false;
177
        bool m_print_to_file = false;
178
179
        bool m_log_timestamps = DEFAULT_LOGTIMESTAMPS;
180
        bool m_log_time_micros = DEFAULT_LOGTIMEMICROS;
181
        bool m_log_threadnames = DEFAULT_LOGTHREADNAMES;
182
        bool m_log_sourcelocations = DEFAULT_LOGSOURCELOCATIONS;
183
        bool m_always_print_category_level = DEFAULT_LOGLEVELALWAYS;
184
185
        fs::path m_file_path;
186
        std::atomic<bool> m_reopen_file{false};
187
188
        /** Send a string to the log output */
189
        void LogPrintStr(std::string_view str, SourceLocation&& source_loc, BCLog::LogFlags category, BCLog::Level level, bool should_ratelimit)
190
            EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
191
192
        /** Returns whether logs will be written to any output */
193
        bool Enabled() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
194
0
        {
195
0
            StdLockGuard scoped_lock(m_cs);
196
0
            return m_buffering || m_print_to_console || m_print_to_file || !m_print_callbacks.empty();
197
0
        }
198
199
        /** Connect a slot to the print signal and return the connection */
200
        std::list<std::function<void(const std::string&)>>::iterator PushBackCallback(std::function<void(const std::string&)> fun) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
201
0
        {
202
0
            StdLockGuard scoped_lock(m_cs);
203
0
            m_print_callbacks.push_back(std::move(fun));
204
0
            return --m_print_callbacks.end();
205
0
        }
206
207
        /** Delete a connection */
208
        void DeleteCallback(std::list<std::function<void(const std::string&)>>::iterator it) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
209
0
        {
210
0
            StdLockGuard scoped_lock(m_cs);
211
0
            m_print_callbacks.erase(it);
212
0
        }
213
214
        size_t NumConnections()
215
0
        {
216
0
            StdLockGuard scoped_lock(m_cs);
217
0
            return m_print_callbacks.size();
218
0
        }
219
220
        /** Start logging (and flush all buffered messages) */
221
        bool StartLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
222
        /** Only for testing */
223
        void DisconnectTestLogger() EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
224
225
        void SetRateLimiting(std::shared_ptr<LogRateLimiter> limiter) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
226
0
        {
227
0
            StdLockGuard scoped_lock(m_cs);
228
0
            m_limiter = std::move(limiter);
229
0
        }
230
231
        /** Disable logging
232
         * This offers a slight speedup and slightly smaller memory usage
233
         * compared to leaving the logging system in its default state.
234
         * Mostly intended for libbitcoin-kernel apps that don't want any logging.
235
         * Should be used instead of StartLogging().
236
         */
237
        void DisableLogging() EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
238
239
        void ShrinkDebugFile();
240
241
        std::unordered_map<LogFlags, Level> CategoryLevels() const EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
242
0
        {
243
0
            StdLockGuard scoped_lock(m_cs);
244
0
            return m_category_log_levels;
245
0
        }
246
        void SetCategoryLogLevel(const std::unordered_map<LogFlags, Level>& levels) EXCLUSIVE_LOCKS_REQUIRED(!m_cs)
247
0
        {
248
0
            StdLockGuard scoped_lock(m_cs);
249
0
            m_category_log_levels = levels;
250
0
        }
251
        void AddCategoryLogLevel(LogFlags category, Level level)
252
0
        {
253
0
            StdLockGuard scoped_lock(m_cs);
254
0
            m_category_log_levels[category] = level;
255
0
        }
256
        bool SetCategoryLogLevel(std::string_view category_str, std::string_view level_str) EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
257
258
0
        Level LogLevel() const { return m_log_level.load(); }
259
0
        void SetLogLevel(Level level) { m_log_level = level; }
260
        bool SetLogLevel(std::string_view level);
261
262
0
        CategoryMask GetCategoryMask() const { return m_categories.load(); }
263
264
        void EnableCategory(LogFlags flag);
265
        bool EnableCategory(std::string_view str);
266
        void DisableCategory(LogFlags flag);
267
        bool DisableCategory(std::string_view str);
268
269
        bool WillLogCategory(LogFlags category) const;
270
        bool WillLogCategoryLevel(LogFlags category, Level level) const EXCLUSIVE_LOCKS_REQUIRED(!m_cs);
271
272
        /** Returns a vector of the log categories in alphabetical order. */
273
        std::vector<LogCategory> LogCategoriesList() const;
274
        /** Returns a string with the log categories in alphabetical order. */
275
        std::string LogCategoriesString() const
276
0
        {
277
0
            return util::Join(LogCategoriesList(), ", ", [&](const LogCategory& i) { return i.category; });
278
0
        };
279
280
        //! Returns a string with all user-selectable log levels.
281
        std::string LogLevelsString() const;
282
283
        //! Returns the string representation of a log level.
284
        static std::string LogLevelToStr(BCLog::Level level);
285
286
        bool DefaultShrinkDebugFile() const;
287
    };
288
289
} // namespace BCLog
290
291
BCLog::Logger& LogInstance();
292
293
/** Return true if log accepts specified category, at the specified level. */
294
static inline bool LogAcceptCategory(BCLog::LogFlags category, BCLog::Level level)
295
0
{
296
0
    return LogInstance().WillLogCategoryLevel(category, level);
297
0
}
Unexecuted instantiation: addrman.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: banman.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: connman.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: deserialize.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: i2p.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: net.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: net_permissions.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: netaddress.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: netbase_dns_lookup.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: node_eviction.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: p2p_handshake.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: pcp.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: process_message.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: process_messages.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: socks5.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: threadpool.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: coincontrol.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: fees.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: scriptpubkeyman.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: spend.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: chainparams.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: args.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: system.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: netbase.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: request.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: signingprovider.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: config.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: logging.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: coinselection.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: dump.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: migrate.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: wallet.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: walletdb.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: walletutil.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: db.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: external_signer_scriptpubkeyman.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: interfaces.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: load.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: receive.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: sqlite.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: feebumper.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: addresses.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: backup.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: coins.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: encrypt.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: signmessage.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: transactions.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: util.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: random.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: setup_common.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: addrdb.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: blockencodings.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: dbwrapper.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: headerssync.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: httpserver.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: init.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: mapport.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: net_processing.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: netgroup.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: caches.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: chainstatemanager_args.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: kernel_notifications.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: mempool_args.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: mempool_persist.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: miner.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: timeoffsets.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: txdownloadman_impl.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: txorphanage.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: txreconciliation.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: noui.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: block_policy_estimator.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: node.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: server.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: torcontrol.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: httprpc.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: blockfilterindex.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: coinstatsindex.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: txospenderindex.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: abort.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: netif.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: common.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
Unexecuted instantiation: net_types.cpp:LogAcceptCategory(BCLog::LogFlags, util::log::Level)
298
299
/** Return true if str parses as a log category and set the flag */
300
bool GetLogCategory(BCLog::LogFlags& flag, std::string_view str);
301
302
#endif // BITCOIN_LOGGING_H