Fix FormatBuf implementation (#491)
Fixes #491 (and probably #480) Before, the put-area of the custom streambuf
implementation was (sometimes) incorrectly extended beyond the writeable buffer.
The new implementation is in some cases not as efficient as the old, but avoids
to write into uninitialized memory.
{"label": "fmtlib:master", "ref": "master", "sha": "c03f55ec3a0511611fa7f0537f858544a0ed03bd"}
I wrote this test case, but it fails:

```
TEST(OStreamTest, MemoryWriterAllocation) {
  fmt::MemoryWriter w;
  size_t final_len{};
  const size_t l = 10000;

  for (size_t i = 0; i < l; i++) {
    const std::string token = std::to_string(i);
    final_len += token.size();
    w << token;
  }

  const std::string rs = w.str();
  EXPECT_EQ(w.size(), final_len);
}
```

I'm getting this stack trace:

```
ostream-test: malloc.c:2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' failed.

Program received signal SIGABRT, Aborted.
0x00007ffff7027067 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56      ../nptl/sysdeps/unix/sysv/linux/raise.c: File o directory non esistente.
(gdb) bt
#0  0x00007ffff7027067 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff7028448 in __GI_abort () at abort.c:89
#2  0x00007ffff706a0ad in __malloc_assert (
    assertion=assertion@entry=0x7ffff715a748 "(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offs"..., file=file@entry=0x7ffff715628d "malloc.c", line=line@entry=2372, 
    function=function@entry=0x7ffff715660b <__func__.11291> "sysmalloc") at malloc.c:293
#3  0x00007ffff706cd90 in sysmalloc (av=0x7ffff7397620 <main_arena>, nb=19232) at malloc.c:2369
#4  _int_malloc (av=0x7ffff7397620 <main_arena>, bytes=19210) at malloc.c:3800
#5  0x00007ffff706e020 in __GI___libc_malloc (bytes=19210) at malloc.c:2891
#6  0x00007ffff79132e8 in operator new(unsigned long) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#7  0x000000000049c5c0 in __gnu_cxx::new_allocator<char>::allocate (this=0x7fffffffd950, __n=19210) at /usr/include/c++/4.9/ext/new_allocator.h:104
#8  0x00000000004a3298 in fmt::internal::MemoryBuffer<char, 500ul, std::allocator<char> >::grow (this=0x7fffffffd950, size=12810) at /home/meox/git/fmt/fmt/format.h:807
#9  0x000000000048e4f8 in fmt::Buffer<char>::resize (this=0x7fffffffd950, new_size=12810) at /home/meox/git/fmt/fmt/format.h:702
#10 0x000000000048c23d in fmt::operator<< <std::string, char> (writer=..., value="3479") at /home/meox/git/fmt/fmt/ostream.h:138
#11 0x000000000048711c in OStreamTest_MemoryWriterAllocation_Test::TestBody (this=0x71e240) at /home/meox/git/fmt/test/ostream-test.cc:203
#12 0x00000000004cf88e in testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test, void> (object=0x71e240, method=&virtual testing::Test::TestBody(), 
    location=0x4e9263 "the test body") at /home/meox/git/fmt/test/gmock-gtest-all.cc:3562
#13 0x00000000004c9c24 in testing::internal::HandleExceptionsInMethodIfSupported<testing::Test, void> (object=0x71e240, method=&virtual testing::Test::TestBody(), 
    location=0x4e9263 "the test body") at /home/meox/git/fmt/test/gmock-gtest-all.cc:3598
#14 0x00000000004aacff in testing::Test::Run (this=0x71e240) at /home/meox/git/fmt/test/gmock-gtest-all.cc:3635
#15 0x00000000004ab46f in testing::TestInfo::Run (this=0x71e150) at /home/meox/git/fmt/test/gmock-gtest-all.cc:3810
#16 0x00000000004aba78 in testing::TestCase::Run (this=0x71d490) at /home/meox/git/fmt/test/gmock-gtest-all.cc:3928
#17 0x00000000004b2119 in testing::internal::UnitTestImpl::RunAllTests (this=0x71d150) at /home/meox/git/fmt/test/gmock-gtest-all.cc:5799
#18 0x00000000004d06cd in testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (object=0x71d150, 
    method=(bool (testing::internal::UnitTestImpl::*)(testing::internal::UnitTestImpl * const)) 0x4b1e96 <testing::internal::UnitTestImpl::RunAllTests()>, 
    location=0x4e9b40 "auxiliary test code (environments or event listeners)") at /home/meox/git/fmt/test/gmock-gtest-all.cc:3562
#19 0x00000000004ca9be in testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl, bool> (object=0x71d150, 
    method=(bool (testing::internal::UnitTestImpl::*)(testing::internal::UnitTestImpl * const)) 0x4b1e96 <testing::internal::UnitTestImpl::RunAllTests()>, 
    location=0x4e9b40 "auxiliary test code (environments or event listeners)") at /home/meox/git/fmt/test/gmock-gtest-all.cc:3598
#20 0x00000000004b0eab in testing::UnitTest::Run (this=0x71cc00 <testing::UnitTest::GetInstance()::instance>) at /home/meox/git/fmt/test/gmock-gtest-all.cc:5413
#21 0x00000000004a570d in RUN_ALL_TESTS () at /home/meox/git/fmt/test/./gtest/gtest.h:20062
#22 0x00000000004a5694 in main (argc=1, argv=0x7fffffffe058) at /home/meox/git/fmt/test/test-main.cc:57
```

MemoryWriter allocation issue
diff --git a/fmt/ostream.h b/fmt/ostream.h
index 7e13a5a71ed3..f529e24146b1 100644
--- a/fmt/ostream.h
+++ b/fmt/ostream.h
@@ -24,32 +24,27 @@ class FormatBuf : public std::basic_streambuf<Char> {
   typedef typename std::basic_streambuf<Char>::traits_type traits_type;
 
   Buffer<Char> &buffer_;
-  Char *start_;
 
  public:
-  FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
-    this->setp(start_, start_ + buffer_.capacity());
-  }
+  FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {}
 
-  FormatBuf(Buffer<Char> &buffer, Char *start) : buffer_(buffer) , start_(start) {
-    this->setp(start_, start_ + buffer_.capacity());
-  }
+ protected:
+  // The put-area is actually always empty. This makes the implementation
+  // simpler and has the advantage that the streambuf and the buffer are always
+  // in sync and sputc never writes into uninitialized memory. The obvious
+  // disadvantage is that each call to sputc always results in a (virtual) call
+  // to overflow. There is no disadvantage here for sputn since this always
+  // results in a call to xsputn.
 
   int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
-    if (!traits_type::eq_int_type(ch, traits_type::eof())) {
-      size_t buf_size = size();
-      buffer_.resize(buf_size);
-      buffer_.reserve(buf_size * 2);
-
-      start_ = &buffer_[0];
-      start_[buf_size] = traits_type::to_char_type(ch);
-      this->setp(start_+ buf_size + 1, start_ + buf_size * 2);
-    }
+    if (!traits_type::eq_int_type(ch, traits_type::eof()))
+      buffer_.push_back(ch);
     return ch;
   }
 
-  size_t size() const {
-    return to_unsigned(this->pptr() - start_);
+  std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
+    buffer_.append(s, s + count);
+    return count;
   }
 };
 
@@ -99,7 +94,7 @@ void format_arg(BasicFormatter<Char, ArgFormatter_> &f,
   std::basic_ostream<Char> output(&format_buf);
   output << value;
 
-  BasicStringRef<Char> str(&buffer[0], format_buf.size());
+  BasicStringRef<Char> str(&buffer[0], buffer.size());
   typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
   format_str = f.format(format_str, MakeArg(str));
 }
@@ -128,14 +123,10 @@ typename std::enable_if<
 operator<<(BasicWriter<Char> &writer, const T &value) {
   FMT_STATIC_ASSERT(internal::is_streamable<T>::value, "T must be Streamable");
 
-  auto &buffer = writer.buffer();
-  Char *start = &buffer[0] + buffer.size();
-
-  internal::FormatBuf<Char> format_buf(buffer, start);
+  internal::FormatBuf<Char> format_buf(writer.buffer());
   std::basic_ostream<Char> output(&format_buf);
   output << value;
 
-  buffer.resize(buffer.size() + format_buf.size());
   return writer;
 }
 #endif

diff --git a/test/ostream-test.cc b/test/ostream-test.cc
index a7341065eb01..0e84f5275afd 100644
--- a/test/ostream-test.cc
+++ b/test/ostream-test.cc
@@ -191,3 +191,26 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
   } while (size != 0);
   fmt::internal::write(os, w);
 }
+
+#if __cplusplus >= 201103L
+struct Xs {
+  const size_t size;
+  const std::string s;
+  Xs() : size(200), s(size, 'x') {}
+};
+
+inline std::ostream& operator<<(std::ostream& os, Xs const& xs) {
+  return os << xs.s;
+}
+
+TEST(OStreamTest, FormatBuf1) {
+  Xs xs;
+  fmt::MemoryWriter w;
+  int n = fmt::internal::INLINE_BUFFER_SIZE / xs.size + 1;
+  for (int i = 0; i < n; ++i)
+    w << xs;
+  EXPECT_EQ(w.size(), size_t(n * xs.size));
+  w << xs;
+  EXPECT_EQ(w.size(), size_t((n + 1) * xs.size));
+}
+#endif

{"ostream-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}}
{"format-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "gtest-extra-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "posix-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "assert-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "container-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "macro-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "posix-mock-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "time-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "printf-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "string-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "util-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "format-impl-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}, "custom-formatter-test": {"run": "PASS", "test": "PASS", "fix": "PASS"}}
{"ostream-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}}
{"passed_count": 14, "failed_count": 0, "skipped_count": 0, "passed_tests": ["format-test", "gtest-extra-test", "posix-test", "ostream-test", "assert-test", "container-test", "macro-test", "posix-mock-test", "time-test", "printf-test", "string-test", "util-test", "format-impl-test", "custom-formatter-test"], "failed_tests": [], "skipped_tests": []}
{"passed_count": 13, "failed_count": 0, "skipped_count": 0, "passed_tests": ["format-test", "gtest-extra-test", "posix-test", "assert-test", "container-test", "macro-test", "posix-mock-test", "time-test", "printf-test", "string-test", "util-test", "format-impl-test", "custom-formatter-test"], "failed_tests": [], "skipped_tests": []}
{"passed_count": 14, "failed_count": 0, "skipped_count": 0, "passed_tests": ["format-test", "gtest-extra-test", "posix-test", "ostream-test", "assert-test", "container-test", "macro-test", "posix-mock-test", "time-test", "printf-test", "string-test", "util-test", "format-impl-test", "custom-formatter-test"], "failed_tests": [], "skipped_tests": []}