Skip to content

Possible use-after-move in join() #4231

@mattgodbolt

Description

@mattgodbolt

The code at:

fmt/include/fmt/ranges.h

Lines 661 to 666 in 720da57

auto format(view_ref& value, FormatContext& ctx) const
-> decltype(ctx.out()) {
auto it = std::forward<view_ref>(value).begin;
auto out = ctx.out();
if (it == value.end) return out;
out = value_formatter_.format(*it, ctx);

Does a

auto it = std::forward<view_ref>(value).begin;

and later accesses value.end and value.sep.

In the case the iterator is not copy constructible then the view_ref is an rvalue-reference:

  using view_ref = conditional_t<std::is_copy_constructible<It>::value,
                                 const join_view<It, Sentinel, Char>&,
                                 join_view<It, Sentinel, Char>&&>;

which effectively turns the forward<> into a move.

clang-tidy warns on the accesses of end and sep as they are accesses on a moved-from object.

I'm not sure that this is really a problem in practice but it seems like something that should be avoided. I can't see an easy way to do so though. I'm not sure we can cast just the iterator easily? Taking a copy of sep works but for the same reasons as above we can't copy end out without a move either.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions