diff --git a/libio/Makefile b/libio/Makefile
index 8adf2d8..159ddf1 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -58,9 +58,9 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
 	tst-mmap2-eofsync tst-mmap-offend bug-fopena+ bug-wfflush \
 	bug-ungetc2 bug-ftell bug-ungetc3 bug-ungetc4 tst-fopenloc2 \
 	tst-memstream1 tst-memstream2 tst-memstream3 tst-memstream4 \
-	tst-memstream5 \
+	tst-memstream5 tst-memstream6 \
 	tst-wmemstream1 tst-wmemstream2 tst-wmemstream3 tst-wmemstream4 \
-	tst-wmemstream5 bug-memstream1 bug-wmemstream1 \
+	tst-wmemstream5 tst-wmemstream6 bug-memstream1 bug-wmemstream1 \
 	tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
 	tst-fwrite-error tst-ftell-partial-wide tst-ftell-active-handler \
 	tst-ftell-append tst-fputws
diff --git a/libio/memstream.c b/libio/memstream.c
index 67ecc09..7c30400 100644
--- a/libio/memstream.c
+++ b/libio/memstream.c
@@ -26,12 +26,16 @@ struct _IO_FILE_memstream
   _IO_strfile _sf;
   char **bufloc;
   _IO_size_t *sizeloc;
+  char *prevwriteptr;
+  char *seekwriteptr;
 };
 
 
 static int _IO_mem_sync (_IO_FILE* fp) __THROW;
 static void _IO_mem_finish (_IO_FILE* fp, int) __THROW;
 static int _IO_mem_overflow (_IO_FILE *fp, int c) __THROW;
+static _IO_off64_t _IO_mem_seekoff (_IO_FILE *fp, _IO_off64_t offset,
+				    int dir, int mode) __THROW;
 
 
 static const struct _IO_jump_t _IO_mem_jumps libio_vtable =
@@ -44,7 +48,7 @@ static const struct _IO_jump_t _IO_mem_jumps libio_vtable =
   JUMP_INIT (pbackfail, _IO_str_pbackfail),
   JUMP_INIT (xsputn, _IO_default_xsputn),
   JUMP_INIT (xsgetn, _IO_default_xsgetn),
-  JUMP_INIT (seekoff, _IO_str_seekoff),
+  JUMP_INIT (seekoff, _IO_mem_seekoff),
   JUMP_INIT (seekpos, _IO_default_seekpos),
   JUMP_INIT (setbuf, _IO_default_setbuf),
   JUMP_INIT (sync, _IO_mem_sync),
@@ -98,11 +102,46 @@ __open_memstream (char **bufloc, _IO_size_t *sizeloc)
   new_f->fp.bufloc = bufloc;
   new_f->fp.sizeloc = sizeloc;
 
+  /* To correctly report the buffer size the implementation must track both
+     the buffer size and currently bytes written, however _IO_write_ptr is
+     updated on both write and seek operations (since some _IO_* function
+     access the pointer directly to optimize updates).  So to track current
+     written bytes two fields are used:
+
+     - prevwriteptr: track previous _IO_write_ptr before a seek operation on
+       the stream.
+     - seekwriteptr: track resulted _IO_write_ptr after a seek operation on
+       the stream.
+
+     Also, prevwriteptr is only updated iff _IO_write_ptr changed over calls
+     (meaning that a write operation occured)
+
+     So final buffer size is based on current _IO_write_ptr only if
+     its value is different than seekwriteptr, otherwise it uses the old
+     _IO_write_ptr value before seek operation (prevwriteptr).  */
+  new_f->fp.prevwriteptr = new_f->fp.seekwriteptr =
+    new_f->fp._sf._sbf._f._IO_write_ptr;
+
   return (_IO_FILE *) &new_f->fp._sf._sbf;
 }
 libc_hidden_def (__open_memstream)
 weak_alias (__open_memstream, open_memstream)
 
+/* Update 'size' with written number of bytes and return true if a written
+   operation has occured.  */
+static bool
+update_bufsize (const _IO_FILE *fp, size_t *size)
+{
+  const struct _IO_FILE_memstream *mp =
+    (const struct _IO_FILE_memstream *) fp;
+  if (fp->_IO_write_ptr == mp->seekwriteptr)
+    {
+      *size = mp->prevwriteptr - fp->_IO_write_base;
+      return false;
+    }
+  *size = fp->_IO_write_ptr - fp->_IO_write_base;
+  return true;
+}
 
 static int
 _IO_mem_sync (_IO_FILE *fp)
@@ -116,7 +155,7 @@ _IO_mem_sync (_IO_FILE *fp)
     }
 
   *mp->bufloc = fp->_IO_write_base;
-  *mp->sizeloc = fp->_IO_write_ptr - fp->_IO_write_base;
+  update_bufsize (fp, mp->sizeloc);
 
   return 0;
 }
@@ -131,8 +170,9 @@ _IO_mem_finish (_IO_FILE *fp, int dummy)
 				  fp->_IO_write_ptr - fp->_IO_write_base + 1);
   if (*mp->bufloc != NULL)
     {
-      (*mp->bufloc)[fp->_IO_write_ptr - fp->_IO_write_base] = '\0';
-      *mp->sizeloc = fp->_IO_write_ptr - fp->_IO_write_base;
+      /* An '\0' should be appended iff a write operation ocurred.  */
+      if (update_bufsize (fp, mp->sizeloc))
+	(*mp->bufloc)[*mp->sizeloc] = '\0';
 
       fp->_IO_buf_base = NULL;
     }
@@ -148,8 +188,19 @@ _IO_mem_overflow (_IO_FILE *fp, int c)
       /* Updates the returned size location on stream flush.  */
       struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
       *mp->bufloc = fp->_IO_write_base;
-      *mp->sizeloc = fp->_IO_write_ptr - fp->_IO_write_base;
+      update_bufsize (fp, mp->sizeloc);
       return 0;
     }
   return _IO_str_overflow (fp, c);
 }
+
+static _IO_off64_t
+_IO_mem_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
+{
+  struct _IO_FILE_memstream *mp = (struct _IO_FILE_memstream *) fp;
+  if (fp->_IO_write_ptr != mp->seekwriteptr)
+    mp->prevwriteptr = fp->_IO_write_ptr;
+  _IO_off64_t ret = _IO_str_seekoff (fp, offset, dir, mode);
+  mp->seekwriteptr = fp->_IO_write_ptr;
+  return ret;
+}
diff --git a/libio/tst-memstream3.c b/libio/tst-memstream3.c
index ce201d1..6521f92 100644
--- a/libio/tst-memstream3.c
+++ b/libio/tst-memstream3.c
@@ -126,15 +126,17 @@ do_test_bz20181 (void)
   if (fflush (fp) != 0)
     ERROR_RET1 ("fflush failed (errno = %d)\n", errno);
 
-  /* Avoid truncating the buffer on close.  */
+  /* fseek updates the internal buffer, but open_memstream should set the
+     size to smaller of the buffer size and number of bytes written.  Since
+     it was written just character ('z') final size should be 1.  */
   if (fseek (fp, 3, SEEK_SET) != 0)
     ERROR_RET1 ("fseek failed (errno = %d)\n", errno);
 
   if (fclose (fp) != 0)
     ERROR_RET1 ("fclose failed (errno = %d\n", errno);
 
-  if (size != 3)
-    ERROR_RET1 ("size != 3\n");
+  if (size != 1)
+    ERROR_RET1 ("size != 1 (got %zu)\n", size);
 
   if (buf[0] != W('z')
       || buf[1] != W('b')
diff --git a/libio/tst-memstream6.c b/libio/tst-memstream6.c
new file mode 100644
index 0000000..b877d68
--- /dev/null
+++ b/libio/tst-memstream6.c
@@ -0,0 +1,74 @@
+/* Test for open_memstream BZ #15298.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "tst-memstream.h"
+
+static void
+mcheck_abort (enum mcheck_status ev)
+{
+  printf ("mecheck failed with status %d\n", (int) ev);
+  exit (1);
+}
+
+static int
+do_test (void)
+{
+  mcheck_pedantic (mcheck_abort);
+
+  {
+    CHAR_T *buf;
+    size_t size;
+
+    FILE *fp = OPEN_MEMSTREAM (&buf, &size);
+    TEST_VERIFY_EXIT (fp != NULL);
+
+    /* Move internal position but do not write any bytes.  Final size should
+       be 0.  */
+    TEST_VERIFY_EXIT (fseek (fp, 10, SEEK_SET) != -1);
+    TEST_VERIFY_EXIT (fseek (fp, 20, SEEK_CUR) != -1);
+    TEST_VERIFY_EXIT (fseek (fp, 30, SEEK_CUR) != -1);
+    TEST_VERIFY_EXIT (fflush (fp) != -1);
+    TEST_VERIFY (size == 0);
+
+    /* Now write some bytes and change internal position.  Final size should
+      be based on written bytes.  */
+    TEST_VERIFY_EXIT (fseek (fp, 0, SEEK_SET) != -1);
+    TEST_VERIFY_EXIT (FWRITE (W("abc"), 1, 3, fp) == 3);
+    TEST_VERIFY_EXIT (fseek (fp, 20, SEEK_CUR) != -1);
+    TEST_VERIFY_EXIT (fseek (fp, 30, SEEK_CUR) != -1);
+    TEST_VERIFY_EXIT (fflush (fp) != -1);
+    TEST_VERIFY (size == 3);
+
+    /* Finally set position, write some bytes and change position again.
+       Final size should be based again on write position.  */
+    size_t offset = 2048;
+    TEST_VERIFY_EXIT (fseek (fp, offset, SEEK_SET) != -1);
+    TEST_VERIFY_EXIT (FWRITE (W("def"), 1, 3, fp) == 3);
+    TEST_VERIFY_EXIT (fseek (fp, 20, SEEK_CUR) != -1);
+    TEST_VERIFY_EXIT (fseek (fp, 20, SEEK_CUR) != -1);
+    TEST_VERIFY_EXIT (fflush (fp) != -1);
+    TEST_VERIFY (size == (offset + 3));
+
+    TEST_VERIFY_EXIT (fclose (fp) == 0);
+    free (buf);
+  }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/libio/tst-wmemstream6.c b/libio/tst-wmemstream6.c
new file mode 100644
index 0000000..5d8cd75
--- /dev/null
+++ b/libio/tst-wmemstream6.c
@@ -0,0 +1,20 @@
+/* Test for open_wmemstream BZ #15298.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#define TEST_WCHAR
+#include <libio/tst-memstream6.c>
diff --git a/libio/wmemstream.c b/libio/wmemstream.c
index d68334b..db54b5e 100644
--- a/libio/wmemstream.c
+++ b/libio/wmemstream.c
@@ -27,12 +27,16 @@ struct _IO_FILE_wmemstream
   _IO_strfile _sf;
   wchar_t **bufloc;
   _IO_size_t *sizeloc;
+  wchar_t *prevwriteptr;
+  wchar_t *seekwriteptr;
 };
 
 
 static int _IO_wmem_sync (_IO_FILE* fp) __THROW;
 static void _IO_wmem_finish (_IO_FILE* fp, int) __THROW;
 static int _IO_wmem_overflow (_IO_FILE *fp, int c) __THROW;
+static _IO_off64_t _IO_wmem_seekoff (_IO_FILE *fp, _IO_off64_t offset,
+				     int dir, int mode) __THROW;
 
 
 static const struct _IO_jump_t _IO_wmem_jumps libio_vtable =
@@ -45,7 +49,7 @@ static const struct _IO_jump_t _IO_wmem_jumps libio_vtable =
   JUMP_INIT (pbackfail, (_IO_pbackfail_t) _IO_wstr_pbackfail),
   JUMP_INIT (xsputn, _IO_wdefault_xsputn),
   JUMP_INIT (xsgetn, _IO_wdefault_xsgetn),
-  JUMP_INIT (seekoff, _IO_wstr_seekoff),
+  JUMP_INIT (seekoff, _IO_wmem_seekoff),
   JUMP_INIT (seekpos, _IO_default_seekpos),
   JUMP_INIT (setbuf, _IO_default_setbuf),
   JUMP_INIT (sync, _IO_wmem_sync),
@@ -99,11 +103,46 @@ open_wmemstream (wchar_t **bufloc, _IO_size_t *sizeloc)
 
   new_f->fp.bufloc = bufloc;
   new_f->fp.sizeloc = sizeloc;
+  /* To correctly report the buffer size the implementation must track both
+     the buffer size and currently bytes written, however _IO_write_ptr is
+     updated on both write and seek operations (since some _IO_* function
+     access the pointer directly to optimize updates).  So to track current
+     written bytes two fields are used:
+
+     - prevwriteptr: track previous _IO_write_ptr before a seek operation on
+       the stream.
+     - seekwriteptr: track resulted _IO_write_ptr after a seek operation on
+       the stream.
+
+     Also, prevwriteptr is only updated iff _IO_write_ptr changed over calls
+     (meaning that a write operation occured)
+
+     So final buffer size is based on current _IO_write_ptr only if
+     its value is different than seekwriteptr, otherwise it uses the old
+     _IO_write_ptr value before seek operation (prevwriteptr).  */
+  new_f->fp.prevwriteptr = new_f->fp.seekwriteptr =
+    new_f->fp._sf._sbf._f._wide_data->_IO_write_ptr;
 
   return (_IO_FILE *) &new_f->fp._sf._sbf;
 }
 
 
+/* Update 'size' with written number of bytes and return true if a written
+   operation has occured.  */
+static bool
+update_bufsize (const _IO_FILE *fp, size_t *size)
+{
+  const struct _IO_FILE_wmemstream *mp =
+    (const struct _IO_FILE_wmemstream *) fp;
+  if (fp->_wide_data->_IO_write_ptr == mp->seekwriteptr)
+    {
+      *size = mp->prevwriteptr - fp->_wide_data->_IO_write_base;
+      return false;
+    }
+  *size = fp->_wide_data->_IO_write_ptr - fp->_wide_data->_IO_write_base;
+  return true;
+}
+
 static int
 _IO_wmem_sync (_IO_FILE *fp)
 {
@@ -116,13 +155,11 @@ _IO_wmem_sync (_IO_FILE *fp)
     }
 
   *mp->bufloc = fp->_wide_data->_IO_write_base;
-  *mp->sizeloc = (fp->_wide_data->_IO_write_ptr
-		  - fp->_wide_data->_IO_write_base);
+  update_bufsize (fp, mp->sizeloc);
 
   return 0;
 }
 
-
 static void
 _IO_wmem_finish (_IO_FILE *fp, int dummy)
 {
@@ -134,10 +171,8 @@ _IO_wmem_finish (_IO_FILE *fp, int dummy)
 				     * sizeof (wchar_t));
   if (*mp->bufloc != NULL)
     {
-      size_t len = (fp->_wide_data->_IO_write_ptr
-		    - fp->_wide_data->_IO_write_base);
-      (*mp->bufloc)[len] = '\0';
-      *mp->sizeloc = len;
+      if (update_bufsize (fp, mp->sizeloc))
+	(*mp->bufloc)[*mp->sizeloc] = L'\0';
 
       fp->_wide_data->_IO_buf_base = NULL;
     }
@@ -153,9 +188,19 @@ _IO_wmem_overflow (_IO_FILE *fp, int c)
       /* Updates the returned size location on stream flush.  */
       struct _IO_FILE_wmemstream *mp = (struct _IO_FILE_wmemstream *) fp;
       *mp->bufloc = fp->_wide_data->_IO_write_base;
-      *mp->sizeloc = (fp->_wide_data->_IO_write_ptr
-		     - fp->_wide_data->_IO_write_base);
+      update_bufsize (fp, mp->sizeloc);
       return 0;
     }
   return _IO_wstr_overflow (fp, c);
 }
+
+static _IO_off64_t
+_IO_wmem_seekoff (_IO_FILE *fp, _IO_off64_t offset, int dir, int mode)
+{
+  struct _IO_FILE_wmemstream *mp = (struct _IO_FILE_wmemstream *) fp;
+  if (fp->_wide_data->_IO_write_ptr != mp->seekwriteptr)
+    mp->prevwriteptr = fp->_wide_data->_IO_write_ptr;
+  _IO_off64_t ret = _IO_wstr_seekoff (fp, offset, dir, mode);
+  mp->seekwriteptr = fp->_wide_data->_IO_write_ptr;
+  return ret;
+}
