Skip to content

Commit

Permalink
Fix UB in format_arg_store implementation.
Browse files Browse the repository at this point in the history
format_arg_store struct contains pointers to its own members, so autogenerated
copy constructor and copy assignment is not correct. Need to reassign pointers
to |this| internals.
  • Loading branch information
ivafanas committed Jan 31, 2024
1 parent 71a4a8d commit f767fb4
Showing 1 changed file with 22 additions and 1 deletion.
23 changes: 22 additions & 1 deletion include/fmt/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -1636,7 +1636,9 @@ template <typename Context, size_t NUM_ARGS, size_t NUM_NAMED_ARGS,
struct format_arg_store {
// args_[0].named_args points to named_args to avoid bloating format_args.
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
arg_t<Context, NUM_ARGS> args[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
static constexpr int ARGS_ARR_SIZE = 1 + (NUM_ARGS != 0 ? NUM_ARGS : +1);

arg_t<Context, NUM_ARGS> args[ARGS_ARR_SIZE];
named_arg_info<typename Context::char_type> named_args[NUM_NAMED_ARGS];

template <typename... T>
Expand All @@ -1649,6 +1651,25 @@ struct format_arg_store {
0,
(init_named_arg(named_args, arg_index, named_arg_index, values), 0)...};
}

format_arg_store(const format_arg_store& rhs) {
args[0] = {named_args, NUM_NAMED_ARGS};
for (int i = 1; i < ARGS_ARR_SIZE; ++i)
args[i] = rhs.args[i];
for (int i = 0; i < NUM_NAMED_ARGS; ++i)
named_args[i] = rhs.named_args[i];
}

format_arg_store &operator=(const format_arg_store &rhs) {
if (this != &rhs) {
args[0] = {named_args, NUM_NAMED_ARGS};
for (int i = 1; i < ARGS_ARR_SIZE; ++i)
args[i] = rhs.args[i];
for (int i = 0; i < NUM_NAMED_ARGS; ++i)
named_args[i] = rhs.named_args[i];
}
return *this;
}
};

// A specialization of format_arg_store without named arguments.
Expand Down

0 comments on commit f767fb4

Please sign in to comment.