I reported issue to spdlog project where I provided clang-tidy report about uninitialized fields. It looks like this:
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:2955:15: warning: 5 uninitialized fields at the end of the constructor call [clang-analyzer-optin.cplusplus.UninitializedObject]
2955 | types_{
| ^
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:732:7: note: uninitialized field 'this->context_.num_args_'
732 | int num_args_;
| ^~~~~~~~~
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:733:15: note: uninitialized pointer 'this->context_.types_'
733 | const type* types_;
| ^~~~~~
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:432:15: note: uninitialized pointer 'this->context_.basic_format_parse_context::format_str_.data_'
432 | const Char* data_;
| ^~~~~
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:433:10: note: uninitialized field 'this->context_.basic_format_parse_context::format_str_.size_'
433 | size_t size_;
| ^~~~~
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:657:7: note: uninitialized field 'this->context_.basic_format_parse_context::next_arg_id_'
657 | int next_arg_id_;
| ^~~~~~~~~~~~
/Users/user/projects/github/spdlog/myapp/main.cpp:6:19: note: Calling constructor for 'basic_format_string<char, int>'
6 | spdlog::error("Some error message with arg: {}", 1);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:3155:5: note: Taking true branch
3155 | if constexpr (detail::count_named_args<Args...>() ==
| ^
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:3159:47: note: Calling constructor for 'format_string_checker<char, fmt::detail::error_handler, int>'
3159 | detail::parse_format_string<true>(str_, checker(s, {}));
| ^~~~~~~~~~~~~~
/Users/user/projects/github/spdlog/myapp/../artifacts/include/spdlog/fmt/bundled/core.h:2955:15: note: 5 uninitialized fields at the end of the constructor call
2955 | types_{
| ^
2956 | mapped_type_constant<Args,
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
2957 | basic_format_context<Char*, Char>>::value...} {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp code looks quite simpe:
#include <spdlog/spdlog.h>
int main()
{
spdlog::error("Some error message with arg: {}", 1);
}
Then I started code reading to understand why variables are not inited and how can I fix that. Unfortunately, I didn't realise the root of the warnings.
spdlog::error("Some error message with arg: {}", 1); leads to calling error function. It has the following signature:
template<typename... Args>
inline void error(format_string_t<Args...> fmt, Args &&... args);
Here fmt argument has to be created - leads to calling format_string_t constructor:
template<typename... Args>
using format_string_t = fmt::format_string<Args...>;
fmt::format_string expands to:
template<typename... Args>
using format_string = basic_format_string<char, type_identity_t<Args>...>;
basic_format_string class looks like this:
template<typename Char, typename... Args>
class basic_format_string
{
...
public:
template<typename S, FMT_ENABLE_IF(std::is_convertible<const S &, basic_string_view<Char>>::value)>
FMT_CONSTEVAL FMT_INLINE basic_format_string(const S &s)
: str_(s)
{
...
if constexpr (detail::count_named_args<Args...>() == detail::count_statically_named_args<Args...>())
{
using checker = detail::format_string_checker<Char, detail::error_handler, remove_cvref_t<Args>...>;
detail::parse_format_string<true>(str_, checker(s, {}));
}
}
...
}
Here format_string_checker constructor is calling:
template <typename Char, typename ErrorHandler, typename... Args>
class format_string_checker {
...
public:
explicit FMT_CONSTEXPR format_string_checker(
basic_string_view<Char> format_str, ErrorHandler eh)
: context_(format_str, num_args, types_, eh),
parse_funcs_{&parse_format_specs<Args, parse_context_type>...},
types_{
mapped_type_constant<Args,
basic_format_context<Char*, Char>>::value...} {
}
...
}
So, context_ constructor is calling as well - compile_parse_context<Char, ErrorHandler>
private:
int num_args_;
const type *types_;
using base = basic_format_parse_context<Char, ErrorHandler>;
public:
explicit FMT_CONSTEXPR compile_parse_context(
basic_string_view<Char> format_str, int num_args, const type *types, ErrorHandler eh = {}, int next_arg_id = 0)
: base(format_str, eh, next_arg_id)
, num_args_(num_args)
, types_(types)
{}
...
}
num_args_ and types_ are inited. I thought maybe I'm missing something and somehow default constructor is calling, and members don't have default values. However, even I set default values for these member - clang-tidy reports about the same problem.
Am I missing something or clang-tidy reports about that problem by mistake?
spdlog: v1.13.0
clang information
user@mac build % clang++ --version
Apple clang version 15.0.0 (clang-1500.1.0.2.5)
Target: arm64-apple-darwin23.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
user@mac build % clang-tidy --version
LLVM (http://llvm.org/):
LLVM version 19.0.0git
Optimized build.
UPD.O:
- I tried to specify
core.hinHeaderFilterRegexto not analyze it. The same result. - I managed to suppress this warning by adding
/* NOLINTBEGIN */and/* NOLINTEND */beforeFMT_BEGIN_DETAIL_NAMESPACEand afterFMT_END_DETAIL_NAMESPACE(wrapcompile_parse_contextclass) - it works. However, it is bad practice to patch 3rd party library and even worse do that without confidence the problem doesn't exist.