diff --git a/NEWS b/NEWS
index 781f7a7..64a842b 100644
--- a/NEWS
+++ b/NEWS
@@ -9,8 +9,8 @@ Version 2.22
 
 * The following bugs are resolved with this release:
 
-  4719, 15467, 15790, 16560, 17569, 17792, 17912, 17932, 17944, 17949,
-  17964, 17965, 17967, 17969.
+  4719, 15467, 15790, 16374, 16560, 17569, 17792, 17912, 17932, 17944,
+  17949, 17964, 17965, 17967, 17969.
 
 Version 2.21
 
diff --git a/libio/filedoalloc.c b/libio/filedoalloc.c
index 918a24a..4be1b83 100644
--- a/libio/filedoalloc.c
+++ b/libio/filedoalloc.c
@@ -125,7 +125,10 @@ _IO_file_doallocate (fp)
 	size = st.st_blksize;
 #endif
     }
-  ALLOC_BUF (p, size, EOF);
+
+  p = calloc (size, 1);
+  if (p == NULL) return EOF;
+
   _IO_setb (fp, p, p + size, 1);
   return 1;
 }
diff --git a/libio/genops.c b/libio/genops.c
index 6612997..c787842 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -398,7 +398,7 @@ _IO_setb (f, b, eb, a)
      int a;
 {
   if (f->_IO_buf_base && !(f->_flags & _IO_USER_BUF))
-    FREE_BUF (f->_IO_buf_base, _IO_blen (f));
+    free (f->_IO_buf_base);
   f->_IO_buf_base = b;
   f->_IO_buf_end = eb;
   if (a)
@@ -587,7 +587,9 @@ _IO_default_doallocate (fp)
 {
   char *buf;
 
-  ALLOC_BUF (buf, _IO_BUFSIZ, EOF);
+  buf = calloc (_IO_BUFSIZ, 1);
+  if (buf == NULL) return EOF;
+
   _IO_setb (fp, buf, buf+_IO_BUFSIZ, 1);
   return 1;
 }
@@ -687,7 +689,7 @@ _IO_default_finish (fp, dummy)
   struct _IO_marker *mark;
   if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF))
     {
-      FREE_BUF (fp->_IO_buf_base, _IO_blen (fp));
+      free (fp->_IO_buf_base);
       fp->_IO_buf_base = fp->_IO_buf_end = NULL;
     }
 
@@ -950,8 +952,6 @@ _IO_unbuffer_write (void)
   for (fp = (_IO_FILE *) _IO_list_all; fp; fp = fp->_chain)
     {
       if (! (fp->_flags & _IO_UNBUFFERED)
-	  && (! (fp->_flags & _IO_NO_WRITES)
-	      || (fp->_flags & _IO_IS_APPENDING))
 	  /* Iff stream is un-orientated, it wasn't used. */
 	  && fp->_mode != 0)
 	{
@@ -967,14 +967,30 @@ _IO_unbuffer_write (void)
 	      __sched_yield ();
 #endif
 
-	  if (! dealloc_buffers && !(fp->_flags & _IO_USER_BUF))
+	  if (!dealloc_buffers)
 	    {
-	      fp->_flags |= _IO_USER_BUF;
-
-	      fp->_freeres_list = freeres_list;
-	      freeres_list = fp;
-	      fp->_freeres_buf = fp->_IO_buf_base;
-	      fp->_freeres_size = _IO_blen (fp);
+	      const bool need_freeres = !(fp->_flags & _IO_USER_BUF)
+		  || (!(fp->_flags2 & _IO_FLAGS2_USER_WBUF) && fp->_mode > 0);
+
+	     if (need_freeres)
+		{
+		  fp->_freeres_buf = fp->_freeres_wbuf = NULL;
+		  fp->_freeres_list = freeres_list;
+		  freeres_list = fp;
+
+		  if (!(fp->_flags & _IO_USER_BUF))
+		    {
+		      fp->_flags |= _IO_USER_BUF;
+		      fp->_freeres_buf = fp->_IO_buf_base;
+		    }
+
+		  if (fp->_mode > 0
+		      && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
+		    {
+		      fp->_flags2 |= _IO_FLAGS2_USER_WBUF;
+		      fp->_freeres_wbuf = fp->_wide_data->_IO_buf_base;
+		    }
+		}
 	    }
 
 	  _IO_SETBUF (fp, NULL, 0);
@@ -998,7 +1014,8 @@ libc_freeres_fn (buffer_free)
 
   while (freeres_list != NULL)
     {
-      FREE_BUF (freeres_list->_freeres_buf, freeres_list->_freeres_size);
+      free (freeres_list->_freeres_buf);
+      free (freeres_list->_freeres_wbuf);
 
       freeres_list = freeres_list->_freeres_list;
     }
diff --git a/libio/libio.h b/libio/libio.h
index 9ff1fb0..fd139d3 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -297,17 +297,17 @@ struct _IO_FILE_complete
   struct _IO_wide_data *_wide_data;
   struct _IO_FILE *_freeres_list;
   void *_freeres_buf;
-  size_t _freeres_size;
+  void *_freeres_wbuf;
 # else
   void *__pad1;
   void *__pad2;
   void *__pad3;
   void *__pad4;
-  size_t __pad5;
+  void *__pad5;
 # endif
   int _mode;
   /* Make sure we don't get into trouble again.  */
-  char _unused2[15 * sizeof (int) - 4 * sizeof (void *) - sizeof (size_t)];
+  char _unused2[15 * sizeof (int) - 5 * sizeof (void *)];
 #endif
 };
 
diff --git a/libio/libioP.h b/libio/libioP.h
index d8604ca..bee9eaa 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -746,45 +746,6 @@ extern _IO_off64_t _IO_seekpos_unlocked (_IO_FILE *, _IO_off64_t, int)
 #  define ftruncate __ftruncate
 # endif
 
-# define ROUND_TO_PAGE(_S) \
-       (((_S) + EXEC_PAGESIZE - 1) & ~(EXEC_PAGESIZE - 1))
-
-# define FREE_BUF(_B, _S) \
-       munmap ((_B), ROUND_TO_PAGE (_S))
-# define ALLOC_BUF(_B, _S, _R) \
-       do {								      \
-	  (_B) = (char *) mmap (0, ROUND_TO_PAGE (_S),			      \
-				PROT_READ | PROT_WRITE,			      \
-				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);	      \
-	  if ((_B) == (char *) MAP_FAILED)				      \
-	    return (_R);						      \
-       } while (0)
-# define ALLOC_WBUF(_B, _S, _R) \
-       do {								      \
-	  (_B) = (wchar_t *) mmap (0, ROUND_TO_PAGE (_S),		      \
-				   PROT_READ | PROT_WRITE,		      \
-				   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);	      \
-	  if ((_B) == (wchar_t *) MAP_FAILED)				      \
-	    return (_R);						      \
-       } while (0)
-
-#else /* _G_HAVE_MMAP */
-
-# define FREE_BUF(_B, _S) \
-       free(_B)
-# define ALLOC_BUF(_B, _S, _R) \
-       do {								      \
-	  (_B) = (char*)malloc(_S);					      \
-	  if ((_B) == NULL)						      \
-	    return (_R);						      \
-       } while (0)
-# define ALLOC_WBUF(_B, _S, _R) \
-       do {								      \
-	  (_B) = (wchar_t *)malloc(_S);					      \
-	  if ((_B) == NULL)						      \
-	    return (_R);						      \
-       } while (0)
-
 #endif /* _G_HAVE_MMAP */
 
 #ifndef OS_FSTAT
diff --git a/libio/wfiledoalloc.c b/libio/wfiledoalloc.c
index 12425fd..9c7fbf6 100644
--- a/libio/wfiledoalloc.c
+++ b/libio/wfiledoalloc.c
@@ -95,7 +95,10 @@ _IO_wfile_doallocate (fp)
   size = fp->_IO_buf_end - fp->_IO_buf_base;
   if ((fp->_flags & _IO_USER_BUF))
     size = (size + sizeof (wchar_t) - 1) / sizeof (wchar_t);
-  ALLOC_WBUF (p, size * sizeof (wchar_t), EOF);
+
+  p = calloc (size, sizeof (wchar_t));
+  if (p == NULL) return EOF;
+
   _IO_wsetb (fp, p, p + size, 1);
   return 1;
 }
diff --git a/libio/wgenops.c b/libio/wgenops.c
index 69f3b95..afebee5 100644
--- a/libio/wgenops.c
+++ b/libio/wgenops.c
@@ -111,7 +111,7 @@ _IO_wsetb (f, b, eb, a)
      int a;
 {
   if (f->_wide_data->_IO_buf_base && !(f->_flags2 & _IO_FLAGS2_USER_WBUF))
-    FREE_BUF (f->_wide_data->_IO_buf_base, _IO_wblen (f) * sizeof (wchar_t));
+    free (f->_wide_data->_IO_buf_base);
   f->_wide_data->_IO_buf_base = b;
   f->_wide_data->_IO_buf_end = eb;
   if (a)
@@ -195,8 +195,7 @@ _IO_wdefault_finish (fp, dummy)
   struct _IO_marker *mark;
   if (fp->_wide_data->_IO_buf_base && !(fp->_flags2 & _IO_FLAGS2_USER_WBUF))
     {
-      FREE_BUF (fp->_wide_data->_IO_buf_base,
-		_IO_wblen (fp) * sizeof (wchar_t));
+      free (fp->_wide_data->_IO_buf_base);
       fp->_wide_data->_IO_buf_base = fp->_wide_data->_IO_buf_end = NULL;
     }
 
@@ -426,7 +425,9 @@ _IO_wdefault_doallocate (fp)
 {
   wchar_t *buf;
 
-  ALLOC_WBUF (buf, _IO_BUFSIZ, EOF);
+  buf = calloc (_IO_BUFSIZ, 1);
+  if (buf == NULL) return EOF;
+
   _IO_wsetb (fp, buf, buf + _IO_BUFSIZ, 1);
   return 1;
 }
