Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

format_to() with fmt::memory_buffer docs vague #877

Closed
whiterabbit963 opened this issue Sep 22, 2018 · 4 comments
Closed

format_to() with fmt::memory_buffer docs vague #877

whiterabbit963 opened this issue Sep 22, 2018 · 4 comments

Comments

@whiterabbit963
Copy link

whiterabbit963 commented Sep 22, 2018

First off, great library! Would love to see it as part of the stdlib.

When passing a fmt::memory_buffer as the first argument in format_to(), it is wrapped in a back_inserter_iterator. It would be helpful if there was a notation in the documentation that explained this relationship. I have read through the docs a few times and it was unclear to me if format_to() would overwrite or append. Through experimentation I discovered that it appended.

From what I can tell, appending appears to be the "standard" behavior, but it does not appear to be required behavior. I feel like it deserves a notation indicating this fact.

Thanks!

@whiterabbit963
Copy link
Author

Found more unexpected behavior.

    string x;
    fmt::format_to(back_inserter(x), "hello_world");
    fmt::format_to(x.begin(), "hello_again_world!");

Produces: "hello_again"
Initially, I expected, "hello_again_world".

The following code is executed to produce the output.

  void on_text(const Char *begin, const Char *end) {
    auto size = internal::to_unsigned(end - begin);
    auto out = context.out();
    auto &&it = internal::reserve(out, size);
    it = std::copy_n(begin, size, it);
    context.advance_to(out);
  }

Since copy_n() does not explicitly extend the size of the out container, the rest is clipped.
Interestingly, when examining what is written to the destination in a debugger, the whole input is copied to the output. I do not think this is a buffer overrun, since copy_n() appears like it is supposed to handle this situation.

Should I expect what actually happens, or should I expect the buffer to be lengthened?

@vitaut
Copy link
Contributor

vitaut commented Sep 28, 2018

This is unsafe if x is not large enough to fit the output:

    fmt::format_to(x.begin(), "hello_again_world!");

Should I expect what actually happens, or should I expect the buffer to be lengthened?

Neither. The buffer is not lengthened (because in general you can't increase the buffer size from an iterator) and the output won't necessarily be truncated. Your second example has a UB and
you should either use back_insert_iterator or preallocate large enough buffer (same as you'd do with std::copy).

@vitaut
Copy link
Contributor

vitaut commented Sep 28, 2018

And I clarified the append behavior in 66992e9.

@vitaut vitaut closed this as completed Sep 28, 2018
@whiterabbit963
Copy link
Author

Thanks for the clarification. In retrospect, it is obvious that iterators should not be expected to lengthen a buffer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants