public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
@ 2014-07-02 12:30 Adhemerval Zanella
  2014-07-07 18:01 ` Adhemerval Zanella
  2014-10-20 23:00 ` Rich Felker
  0 siblings, 2 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2014-07-02 12:30 UTC (permalink / raw)
  To: GNU C. Library

Hi,

This is a small update on the previous fmemopen patch I have sent [1].
the change is basically:

* 'w' mode does not truncate the buffer, only 'w+'

I also rebased against master to adjust NEWS file.

[1] https://sourceware.org/ml/libc-alpha/2014-06/msg00878.html

--

	[BZ #6544]
	[BZ #11216]
	[BZ #12836]
	[BZ #13151]
	[BZ #13152]
	[BZ #14292]
	* include/stdio.h (fmemopen): Remove hidden prototype.
	(__fmemopen): Add new hidden prototype.
	* libio/Makefile: Add oldfmemopen object.
	* libio/Versions [GLIBC_2.20]: Add new fmemopen symbol.
	* libio/fmemopen.c (__fmemopen): Function rewrite to be POSIX
	compliance.
	* libio/oldfmemopen.c: New file: old fmemopen implementation for
	symbol compatibility.
	* stdio-common/Makefile [tests]: Add new tst-fmemopen3.
	* stdio-common/psiginfo.c [psiginfo]: Call __fmemopen instead of
	fmemopen.
	* stdio-common/tst-fmemopen3.c: New file: more fmemopen tests, focus
	on append and read mode.
	* sysdeps/unix/sysv/linux/aarch64/nptl/libc.abilist [GLIBC_2.20]: Add
	fmemopen.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist [GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/arm/libc.abilist [GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist [GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist [GLIBC_2.20]:
	Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist [GLIBC_2.20]:
	Likewise.
	* sysdeps/unix/sysv/linux/microblaze/nptl/libc.abilist [GLIBC_2.20]:
	Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist [GLIBC_2.20]:
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist [GLIBC_2.20]:
	Likewise.
	* sysdeps/unix/sysv/linux/sh/nptl/libc.abilist [GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
	[GLIBC_2.20]: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist [GLIBC_2.20]:
	Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist [GLIBC_2.20]:
	Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist [GLIBC_2.20]:
	Likewise.

---

diff --git a/NEWS b/NEWS
index a07ea66..7a0851e 100644
--- a/NEWS
+++ b/NEWS
@@ -9,19 +9,20 @@ Version 2.20
 
 * The following bugs are resolved with this release:
 
-  6804, 9894, 12994, 13347, 13651, 14308, 14770, 15119, 15132, 15347, 15514,
-  15698, 15804, 15894, 15946, 16002, 16064, 16095, 16198, 16284, 16287,
-  16315, 16348, 16349, 16354, 16357, 16362, 16447, 16516, 16532, 16539,
-  16545, 16561, 16562, 16564, 16574, 16599, 16600, 16609, 16610, 16611,
-  16613, 16619, 16623, 16629, 16632, 16634, 16639, 16642, 16648, 16649,
-  16670, 16674, 16677, 16680, 16681, 16683, 16689, 16695, 16701, 16706,
-  16707, 16712, 16713, 16714, 16724, 16731, 16739, 16740, 16743, 16754,
-  16758, 16759, 16760, 16770, 16786, 16789, 16791, 16796, 16799, 16800,
-  16815, 16823, 16824, 16831, 16838, 16849, 16854, 16876, 16877, 16878,
-  16882, 16885, 16888, 16890, 16912, 16915, 16916, 16917, 16918, 16922,
-  16927, 16928, 16932, 16943, 16958, 16965, 16966, 16967, 16977, 16978,
-  16984, 16990, 16996, 17009, 17022, 17031, 17042, 17048, 17050, 17058,
-  17061, 17062, 17069, 17075, 17079, 17084, 17086, 17092, 17097.
+  6544, 6804, 9894, 11216, 12836, 12994, 13151, 13152, 13347, 13651, 14292,
+  14308, 14770, 15119, 15132, 15347, 15514, 15698, 15804, 15894, 15946,
+  16002, 16064, 16095, 16198, 16284, 16287, 16315, 16348, 16349, 16354,
+  16357, 16362, 16447, 16516, 16532, 16539, 16545, 16561, 16562, 16564,
+  16574, 16599, 16600, 16609, 16610, 16611, 16613, 16619, 16623, 16629,
+  16632, 16634, 16639, 16642, 16648, 16649, 16670, 16674, 16677, 16680,
+  16681, 16683, 16689, 16695, 16701, 16706, 16707, 16712, 16713, 16714,
+  16724, 16731, 16739, 16740, 16743, 16754, 16758, 16759, 16760, 16770,
+  16786, 16789, 16791, 16796, 16799, 16800, 16815, 16823, 16824, 16831,
+  16838, 16849, 16854, 16876, 16877, 16878, 16882, 16885, 16888, 16890,
+  16912, 16915, 16916, 16917, 16918, 16922, 16927, 16928, 16932, 16943,
+  16958, 16965, 16966, 16967, 16977, 16978, 16984, 16990, 16996, 17009,
+  17022, 17031, 17042, 17048, 17050, 17058, 17061, 17062, 17069, 17075,
+  17079, 17084, 17086, 17092, 17097.
 
 * Optimized strchr implementation for AArch64.  Contributed by ARM Ltd.
 
diff --git a/include/stdio.h b/include/stdio.h
index 9f2ea31..94ba5a5 100644
--- a/include/stdio.h
+++ b/include/stdio.h
@@ -152,7 +152,6 @@ libc_hidden_proto (fread_unlocked)
 libc_hidden_proto (fwrite_unlocked)
 libc_hidden_proto (fgets_unlocked)
 libc_hidden_proto (fputs_unlocked)
-libc_hidden_proto (fmemopen)
 libc_hidden_proto (open_memstream)
 libc_hidden_proto (__libc_fatal)
 libc_hidden_proto (__vsprintf_chk)
@@ -180,6 +179,9 @@ gets (char *__str)
 }
 #  endif
 
+extern FILE * __fmemopen (void *buf, size_t len, const char *mode);
+libc_hidden_proto (__fmemopen)
+
 __END_DECLS
 # endif
 
diff --git a/libio/Makefile b/libio/Makefile
index 56952ce..c76b37e 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -46,7 +46,7 @@ routines	:=							      \
 	__fbufsize __freading __fwriting __freadable __fwritable __flbf	      \
 	__fpurge __fpending __fsetlocking				      \
 									      \
-	libc_fatal fmemopen
+	libc_fatal fmemopen oldfmemopen
 
 tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
 	tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
diff --git a/libio/Versions b/libio/Versions
index 8df89d2..7ffa64d 100644
--- a/libio/Versions
+++ b/libio/Versions
@@ -148,6 +148,10 @@ libc {
   GLIBC_2.4 {
     open_wmemstream;
   }
+  GLIBC_2.20 {
+    # f*
+    fmemopen;
+  }
   GLIBC_PRIVATE {
     # Used by NPTL and librt
     __libc_fatal;
diff --git a/libio/fmemopen.c b/libio/fmemopen.c
index aee2696..53e9d57 100644
--- a/libio/fmemopen.c
+++ b/libio/fmemopen.c
@@ -1,7 +1,6 @@
-/* Fmemopen implementation.
-   Copyright (C) 2000-2014 Free Software Foundation, Inc.
+/* fmemopen implementation.
+   Copyright (C) 2014 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hanno Mueller, kontakt@hanno.de, 2000.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -17,54 +16,10 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-/*
- * fmemopen() - "my" version of a string stream
- * Hanno Mueller, kontakt@hanno.de
- *
- *
- * I needed fmemopen() for an application that I currently work on,
- * but couldn't find it in libio. The following snippet of code is an
- * attempt to implement what glibc's documentation describes.
- *
- *
- *
- * I already see some potential problems:
- *
- * - I never used the "original" fmemopen(). I am sure that "my"
- *   fmemopen() behaves differently than the original version.
- *
- * - The documentation doesn't say wether a string stream allows
- *   seeks. I checked the old fmemopen implementation in glibc's stdio
- *   directory, wasn't quite able to see what is going on in that
- *   source, but as far as I understand there was no seek there. For
- *   my application, I needed fseek() and ftell(), so it's here.
- *
- * - "append" mode and fseek(p, SEEK_END) have two different ideas
- *   about the "end" of the stream.
- *
- *   As described in the documentation, when opening the file in
- *   "append" mode, the position pointer will be set to the first null
- *   character of the string buffer (yet the buffer may already
- *   contain more data). For fseek(), the last byte of the buffer is
- *   used as the end of the stream.
- *
- * - It is unclear to me what the documentation tries to say when it
- *   explains what happens when you use fmemopen with a NULL
- *   buffer.
- *
- *   Quote: "fmemopen [then] allocates an array SIZE bytes long. This
- *   is really only useful if you are going to write things to the
- *   buffer and then read them back in again."
- *
- *   What does that mean if the original fmemopen() did not allow
- *   seeking? How do you read what you just wrote without seeking back
- *   to the beginning of the stream?
- *
- * - I think there should be a second version of fmemopen() that does
- *   not add null characters for each write. (At least in my
- *   application, I am not actually using strings but binary data and
- *   so I don't need the stream to add null characters on its own.)
- */
+/* fmemopen() from 2.20 and forward works as defined by POSIX.  It also
+   provides an older symbol, version 2.2.5, that behaves different regarding
+   SEEK_END (libio/oldfmemopen.c).  */
+
 
 #include <errno.h>
 #include <libio.h>
@@ -79,25 +34,23 @@
 typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
 struct fmemopen_cookie_struct
 {
-  char *buffer;
-  int mybuffer;
-  int binmode;
-  size_t size;
-  _IO_off64_t pos;
-  size_t maxpos;
+  char        *buffer;   /* memory buffer.  */
+  int         mybuffer;  /* own allocated buffer?  */
+  int         append;    /* buffer openened for append?  */
+  size_t      size;      /* buffer length in bytes.  */
+  _IO_off64_t pos;       /* current position at the buffer.  */
+  size_t      maxpos;    /* max position in buffer.  */
 };
 
 
 static ssize_t
 fmemopen_read (void *cookie, char *b, size_t s)
 {
-  fmemopen_cookie_t *c;
-
-  c = (fmemopen_cookie_t *) cookie;
+  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
 
-  if (c->pos + s > c->size)
+  if (c->pos + s > c->maxpos)
     {
-      if ((size_t) c->pos == c->size)
+      if ((size_t) c->pos == c->maxpos)
 	return 0;
       s = c->size - c->pos;
     }
@@ -115,29 +68,28 @@ fmemopen_read (void *cookie, char *b, size_t s)
 static ssize_t
 fmemopen_write (void *cookie, const char *b, size_t s)
 {
-  fmemopen_cookie_t *c;
+  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
+  _IO_off64_t pos = c->append ? c->maxpos : c->pos;
   int addnullc;
 
-  c = (fmemopen_cookie_t *) cookie;
-
-  addnullc = c->binmode == 0 && (s == 0 || b[s - 1] != '\0');
+  addnullc = (s == 0 || b[s - 1] != '\0');
 
-  if (c->pos + s + addnullc > c->size)
+  if (pos + s + addnullc > c->size)
     {
-      if ((size_t) (c->pos + addnullc) == c->size)
+      if ((size_t) (pos + addnullc) >= c->size)
 	{
 	  __set_errno (ENOSPC);
 	  return 0;
 	}
-      s = c->size - c->pos - addnullc;
+      s = c->size - pos - addnullc;
     }
 
-  memcpy (&(c->buffer[c->pos]), b, s);
+  memcpy (&(c->buffer[pos]), b, s);
 
-  c->pos += s;
-  if ((size_t) c->pos > c->maxpos)
+  pos += s;
+  if ((size_t) pos > c->maxpos)
     {
-      c->maxpos = c->pos;
+      c->maxpos = pos;
       if (addnullc)
 	c->buffer[c->maxpos] = '\0';
     }
@@ -150,9 +102,7 @@ static int
 fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
 {
   _IO_off64_t np;
-  fmemopen_cookie_t *c;
-
-  c = (fmemopen_cookie_t *) cookie;
+  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
 
   switch (w)
     {
@@ -165,7 +115,7 @@ fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
       break;
 
     case SEEK_END:
-      np = (c->binmode ? c->size : c->maxpos) - *p;
+      np = c->maxpos + *p;
       break;
 
     default:
@@ -184,9 +134,7 @@ fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
 static int
 fmemopen_close (void *cookie)
 {
-  fmemopen_cookie_t *c;
-
-  c = (fmemopen_cookie_t *) cookie;
+  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
 
   if (c->mybuffer)
     free (c->buffer);
@@ -197,18 +145,11 @@ fmemopen_close (void *cookie)
 
 
 FILE *
-fmemopen (void *buf, size_t len, const char *mode)
+__fmemopen (void *buf, size_t len, const char *mode)
 {
   cookie_io_functions_t iof;
   fmemopen_cookie_t *c;
 
-  if (__glibc_unlikely (len == 0))
-    {
-    einval:
-      __set_errno (EINVAL);
-      return NULL;
-    }
-
   c = (fmemopen_cookie_t *) malloc (sizeof (fmemopen_cookie_t));
   if (c == NULL)
     return NULL;
@@ -231,26 +172,38 @@ fmemopen (void *buf, size_t len, const char *mode)
       if (__glibc_unlikely ((uintptr_t) len > -(uintptr_t) buf))
 	{
 	  free (c);
-	  goto einval;
+	  __set_errno (EINVAL);
+	  return NULL;
 	}
 
       c->buffer = buf;
 
-      if (mode[0] == 'w')
+      /* POSIX states that w+ mode should truncate the buffer.  */
+      if (mode[0] == 'w' && mode[1] == '+')
 	c->buffer[0] = '\0';
 
       c->maxpos = strnlen (c->buffer, len);
     }
 
+
+  /* Mode   |  starting position (cookie::pos) |          size (cookie::size)
+   * ------ |----------------------------------|-----------------------------
+   * read   |          beginning of the buffer |                size argument
+   * write  |          beginning of the buffer |                         zero
+   * append |    first null or size buffer + 1 |  first null or size argument
+   */
+
   c->size = len;
 
-  if (mode[0] == 'a')
+  if (mode[0] == 'r')
+    c->maxpos = len;
+
+  c->append = mode[0] == 'a';
+  if (c->append)
     c->pos = c->maxpos;
   else
     c->pos = 0;
 
-  c->binmode = mode[0] != '\0' && mode[1] == 'b';
-
   iof.read = fmemopen_read;
   iof.write = fmemopen_write;
   iof.seek = fmemopen_seek;
@@ -258,4 +211,5 @@ fmemopen (void *buf, size_t len, const char *mode)
 
   return _IO_fopencookie (c, mode, iof);
 }
-libc_hidden_def (fmemopen)
+libc_hidden_def (__fmemopen)
+versioned_symbol (libc, __fmemopen, fmemopen, GLIBC_2_20);
diff --git a/libio/oldfmemopen.c b/libio/oldfmemopen.c
new file mode 100644
index 0000000..4e85ebe
--- /dev/null
+++ b/libio/oldfmemopen.c
@@ -0,0 +1,265 @@
+/* Fmemopen implementation.
+   Copyright (C) 2000-2014 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Hanno Mueller, kontakt@hanno.de, 2000.
+
+   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/>.  */
+
+/*
+ * fmemopen() - "my" version of a string stream
+ * Hanno Mueller, kontakt@hanno.de
+ *
+ *
+ * I needed fmemopen() for an application that I currently work on,
+ * but couldn't find it in libio. The following snippet of code is an
+ * attempt to implement what glibc's documentation describes.
+ *
+ *
+ *
+ * I already see some potential problems:
+ *
+ * - I never used the "original" fmemopen(). I am sure that "my"
+ *   fmemopen() behaves differently than the original version.
+ *
+ * - The documentation doesn't say wether a string stream allows
+ *   seeks. I checked the old fmemopen implementation in glibc's stdio
+ *   directory, wasn't quite able to see what is going on in that
+ *   source, but as far as I understand there was no seek there. For
+ *   my application, I needed fseek() and ftell(), so it's here.
+ *
+ * - "append" mode and fseek(p, SEEK_END) have two different ideas
+ *   about the "end" of the stream.
+ *
+ *   As described in the documentation, when opening the file in
+ *   "append" mode, the position pointer will be set to the first null
+ *   character of the string buffer (yet the buffer may already
+ *   contain more data). For fseek(), the last byte of the buffer is
+ *   used as the end of the stream.
+ *
+ * - It is unclear to me what the documentation tries to say when it
+ *   explains what happens when you use fmemopen with a NULL
+ *   buffer.
+ *
+ *   Quote: "fmemopen [then] allocates an array SIZE bytes long. This
+ *   is really only useful if you are going to write things to the
+ *   buffer and then read them back in again."
+ *
+ *   What does that mean if the original fmemopen() did not allow
+ *   seeking? How do you read what you just wrote without seeking back
+ *   to the beginning of the stream?
+ *
+ * - I think there should be a second version of fmemopen() that does
+ *   not add null characters for each write. (At least in my
+ *   application, I am not actually using strings but binary data and
+ *   so I don't need the stream to add null characters on its own.)
+ */
+
+#include "libioP.h"
+
+#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_20)
+
+#include <errno.h>
+#include <libio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+
+
+typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
+struct fmemopen_cookie_struct
+{
+  char *buffer;
+  int mybuffer;
+  int binmode;
+  size_t size;
+  _IO_off64_t pos;
+  size_t maxpos;
+};
+
+
+static ssize_t
+fmemopen_read (void *cookie, char *b, size_t s)
+{
+  fmemopen_cookie_t *c;
+
+  c = (fmemopen_cookie_t *) cookie;
+
+  if (c->pos + s > c->size)
+    {
+      if ((size_t) c->pos == c->size)
+	return 0;
+      s = c->size - c->pos;
+    }
+
+  memcpy (b, &(c->buffer[c->pos]), s);
+
+  c->pos += s;
+  if ((size_t) c->pos > c->maxpos)
+    c->maxpos = c->pos;
+
+  return s;
+}
+
+
+static ssize_t
+fmemopen_write (void *cookie, const char *b, size_t s)
+{
+  fmemopen_cookie_t *c;
+  int addnullc;
+
+  c = (fmemopen_cookie_t *) cookie;
+
+  addnullc = c->binmode == 0 && (s == 0 || b[s - 1] != '\0');
+
+  if (c->pos + s + addnullc > c->size)
+    {
+      if ((size_t) (c->pos + addnullc) == c->size)
+	{
+	  __set_errno (ENOSPC);
+	  return 0;
+	}
+      s = c->size - c->pos - addnullc;
+    }
+
+  memcpy (&(c->buffer[c->pos]), b, s);
+
+  c->pos += s;
+  if ((size_t) c->pos > c->maxpos)
+    {
+      c->maxpos = c->pos;
+      if (addnullc)
+	c->buffer[c->maxpos] = '\0';
+    }
+
+  return s;
+}
+
+
+static int
+fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
+{
+  _IO_off64_t np;
+  fmemopen_cookie_t *c;
+
+  c = (fmemopen_cookie_t *) cookie;
+
+  switch (w)
+    {
+    case SEEK_SET:
+      np = *p;
+      break;
+
+    case SEEK_CUR:
+      np = c->pos + *p;
+      break;
+
+    case SEEK_END:
+      np = (c->binmode ? c->size : c->maxpos) - *p;
+      break;
+
+    default:
+      return -1;
+    }
+
+  if (np < 0 || (size_t) np > c->size)
+    return -1;
+
+  *p = c->pos = np;
+
+  return 0;
+}
+
+
+static int
+fmemopen_close (void *cookie)
+{
+  fmemopen_cookie_t *c;
+
+  c = (fmemopen_cookie_t *) cookie;
+
+  if (c->mybuffer)
+    free (c->buffer);
+  free (c);
+
+  return 0;
+}
+
+
+FILE *
+__old_fmemopen (void *buf, size_t len, const char *mode)
+{
+  cookie_io_functions_t iof;
+  fmemopen_cookie_t *c;
+
+  if (__glibc_unlikely (len == 0))
+    {
+    einval:
+      __set_errno (EINVAL);
+      return NULL;
+    }
+
+  c = (fmemopen_cookie_t *) malloc (sizeof (fmemopen_cookie_t));
+  if (c == NULL)
+    return NULL;
+
+  c->mybuffer = (buf == NULL);
+
+  if (c->mybuffer)
+    {
+      c->buffer = (char *) malloc (len);
+      if (c->buffer == NULL)
+	{
+	  free (c);
+	  return NULL;
+	}
+      c->buffer[0] = '\0';
+      c->maxpos = 0;
+    }
+  else
+    {
+      if (__glibc_unlikely ((uintptr_t) len > -(uintptr_t) buf))
+	{
+	  free (c);
+	  goto einval;
+	}
+
+      c->buffer = buf;
+
+      if (mode[0] == 'w')
+	c->buffer[0] = '\0';
+
+      c->maxpos = strnlen (c->buffer, len);
+    }
+
+  c->size = len;
+
+  if (mode[0] == 'a')
+    c->pos = c->maxpos;
+  else
+    c->pos = 0;
+
+  c->binmode = mode[0] != '\0' && mode[1] == 'b';
+
+  iof.read = fmemopen_read;
+  iof.write = fmemopen_write;
+  iof.seek = fmemopen_seek;
+  iof.close = fmemopen_close;
+
+  return _IO_fopencookie (c, mode, iof);
+}
+compat_symbol (libc, __old_fmemopen, fmemopen, GLIBC_2_2);
+#endif
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 5f8e534..5971e65 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -57,7 +57,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
 	 bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \
 	 scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \
 	 bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \
-	 bug25 tst-printf-round bug26
+	 bug25 tst-printf-round bug26 tst-fmemopen3
 
 test-srcs = tst-unbputc tst-printf
 
diff --git a/stdio-common/psiginfo.c b/stdio-common/psiginfo.c
index 564d237..62a9671 100644
--- a/stdio-common/psiginfo.c
+++ b/stdio-common/psiginfo.c
@@ -60,7 +60,7 @@ void
 psiginfo (const siginfo_t *pinfo, const char *s)
 {
   char buf[512];
-  FILE *fp = fmemopen (buf, sizeof (buf), "w");
+  FILE *fp = __fmemopen (buf, sizeof (buf), "w");
   if (fp == NULL)
     {
       const char *colon;
diff --git a/stdio-common/tst-fmemopen3.c b/stdio-common/tst-fmemopen3.c
new file mode 100644
index 0000000..1ff0920
--- /dev/null
+++ b/stdio-common/tst-fmemopen3.c
@@ -0,0 +1,206 @@
+/* fmemopen tests for append and read mode.
+   Copyright (C) 2014 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+static void
+print_buffer (const char *s, size_t n)
+{
+  size_t i;
+  for (i=0; i<n; ++i)
+    printf ("0x%02X (%c), ", s[i], s[i]);
+}
+
+/* This test check append mode initial position (a/a+) based on POSIX defition
+   (BZ#6544 and BZ#13151).  */
+static int
+do_test_write_append (const char *mode)
+{
+  char buf[32] = "testing buffer";
+  char exp[32] = "testing bufferXX";
+
+  FILE *fp = fmemopen (buf, sizeof (buf), mode);
+
+  fflush (fp);
+  fprintf (fp, "X");
+  fseek (fp, 0, SEEK_SET);
+  fprintf (fp, "X");
+  fclose (fp);
+
+  if (strcmp (buf, exp) != 0)
+    {
+      printf ("%s: check failed: %s != %s\n", __FUNCTION__, buf, exp);
+      return 1;
+    }
+
+  return 0;
+}
+
+/* This test check append mode initial position (a/a+) based on POSIX defition
+   (BZ#6544 and BZ#13151) for buffer without null byte end.  */
+static int
+do_test_write_append_without_null (const char *mode)
+{
+  char buf[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
+  char exp[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
+
+  /* If '\0' is not found in buffer, POSIX states that SEEK_SET should be
+     the size argument.  */
+  FILE *fp = fmemopen (buf, sizeof (buf) - 2, "a");
+
+  fflush (fp);
+  fputc (0x70, fp);
+  fseek (fp, 0, SEEK_SET);
+  fputc (0x70, fp);
+  fputc (0x70, fp);
+  fclose (fp);
+
+  /* POSIX also states that a write operation on the stream shall not advance
+     the current buffer size beyond the size given in fmemopen, so the string
+     should be same.  */
+  if (memcmp (buf, exp, sizeof (buf)) != 0)
+    {
+      printf ("%s: check failed: ", __FUNCTION__);
+      print_buffer (buf, sizeof (buf));
+      printf ("!= ");
+      print_buffer (exp, sizeof (exp));
+      printf ("\n");
+      return 1;
+    }
+
+  return 0;
+}
+
+/* This test check for initial position and feek value for fmemopen objects
+   opened with append mode.  */
+static int
+do_test_read_append (void)
+{
+  char buf[32] = "testing buffer";
+  size_t buflen = strlen (buf);
+  long fpos;
+
+  /* POSIX defines for 'a+' the initial position is the first null byte.  */
+  FILE *fp = fmemopen (buf, sizeof (buf), "a+");
+
+  fpos = ftell (fp);
+  if (fpos != buflen)
+    {
+      printf ("%s: ftell|SEEK_SET (fp) %li != strlen (%s) %li\n",
+	      __FUNCTION__, fpos, buf, buflen);
+      fclose (fp);
+      return 1;
+    }
+
+  fseek (fp, 0, SEEK_END);
+
+  if (fpos != buflen)
+    {
+      printf ("%s: ftell|SEEK_END (fp) %li != strlen (%s) %li\n",
+	      __FUNCTION__, fpos, buf, buflen);
+      fclose (fp);
+      return 1;
+    }
+  fclose (fp);
+
+  /* Check if attempting to read past the current size, defined as strlen (buf)
+     yield an EOF.  */
+  fp = fmemopen (buf, sizeof (buf), "a+");
+  if (getc(fp) != EOF)
+    {
+      printf ("%s: getc(fp) != EOF\n", __FUNCTION__);
+      fclose (fp);
+      return -1;
+    }
+
+  fclose (fp);
+
+  return 0;
+}
+
+/* This test check for fseek (SEEK_END) using negative offsets (BZ#14292).  The
+   starting position of descriptor is different base on the opening mode.  */
+static int
+do_test_read_seek_neg (const char *mode, const char *expected)
+{
+  char buf[] = "abcdefghijklmnopqrstuvxz0123456789";
+  char tmp[10];
+  size_t tmps = sizeof (tmps);
+  long offset = -11;
+
+  FILE *fp = fmemopen (buf, sizeof (buf), mode);
+  fseek (fp, offset, SEEK_END);
+  fread (tmp, tmps, 1, fp);
+  
+  if (memcmp (tmp, expected, tmps) != 0)
+    {
+      printf ("%s: fmemopen(%s) - fseek (fp, %li, SEEK_END):\n",
+	      __FUNCTION__, mode, offset);
+      printf ("  returned: ");
+      print_buffer (tmp, tmps);
+      printf ("\n");
+      printf ("  expected: ");
+      print_buffer (expected, tmps);
+      printf ("\n");
+      return 1;
+    }
+  
+  fclose (fp);
+
+  return 0;
+}
+
+static int
+do_test_read_seek_negative (void)
+{
+  int ret = 0;
+
+  /* 'r' and 'w' modes defines the initial position at the buffer start and
+     seek with SEEK_END shall seek relative to its size give in fmemopen
+     call.  The expected tmp result is 0 to 9 *without* the ending null  */
+  ret += do_test_read_seek_neg ("r", "0123456789");
+  /* 'a+' mode sets the initial position at the first null byte in buffer and
+    SEEK_END shall seek relative to its size as well.  The expected result is
+    z012345678, since SEEK_END plus a+ start at '\0', not size.  */
+  ret += do_test_read_seek_neg ("a+", "z012345678");
+
+  return ret;
+}
+
+static int
+do_test (void)
+{
+  int ret = 0;
+
+  ret += do_test_write_append ("a");
+  ret += do_test_write_append_without_null ("a");
+  ret += do_test_write_append ("a+");
+  ret += do_test_write_append_without_null ("a+");
+
+  ret += do_test_read_append ();
+
+  ret += do_test_read_seek_negative ();
+
+  return ret;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index aeee312..6cf2ddd 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2081,3 +2081,6 @@ GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
  _mcount F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 980e088..11f03a5 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -1822,6 +1822,9 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.2
  GLIBC_2.2 A
  _IO_adjust_wcolumn F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index ce45208..0a6ef89 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -89,6 +89,9 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.4
  GLIBC_2.4 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 3cb314d..af60934 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2023,6 +2023,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
index 067552d..afe6f4b 100644
--- a/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
@@ -1881,6 +1881,9 @@ GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
  getunwind F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index f06cc8e..2bc1ce4 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -90,6 +90,9 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.4
  GLIBC_2.4 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 9010ea7..48c25b4 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1979,6 +1979,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 6e8d993..8b506ed 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2080,3 +2080,6 @@ GLIBC_2.18
  xencrypt F
  xprt_register F
  xprt_unregister F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 1c3490c..eb7860e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1951,6 +1951,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index d8fd823..e4385d2 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1949,6 +1949,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 3e6ed35..44b4f20 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1947,6 +1947,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index c7e46aa..2c00ad7 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1941,6 +1941,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index f27b48b..29b9695 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1983,6 +1983,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index a54382e..b57f378 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1989,6 +1989,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 195b587..7a1deff 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -90,6 +90,9 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  _Exit F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 03f2e83..d23377d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1985,6 +1985,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index 4576fc8..7a4081e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1881,6 +1881,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index a653292..51f8707 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1864,6 +1864,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 9defbdf..46490a7 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1975,6 +1975,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 35987fa..540bc1c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1908,6 +1908,9 @@ GLIBC_2.2.4
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
index caf74b8..a473437 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
@@ -2091,3 +2091,6 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
index 68d975b..16bd028 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
@@ -2091,3 +2091,6 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
index caf74b8..a473437 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
@@ -2091,3 +2091,6 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 914b590..b77feba 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1854,6 +1854,9 @@ GLIBC_2.2.5
 GLIBC_2.2.6
  GLIBC_2.2.6 A
  __nanosleep F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F
 GLIBC_2.3
  GLIBC_2.3 A
  __ctype_b_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 0f64c8d..f638884 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2089,3 +2089,6 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+GLIBC_2.20
+ GLIBC_2.20 A
+ fmemopen F

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-02 12:30 [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance Adhemerval Zanella
@ 2014-07-07 18:01 ` Adhemerval Zanella
  2014-07-14 11:39   ` Adhemerval Zanella
  2014-10-20 23:00 ` Rich Felker
  1 sibling, 1 reply; 13+ messages in thread
From: Adhemerval Zanella @ 2014-07-07 18:01 UTC (permalink / raw)
  To: libc-alpha

ping.

On 02-07-2014 09:29, Adhemerval Zanella wrote:
> Hi,
>
> This is a small update on the previous fmemopen patch I have sent [1].
> the change is basically:
>
> * 'w' mode does not truncate the buffer, only 'w+'
>
> I also rebased against master to adjust NEWS file.
>
> [1] https://sourceware.org/ml/libc-alpha/2014-06/msg00878.html
>
> --
>
> 	[BZ #6544]
> 	[BZ #11216]
> 	[BZ #12836]
> 	[BZ #13151]
> 	[BZ #13152]
> 	[BZ #14292]
> 	* include/stdio.h (fmemopen): Remove hidden prototype.
> 	(__fmemopen): Add new hidden prototype.
> 	* libio/Makefile: Add oldfmemopen object.
> 	* libio/Versions [GLIBC_2.20]: Add new fmemopen symbol.
> 	* libio/fmemopen.c (__fmemopen): Function rewrite to be POSIX
> 	compliance.
> 	* libio/oldfmemopen.c: New file: old fmemopen implementation for
> 	symbol compatibility.
> 	* stdio-common/Makefile [tests]: Add new tst-fmemopen3.
> 	* stdio-common/psiginfo.c [psiginfo]: Call __fmemopen instead of
> 	fmemopen.
> 	* stdio-common/tst-fmemopen3.c: New file: more fmemopen tests, focus
> 	on append and read mode.
> 	* sysdeps/unix/sysv/linux/aarch64/nptl/libc.abilist [GLIBC_2.20]: Add
> 	fmemopen.
> 	* sysdeps/unix/sysv/linux/alpha/libc.abilist [GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/arm/libc.abilist [GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/i386/libc.abilist [GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist [GLIBC_2.20]:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist [GLIBC_2.20]:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/microblaze/nptl/libc.abilist [GLIBC_2.20]:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/fpu/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n32/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/mips/mips64/n64/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist [GLIBC_2.20]:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist [GLIBC_2.20]:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/sh/nptl/libc.abilist [GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> 	[GLIBC_2.20]: Likewise.
> 	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist [GLIBC_2.20]:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist [GLIBC_2.20]:
> 	Likewise.
> 	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist [GLIBC_2.20]:
> 	Likewise.
>
> ---
>
> diff --git a/NEWS b/NEWS
> index a07ea66..7a0851e 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -9,19 +9,20 @@ Version 2.20
>
>  * The following bugs are resolved with this release:
>
> -  6804, 9894, 12994, 13347, 13651, 14308, 14770, 15119, 15132, 15347, 15514,
> -  15698, 15804, 15894, 15946, 16002, 16064, 16095, 16198, 16284, 16287,
> -  16315, 16348, 16349, 16354, 16357, 16362, 16447, 16516, 16532, 16539,
> -  16545, 16561, 16562, 16564, 16574, 16599, 16600, 16609, 16610, 16611,
> -  16613, 16619, 16623, 16629, 16632, 16634, 16639, 16642, 16648, 16649,
> -  16670, 16674, 16677, 16680, 16681, 16683, 16689, 16695, 16701, 16706,
> -  16707, 16712, 16713, 16714, 16724, 16731, 16739, 16740, 16743, 16754,
> -  16758, 16759, 16760, 16770, 16786, 16789, 16791, 16796, 16799, 16800,
> -  16815, 16823, 16824, 16831, 16838, 16849, 16854, 16876, 16877, 16878,
> -  16882, 16885, 16888, 16890, 16912, 16915, 16916, 16917, 16918, 16922,
> -  16927, 16928, 16932, 16943, 16958, 16965, 16966, 16967, 16977, 16978,
> -  16984, 16990, 16996, 17009, 17022, 17031, 17042, 17048, 17050, 17058,
> -  17061, 17062, 17069, 17075, 17079, 17084, 17086, 17092, 17097.
> +  6544, 6804, 9894, 11216, 12836, 12994, 13151, 13152, 13347, 13651, 14292,
> +  14308, 14770, 15119, 15132, 15347, 15514, 15698, 15804, 15894, 15946,
> +  16002, 16064, 16095, 16198, 16284, 16287, 16315, 16348, 16349, 16354,
> +  16357, 16362, 16447, 16516, 16532, 16539, 16545, 16561, 16562, 16564,
> +  16574, 16599, 16600, 16609, 16610, 16611, 16613, 16619, 16623, 16629,
> +  16632, 16634, 16639, 16642, 16648, 16649, 16670, 16674, 16677, 16680,
> +  16681, 16683, 16689, 16695, 16701, 16706, 16707, 16712, 16713, 16714,
> +  16724, 16731, 16739, 16740, 16743, 16754, 16758, 16759, 16760, 16770,
> +  16786, 16789, 16791, 16796, 16799, 16800, 16815, 16823, 16824, 16831,
> +  16838, 16849, 16854, 16876, 16877, 16878, 16882, 16885, 16888, 16890,
> +  16912, 16915, 16916, 16917, 16918, 16922, 16927, 16928, 16932, 16943,
> +  16958, 16965, 16966, 16967, 16977, 16978, 16984, 16990, 16996, 17009,
> +  17022, 17031, 17042, 17048, 17050, 17058, 17061, 17062, 17069, 17075,
> +  17079, 17084, 17086, 17092, 17097.
>
>  * Optimized strchr implementation for AArch64.  Contributed by ARM Ltd.
>
> diff --git a/include/stdio.h b/include/stdio.h
> index 9f2ea31..94ba5a5 100644
> --- a/include/stdio.h
> +++ b/include/stdio.h
> @@ -152,7 +152,6 @@ libc_hidden_proto (fread_unlocked)
>  libc_hidden_proto (fwrite_unlocked)
>  libc_hidden_proto (fgets_unlocked)
>  libc_hidden_proto (fputs_unlocked)
> -libc_hidden_proto (fmemopen)
>  libc_hidden_proto (open_memstream)
>  libc_hidden_proto (__libc_fatal)
>  libc_hidden_proto (__vsprintf_chk)
> @@ -180,6 +179,9 @@ gets (char *__str)
>  }
>  #  endif
>
> +extern FILE * __fmemopen (void *buf, size_t len, const char *mode);
> +libc_hidden_proto (__fmemopen)
> +
>  __END_DECLS
>  # endif
>
> diff --git a/libio/Makefile b/libio/Makefile
> index 56952ce..c76b37e 100644
> --- a/libio/Makefile
> +++ b/libio/Makefile
> @@ -46,7 +46,7 @@ routines	:=							      \
>  	__fbufsize __freading __fwriting __freadable __fwritable __flbf	      \
>  	__fpurge __fpending __fsetlocking				      \
>  									      \
> -	libc_fatal fmemopen
> +	libc_fatal fmemopen oldfmemopen
>
>  tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
>  	tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
> diff --git a/libio/Versions b/libio/Versions
> index 8df89d2..7ffa64d 100644
> --- a/libio/Versions
> +++ b/libio/Versions
> @@ -148,6 +148,10 @@ libc {
>    GLIBC_2.4 {
>      open_wmemstream;
>    }
> +  GLIBC_2.20 {
> +    # f*
> +    fmemopen;
> +  }
>    GLIBC_PRIVATE {
>      # Used by NPTL and librt
>      __libc_fatal;
> diff --git a/libio/fmemopen.c b/libio/fmemopen.c
> index aee2696..53e9d57 100644
> --- a/libio/fmemopen.c
> +++ b/libio/fmemopen.c
> @@ -1,7 +1,6 @@
> -/* Fmemopen implementation.
> -   Copyright (C) 2000-2014 Free Software Foundation, Inc.
> +/* fmemopen implementation.
> +   Copyright (C) 2014 Free Software Foundation, Inc.
>     This file is part of the GNU C Library.
> -   Contributed by Hanno Mueller, kontakt@hanno.de, 2000.
>
>     The GNU C Library is free software; you can redistribute it and/or
>     modify it under the terms of the GNU Lesser General Public
> @@ -17,54 +16,10 @@
>     License along with the GNU C Library; if not, see
>     <http://www.gnu.org/licenses/>.  */
>
> -/*
> - * fmemopen() - "my" version of a string stream
> - * Hanno Mueller, kontakt@hanno.de
> - *
> - *
> - * I needed fmemopen() for an application that I currently work on,
> - * but couldn't find it in libio. The following snippet of code is an
> - * attempt to implement what glibc's documentation describes.
> - *
> - *
> - *
> - * I already see some potential problems:
> - *
> - * - I never used the "original" fmemopen(). I am sure that "my"
> - *   fmemopen() behaves differently than the original version.
> - *
> - * - The documentation doesn't say wether a string stream allows
> - *   seeks. I checked the old fmemopen implementation in glibc's stdio
> - *   directory, wasn't quite able to see what is going on in that
> - *   source, but as far as I understand there was no seek there. For
> - *   my application, I needed fseek() and ftell(), so it's here.
> - *
> - * - "append" mode and fseek(p, SEEK_END) have two different ideas
> - *   about the "end" of the stream.
> - *
> - *   As described in the documentation, when opening the file in
> - *   "append" mode, the position pointer will be set to the first null
> - *   character of the string buffer (yet the buffer may already
> - *   contain more data). For fseek(), the last byte of the buffer is
> - *   used as the end of the stream.
> - *
> - * - It is unclear to me what the documentation tries to say when it
> - *   explains what happens when you use fmemopen with a NULL
> - *   buffer.
> - *
> - *   Quote: "fmemopen [then] allocates an array SIZE bytes long. This
> - *   is really only useful if you are going to write things to the
> - *   buffer and then read them back in again."
> - *
> - *   What does that mean if the original fmemopen() did not allow
> - *   seeking? How do you read what you just wrote without seeking back
> - *   to the beginning of the stream?
> - *
> - * - I think there should be a second version of fmemopen() that does
> - *   not add null characters for each write. (At least in my
> - *   application, I am not actually using strings but binary data and
> - *   so I don't need the stream to add null characters on its own.)
> - */
> +/* fmemopen() from 2.20 and forward works as defined by POSIX.  It also
> +   provides an older symbol, version 2.2.5, that behaves different regarding
> +   SEEK_END (libio/oldfmemopen.c).  */
> +
>
>  #include <errno.h>
>  #include <libio.h>
> @@ -79,25 +34,23 @@
>  typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
>  struct fmemopen_cookie_struct
>  {
> -  char *buffer;
> -  int mybuffer;
> -  int binmode;
> -  size_t size;
> -  _IO_off64_t pos;
> -  size_t maxpos;
> +  char        *buffer;   /* memory buffer.  */
> +  int         mybuffer;  /* own allocated buffer?  */
> +  int         append;    /* buffer openened for append?  */
> +  size_t      size;      /* buffer length in bytes.  */
> +  _IO_off64_t pos;       /* current position at the buffer.  */
> +  size_t      maxpos;    /* max position in buffer.  */
>  };
>
>
>  static ssize_t
>  fmemopen_read (void *cookie, char *b, size_t s)
>  {
> -  fmemopen_cookie_t *c;
> -
> -  c = (fmemopen_cookie_t *) cookie;
> +  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
>
> -  if (c->pos + s > c->size)
> +  if (c->pos + s > c->maxpos)
>      {
> -      if ((size_t) c->pos == c->size)
> +      if ((size_t) c->pos == c->maxpos)
>  	return 0;
>        s = c->size - c->pos;
>      }
> @@ -115,29 +68,28 @@ fmemopen_read (void *cookie, char *b, size_t s)
>  static ssize_t
>  fmemopen_write (void *cookie, const char *b, size_t s)
>  {
> -  fmemopen_cookie_t *c;
> +  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
> +  _IO_off64_t pos = c->append ? c->maxpos : c->pos;
>    int addnullc;
>
> -  c = (fmemopen_cookie_t *) cookie;
> -
> -  addnullc = c->binmode == 0 && (s == 0 || b[s - 1] != '\0');
> +  addnullc = (s == 0 || b[s - 1] != '\0');
>
> -  if (c->pos + s + addnullc > c->size)
> +  if (pos + s + addnullc > c->size)
>      {
> -      if ((size_t) (c->pos + addnullc) == c->size)
> +      if ((size_t) (pos + addnullc) >= c->size)
>  	{
>  	  __set_errno (ENOSPC);
>  	  return 0;
>  	}
> -      s = c->size - c->pos - addnullc;
> +      s = c->size - pos - addnullc;
>      }
>
> -  memcpy (&(c->buffer[c->pos]), b, s);
> +  memcpy (&(c->buffer[pos]), b, s);
>
> -  c->pos += s;
> -  if ((size_t) c->pos > c->maxpos)
> +  pos += s;
> +  if ((size_t) pos > c->maxpos)
>      {
> -      c->maxpos = c->pos;
> +      c->maxpos = pos;
>        if (addnullc)
>  	c->buffer[c->maxpos] = '\0';
>      }
> @@ -150,9 +102,7 @@ static int
>  fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
>  {
>    _IO_off64_t np;
> -  fmemopen_cookie_t *c;
> -
> -  c = (fmemopen_cookie_t *) cookie;
> +  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
>
>    switch (w)
>      {
> @@ -165,7 +115,7 @@ fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
>        break;
>
>      case SEEK_END:
> -      np = (c->binmode ? c->size : c->maxpos) - *p;
> +      np = c->maxpos + *p;
>        break;
>
>      default:
> @@ -184,9 +134,7 @@ fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
>  static int
>  fmemopen_close (void *cookie)
>  {
> -  fmemopen_cookie_t *c;
> -
> -  c = (fmemopen_cookie_t *) cookie;
> +  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
>
>    if (c->mybuffer)
>      free (c->buffer);
> @@ -197,18 +145,11 @@ fmemopen_close (void *cookie)
>
>
>  FILE *
> -fmemopen (void *buf, size_t len, const char *mode)
> +__fmemopen (void *buf, size_t len, const char *mode)
>  {
>    cookie_io_functions_t iof;
>    fmemopen_cookie_t *c;
>
> -  if (__glibc_unlikely (len == 0))
> -    {
> -    einval:
> -      __set_errno (EINVAL);
> -      return NULL;
> -    }
> -
>    c = (fmemopen_cookie_t *) malloc (sizeof (fmemopen_cookie_t));
>    if (c == NULL)
>      return NULL;
> @@ -231,26 +172,38 @@ fmemopen (void *buf, size_t len, const char *mode)
>        if (__glibc_unlikely ((uintptr_t) len > -(uintptr_t) buf))
>  	{
>  	  free (c);
> -	  goto einval;
> +	  __set_errno (EINVAL);
> +	  return NULL;
>  	}
>
>        c->buffer = buf;
>
> -      if (mode[0] == 'w')
> +      /* POSIX states that w+ mode should truncate the buffer.  */
> +      if (mode[0] == 'w' && mode[1] == '+')
>  	c->buffer[0] = '\0';
>
>        c->maxpos = strnlen (c->buffer, len);
>      }
>
> +
> +  /* Mode   |  starting position (cookie::pos) |          size (cookie::size)
> +   * ------ |----------------------------------|-----------------------------
> +   * read   |          beginning of the buffer |                size argument
> +   * write  |          beginning of the buffer |                         zero
> +   * append |    first null or size buffer + 1 |  first null or size argument
> +   */
> +
>    c->size = len;
>
> -  if (mode[0] == 'a')
> +  if (mode[0] == 'r')
> +    c->maxpos = len;
> +
> +  c->append = mode[0] == 'a';
> +  if (c->append)
>      c->pos = c->maxpos;
>    else
>      c->pos = 0;
>
> -  c->binmode = mode[0] != '\0' && mode[1] == 'b';
> -
>    iof.read = fmemopen_read;
>    iof.write = fmemopen_write;
>    iof.seek = fmemopen_seek;
> @@ -258,4 +211,5 @@ fmemopen (void *buf, size_t len, const char *mode)
>
>    return _IO_fopencookie (c, mode, iof);
>  }
> -libc_hidden_def (fmemopen)
> +libc_hidden_def (__fmemopen)
> +versioned_symbol (libc, __fmemopen, fmemopen, GLIBC_2_20);
> diff --git a/libio/oldfmemopen.c b/libio/oldfmemopen.c
> new file mode 100644
> index 0000000..4e85ebe
> --- /dev/null
> +++ b/libio/oldfmemopen.c
> @@ -0,0 +1,265 @@
> +/* Fmemopen implementation.
> +   Copyright (C) 2000-2014 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +   Contributed by Hanno Mueller, kontakt@hanno.de, 2000.
> +
> +   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/>.  */
> +
> +/*
> + * fmemopen() - "my" version of a string stream
> + * Hanno Mueller, kontakt@hanno.de
> + *
> + *
> + * I needed fmemopen() for an application that I currently work on,
> + * but couldn't find it in libio. The following snippet of code is an
> + * attempt to implement what glibc's documentation describes.
> + *
> + *
> + *
> + * I already see some potential problems:
> + *
> + * - I never used the "original" fmemopen(). I am sure that "my"
> + *   fmemopen() behaves differently than the original version.
> + *
> + * - The documentation doesn't say wether a string stream allows
> + *   seeks. I checked the old fmemopen implementation in glibc's stdio
> + *   directory, wasn't quite able to see what is going on in that
> + *   source, but as far as I understand there was no seek there. For
> + *   my application, I needed fseek() and ftell(), so it's here.
> + *
> + * - "append" mode and fseek(p, SEEK_END) have two different ideas
> + *   about the "end" of the stream.
> + *
> + *   As described in the documentation, when opening the file in
> + *   "append" mode, the position pointer will be set to the first null
> + *   character of the string buffer (yet the buffer may already
> + *   contain more data). For fseek(), the last byte of the buffer is
> + *   used as the end of the stream.
> + *
> + * - It is unclear to me what the documentation tries to say when it
> + *   explains what happens when you use fmemopen with a NULL
> + *   buffer.
> + *
> + *   Quote: "fmemopen [then] allocates an array SIZE bytes long. This
> + *   is really only useful if you are going to write things to the
> + *   buffer and then read them back in again."
> + *
> + *   What does that mean if the original fmemopen() did not allow
> + *   seeking? How do you read what you just wrote without seeking back
> + *   to the beginning of the stream?
> + *
> + * - I think there should be a second version of fmemopen() that does
> + *   not add null characters for each write. (At least in my
> + *   application, I am not actually using strings but binary data and
> + *   so I don't need the stream to add null characters on its own.)
> + */
> +
> +#include "libioP.h"
> +
> +#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_20)
> +
> +#include <errno.h>
> +#include <libio.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdint.h>
> +#include <string.h>
> +#include <sys/types.h>
> +
> +
> +typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
> +struct fmemopen_cookie_struct
> +{
> +  char *buffer;
> +  int mybuffer;
> +  int binmode;
> +  size_t size;
> +  _IO_off64_t pos;
> +  size_t maxpos;
> +};
> +
> +
> +static ssize_t
> +fmemopen_read (void *cookie, char *b, size_t s)
> +{
> +  fmemopen_cookie_t *c;
> +
> +  c = (fmemopen_cookie_t *) cookie;
> +
> +  if (c->pos + s > c->size)
> +    {
> +      if ((size_t) c->pos == c->size)
> +	return 0;
> +      s = c->size - c->pos;
> +    }
> +
> +  memcpy (b, &(c->buffer[c->pos]), s);
> +
> +  c->pos += s;
> +  if ((size_t) c->pos > c->maxpos)
> +    c->maxpos = c->pos;
> +
> +  return s;
> +}
> +
> +
> +static ssize_t
> +fmemopen_write (void *cookie, const char *b, size_t s)
> +{
> +  fmemopen_cookie_t *c;
> +  int addnullc;
> +
> +  c = (fmemopen_cookie_t *) cookie;
> +
> +  addnullc = c->binmode == 0 && (s == 0 || b[s - 1] != '\0');
> +
> +  if (c->pos + s + addnullc > c->size)
> +    {
> +      if ((size_t) (c->pos + addnullc) == c->size)
> +	{
> +	  __set_errno (ENOSPC);
> +	  return 0;
> +	}
> +      s = c->size - c->pos - addnullc;
> +    }
> +
> +  memcpy (&(c->buffer[c->pos]), b, s);
> +
> +  c->pos += s;
> +  if ((size_t) c->pos > c->maxpos)
> +    {
> +      c->maxpos = c->pos;
> +      if (addnullc)
> +	c->buffer[c->maxpos] = '\0';
> +    }
> +
> +  return s;
> +}
> +
> +
> +static int
> +fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
> +{
> +  _IO_off64_t np;
> +  fmemopen_cookie_t *c;
> +
> +  c = (fmemopen_cookie_t *) cookie;
> +
> +  switch (w)
> +    {
> +    case SEEK_SET:
> +      np = *p;
> +      break;
> +
> +    case SEEK_CUR:
> +      np = c->pos + *p;
> +      break;
> +
> +    case SEEK_END:
> +      np = (c->binmode ? c->size : c->maxpos) - *p;
> +      break;
> +
> +    default:
> +      return -1;
> +    }
> +
> +  if (np < 0 || (size_t) np > c->size)
> +    return -1;
> +
> +  *p = c->pos = np;
> +
> +  return 0;
> +}
> +
> +
> +static int
> +fmemopen_close (void *cookie)
> +{
> +  fmemopen_cookie_t *c;
> +
> +  c = (fmemopen_cookie_t *) cookie;
> +
> +  if (c->mybuffer)
> +    free (c->buffer);
> +  free (c);
> +
> +  return 0;
> +}
> +
> +
> +FILE *
> +__old_fmemopen (void *buf, size_t len, const char *mode)
> +{
> +  cookie_io_functions_t iof;
> +  fmemopen_cookie_t *c;
> +
> +  if (__glibc_unlikely (len == 0))
> +    {
> +    einval:
> +      __set_errno (EINVAL);
> +      return NULL;
> +    }
> +
> +  c = (fmemopen_cookie_t *) malloc (sizeof (fmemopen_cookie_t));
> +  if (c == NULL)
> +    return NULL;
> +
> +  c->mybuffer = (buf == NULL);
> +
> +  if (c->mybuffer)
> +    {
> +      c->buffer = (char *) malloc (len);
> +      if (c->buffer == NULL)
> +	{
> +	  free (c);
> +	  return NULL;
> +	}
> +      c->buffer[0] = '\0';
> +      c->maxpos = 0;
> +    }
> +  else
> +    {
> +      if (__glibc_unlikely ((uintptr_t) len > -(uintptr_t) buf))
> +	{
> +	  free (c);
> +	  goto einval;
> +	}
> +
> +      c->buffer = buf;
> +
> +      if (mode[0] == 'w')
> +	c->buffer[0] = '\0';
> +
> +      c->maxpos = strnlen (c->buffer, len);
> +    }
> +
> +  c->size = len;
> +
> +  if (mode[0] == 'a')
> +    c->pos = c->maxpos;
> +  else
> +    c->pos = 0;
> +
> +  c->binmode = mode[0] != '\0' && mode[1] == 'b';
> +
> +  iof.read = fmemopen_read;
> +  iof.write = fmemopen_write;
> +  iof.seek = fmemopen_seek;
> +  iof.close = fmemopen_close;
> +
> +  return _IO_fopencookie (c, mode, iof);
> +}
> +compat_symbol (libc, __old_fmemopen, fmemopen, GLIBC_2_2);
> +#endif
> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
> index 5f8e534..5971e65 100644
> --- a/stdio-common/Makefile
> +++ b/stdio-common/Makefile
> @@ -57,7 +57,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
>  	 bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \
>  	 scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \
>  	 bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \
> -	 bug25 tst-printf-round bug26
> +	 bug25 tst-printf-round bug26 tst-fmemopen3
>
>  test-srcs = tst-unbputc tst-printf
>
> diff --git a/stdio-common/psiginfo.c b/stdio-common/psiginfo.c
> index 564d237..62a9671 100644
> --- a/stdio-common/psiginfo.c
> +++ b/stdio-common/psiginfo.c
> @@ -60,7 +60,7 @@ void
>  psiginfo (const siginfo_t *pinfo, const char *s)
>  {
>    char buf[512];
> -  FILE *fp = fmemopen (buf, sizeof (buf), "w");
> +  FILE *fp = __fmemopen (buf, sizeof (buf), "w");
>    if (fp == NULL)
>      {
>        const char *colon;
> diff --git a/stdio-common/tst-fmemopen3.c b/stdio-common/tst-fmemopen3.c
> new file mode 100644
> index 0000000..1ff0920
> --- /dev/null
> +++ b/stdio-common/tst-fmemopen3.c
> @@ -0,0 +1,206 @@
> +/* fmemopen tests for append and read mode.
> +   Copyright (C) 2014 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 <assert.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <sys/types.h>
> +
> +static void
> +print_buffer (const char *s, size_t n)
> +{
> +  size_t i;
> +  for (i=0; i<n; ++i)
> +    printf ("0x%02X (%c), ", s[i], s[i]);
> +}
> +
> +/* This test check append mode initial position (a/a+) based on POSIX defition
> +   (BZ#6544 and BZ#13151).  */
> +static int
> +do_test_write_append (const char *mode)
> +{
> +  char buf[32] = "testing buffer";
> +  char exp[32] = "testing bufferXX";
> +
> +  FILE *fp = fmemopen (buf, sizeof (buf), mode);
> +
> +  fflush (fp);
> +  fprintf (fp, "X");
> +  fseek (fp, 0, SEEK_SET);
> +  fprintf (fp, "X");
> +  fclose (fp);
> +
> +  if (strcmp (buf, exp) != 0)
> +    {
> +      printf ("%s: check failed: %s != %s\n", __FUNCTION__, buf, exp);
> +      return 1;
> +    }
> +
> +  return 0;
> +}
> +
> +/* This test check append mode initial position (a/a+) based on POSIX defition
> +   (BZ#6544 and BZ#13151) for buffer without null byte end.  */
> +static int
> +do_test_write_append_without_null (const char *mode)
> +{
> +  char buf[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
> +  char exp[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
> +
> +  /* If '\0' is not found in buffer, POSIX states that SEEK_SET should be
> +     the size argument.  */
> +  FILE *fp = fmemopen (buf, sizeof (buf) - 2, "a");
> +
> +  fflush (fp);
> +  fputc (0x70, fp);
> +  fseek (fp, 0, SEEK_SET);
> +  fputc (0x70, fp);
> +  fputc (0x70, fp);
> +  fclose (fp);
> +
> +  /* POSIX also states that a write operation on the stream shall not advance
> +     the current buffer size beyond the size given in fmemopen, so the string
> +     should be same.  */
> +  if (memcmp (buf, exp, sizeof (buf)) != 0)
> +    {
> +      printf ("%s: check failed: ", __FUNCTION__);
> +      print_buffer (buf, sizeof (buf));
> +      printf ("!= ");
> +      print_buffer (exp, sizeof (exp));
> +      printf ("\n");
> +      return 1;
> +    }
> +
> +  return 0;
> +}
> +
> +/* This test check for initial position and feek value for fmemopen objects
> +   opened with append mode.  */
> +static int
> +do_test_read_append (void)
> +{
> +  char buf[32] = "testing buffer";
> +  size_t buflen = strlen (buf);
> +  long fpos;
> +
> +  /* POSIX defines for 'a+' the initial position is the first null byte.  */
> +  FILE *fp = fmemopen (buf, sizeof (buf), "a+");
> +
> +  fpos = ftell (fp);
> +  if (fpos != buflen)
> +    {
> +      printf ("%s: ftell|SEEK_SET (fp) %li != strlen (%s) %li\n",
> +	      __FUNCTION__, fpos, buf, buflen);
> +      fclose (fp);
> +      return 1;
> +    }
> +
> +  fseek (fp, 0, SEEK_END);
> +
> +  if (fpos != buflen)
> +    {
> +      printf ("%s: ftell|SEEK_END (fp) %li != strlen (%s) %li\n",
> +	      __FUNCTION__, fpos, buf, buflen);
> +      fclose (fp);
> +      return 1;
> +    }
> +  fclose (fp);
> +
> +  /* Check if attempting to read past the current size, defined as strlen (buf)
> +     yield an EOF.  */
> +  fp = fmemopen (buf, sizeof (buf), "a+");
> +  if (getc(fp) != EOF)
> +    {
> +      printf ("%s: getc(fp) != EOF\n", __FUNCTION__);
> +      fclose (fp);
> +      return -1;
> +    }
> +
> +  fclose (fp);
> +
> +  return 0;
> +}
> +
> +/* This test check for fseek (SEEK_END) using negative offsets (BZ#14292).  The
> +   starting position of descriptor is different base on the opening mode.  */
> +static int
> +do_test_read_seek_neg (const char *mode, const char *expected)
> +{
> +  char buf[] = "abcdefghijklmnopqrstuvxz0123456789";
> +  char tmp[10];
> +  size_t tmps = sizeof (tmps);
> +  long offset = -11;
> +
> +  FILE *fp = fmemopen (buf, sizeof (buf), mode);
> +  fseek (fp, offset, SEEK_END);
> +  fread (tmp, tmps, 1, fp);
> +  
> +  if (memcmp (tmp, expected, tmps) != 0)
> +    {
> +      printf ("%s: fmemopen(%s) - fseek (fp, %li, SEEK_END):\n",
> +	      __FUNCTION__, mode, offset);
> +      printf ("  returned: ");
> +      print_buffer (tmp, tmps);
> +      printf ("\n");
> +      printf ("  expected: ");
> +      print_buffer (expected, tmps);
> +      printf ("\n");
> +      return 1;
> +    }
> +  
> +  fclose (fp);
> +
> +  return 0;
> +}
> +
> +static int
> +do_test_read_seek_negative (void)
> +{
> +  int ret = 0;
> +
> +  /* 'r' and 'w' modes defines the initial position at the buffer start and
> +     seek with SEEK_END shall seek relative to its size give in fmemopen
> +     call.  The expected tmp result is 0 to 9 *without* the ending null  */
> +  ret += do_test_read_seek_neg ("r", "0123456789");
> +  /* 'a+' mode sets the initial position at the first null byte in buffer and
> +    SEEK_END shall seek relative to its size as well.  The expected result is
> +    z012345678, since SEEK_END plus a+ start at '\0', not size.  */
> +  ret += do_test_read_seek_neg ("a+", "z012345678");
> +
> +  return ret;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  int ret = 0;
> +
> +  ret += do_test_write_append ("a");
> +  ret += do_test_write_append_without_null ("a");
> +  ret += do_test_write_append ("a+");
> +  ret += do_test_write_append_without_null ("a+");
> +
> +  ret += do_test_read_append ();
> +
> +  ret += do_test_read_seek_negative ();
> +
> +  return ret;
> +}
> +
> +#define TEST_FUNCTION do_test ()
> +#include "../test-skeleton.c"
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index aeee312..6cf2ddd 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2081,3 +2081,6 @@ GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
>   _mcount F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 980e088..11f03a5 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -1822,6 +1822,9 @@ GLIBC_2.17
>  GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.2
>   GLIBC_2.2 A
>   _IO_adjust_wcolumn F
> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
> index ce45208..0a6ef89 100644
> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
> @@ -89,6 +89,9 @@ GLIBC_2.17
>  GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.4
>   GLIBC_2.4 A
>   _Exit F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 3cb314d..af60934 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2023,6 +2023,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
> index 067552d..afe6f4b 100644
> --- a/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
> @@ -1881,6 +1881,9 @@ GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
>   getunwind F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index f06cc8e..2bc1ce4 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -90,6 +90,9 @@ GLIBC_2.17
>  GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.4
>   GLIBC_2.4 A
>   _Exit F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 9010ea7..48c25b4 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -1979,6 +1979,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> index 6e8d993..8b506ed 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
> @@ -2080,3 +2080,6 @@ GLIBC_2.18
>   xencrypt F
>   xprt_register F
>   xprt_unregister F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 1c3490c..eb7860e 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -1951,6 +1951,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index d8fd823..e4385d2 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -1949,6 +1949,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 3e6ed35..44b4f20 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -1947,6 +1947,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index c7e46aa..2c00ad7 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -1941,6 +1941,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index f27b48b..29b9695 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -1983,6 +1983,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index a54382e..b57f378 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -1989,6 +1989,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> index 195b587..7a1deff 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
> @@ -90,6 +90,9 @@ GLIBC_2.17
>  GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   _Exit F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 03f2e83..d23377d 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -1985,6 +1985,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index 4576fc8..7a4081e 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -1881,6 +1881,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
> index a653292..51f8707 100644
> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
> @@ -1864,6 +1864,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index 9defbdf..46490a7 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -1975,6 +1975,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 35987fa..540bc1c 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -1908,6 +1908,9 @@ GLIBC_2.2.4
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> index caf74b8..a473437 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
> @@ -2091,3 +2091,6 @@ GLIBC_2.17
>  GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> index 68d975b..16bd028 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
> @@ -2091,3 +2091,6 @@ GLIBC_2.17
>  GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
> diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> index caf74b8..a473437 100644
> --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
> @@ -2091,3 +2091,6 @@ GLIBC_2.17
>  GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 914b590..b77feba 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -1854,6 +1854,9 @@ GLIBC_2.2.5
>  GLIBC_2.2.6
>   GLIBC_2.2.6 A
>   __nanosleep F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>  GLIBC_2.3
>   GLIBC_2.3 A
>   __ctype_b_loc F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 0f64c8d..f638884 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2089,3 +2089,6 @@ GLIBC_2.17
>  GLIBC_2.18
>   GLIBC_2.18 A
>   __cxa_thread_atexit_impl F
> +GLIBC_2.20
> + GLIBC_2.20 A
> + fmemopen F
>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-07 18:01 ` Adhemerval Zanella
@ 2014-07-14 11:39   ` Adhemerval Zanella
  2014-07-16 21:20     ` Joseph S. Myers
  0 siblings, 1 reply; 13+ messages in thread
From: Adhemerval Zanella @ 2014-07-14 11:39 UTC (permalink / raw)
  To: libc-alpha

ping.

On 07-07-2014 15:00, Adhemerval Zanella wrote:
> ping.
>
> On 02-07-2014 09:29, Adhemerval Zanella wrote:
>> Hi,
>>
>> This is a small update on the previous fmemopen patch I have sent [1].
>> the change is basically:
>>
>> * 'w' mode does not truncate the buffer, only 'w+'
>>
>> I also rebased against master to adjust NEWS file.
>>
>> [1] https://sourceware.org/ml/libc-alpha/2014-06/msg00878.html
>>
>> --
>>
>> 	[BZ #6544]
>> 	[BZ #11216]
>> 	[BZ #12836]
>> 	[BZ #13151]
>> 	[BZ #13152]
>> 	[BZ #14292]
>> 	* include/stdio.h (fmemopen): Remove hidden prototype.
>> 	(__fmemopen): Add new hidden prototype.
>> 	* libio/Makefile: Add oldfmemopen object.
>> 	* libio/Versions [GLIBC_2.20]: Add new fmemopen symbol.
>> 	* libio/fmemopen.c (__fmemopen): Function rewrite to be POSIX
>> 	compliance.
>> 	* libio/oldfmemopen.c: New file: old fmemopen implementation for
>> 	symbol compatibility.
>> 	* stdio-common/Makefile [tests]: Add new tst-fmemopen3.
>> 	* stdio-common/psiginfo.c [psiginfo]: Call __fmemopen instead of
>> 	fmemopen.
>> 	* stdio-common/tst-fmemopen3.c: New file: more fmemopen tests, focus
>> 	on append and read mode.
>> 	* sysdeps/unix/sysv/linux/aarch64/nptl/libc.abilist [GLIBC_2.20]: Add
>> 	fmemopen.
>> 	* sysdeps/unix/sysv/linux/alpha/libc.abilist [GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/arm/libc.abilist [GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/i386/libc.abilist [GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist [GLIBC_2.20]:
>> 	Likewise.
>> 	* sysdeps/unix/sysv/linux/m68k/coldfire/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/m68k/m680x0/nptl/libc.abilist [GLIBC_2.20]:
>> 	Likewise.
>> 	* sysdeps/unix/sysv/linux/microblaze/nptl/libc.abilist [GLIBC_2.20]:
>> 	Likewise.
>> 	* sysdeps/unix/sysv/linux/mips/mips32/fpu/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/mips/mips64/n32/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/mips/mips64/n64/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/powerpc/powerpc64/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/s390/s390-32/nptl/libc.abilist [GLIBC_2.20]:
>> 	Likewise.
>> 	* sysdeps/unix/sysv/linux/s390/s390-64/nptl/libc.abilist [GLIBC_2.20]:
>> 	Likewise.
>> 	* sysdeps/unix/sysv/linux/sh/nptl/libc.abilist [GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/sparc/sparc32/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/sparc/sparc64/nptl/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
>> 	[GLIBC_2.20]: Likewise.
>> 	* sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist [GLIBC_2.20]:
>> 	Likewise.
>> 	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist [GLIBC_2.20]:
>> 	Likewise.
>> 	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist [GLIBC_2.20]:
>> 	Likewise.
>>
>> ---
>>
>> diff --git a/NEWS b/NEWS
>> index a07ea66..7a0851e 100644
>> --- a/NEWS
>> +++ b/NEWS
>> @@ -9,19 +9,20 @@ Version 2.20
>>
>>  * The following bugs are resolved with this release:
>>
>> -  6804, 9894, 12994, 13347, 13651, 14308, 14770, 15119, 15132, 15347, 15514,
>> -  15698, 15804, 15894, 15946, 16002, 16064, 16095, 16198, 16284, 16287,
>> -  16315, 16348, 16349, 16354, 16357, 16362, 16447, 16516, 16532, 16539,
>> -  16545, 16561, 16562, 16564, 16574, 16599, 16600, 16609, 16610, 16611,
>> -  16613, 16619, 16623, 16629, 16632, 16634, 16639, 16642, 16648, 16649,
>> -  16670, 16674, 16677, 16680, 16681, 16683, 16689, 16695, 16701, 16706,
>> -  16707, 16712, 16713, 16714, 16724, 16731, 16739, 16740, 16743, 16754,
>> -  16758, 16759, 16760, 16770, 16786, 16789, 16791, 16796, 16799, 16800,
>> -  16815, 16823, 16824, 16831, 16838, 16849, 16854, 16876, 16877, 16878,
>> -  16882, 16885, 16888, 16890, 16912, 16915, 16916, 16917, 16918, 16922,
>> -  16927, 16928, 16932, 16943, 16958, 16965, 16966, 16967, 16977, 16978,
>> -  16984, 16990, 16996, 17009, 17022, 17031, 17042, 17048, 17050, 17058,
>> -  17061, 17062, 17069, 17075, 17079, 17084, 17086, 17092, 17097.
>> +  6544, 6804, 9894, 11216, 12836, 12994, 13151, 13152, 13347, 13651, 14292,
>> +  14308, 14770, 15119, 15132, 15347, 15514, 15698, 15804, 15894, 15946,
>> +  16002, 16064, 16095, 16198, 16284, 16287, 16315, 16348, 16349, 16354,
>> +  16357, 16362, 16447, 16516, 16532, 16539, 16545, 16561, 16562, 16564,
>> +  16574, 16599, 16600, 16609, 16610, 16611, 16613, 16619, 16623, 16629,
>> +  16632, 16634, 16639, 16642, 16648, 16649, 16670, 16674, 16677, 16680,
>> +  16681, 16683, 16689, 16695, 16701, 16706, 16707, 16712, 16713, 16714,
>> +  16724, 16731, 16739, 16740, 16743, 16754, 16758, 16759, 16760, 16770,
>> +  16786, 16789, 16791, 16796, 16799, 16800, 16815, 16823, 16824, 16831,
>> +  16838, 16849, 16854, 16876, 16877, 16878, 16882, 16885, 16888, 16890,
>> +  16912, 16915, 16916, 16917, 16918, 16922, 16927, 16928, 16932, 16943,
>> +  16958, 16965, 16966, 16967, 16977, 16978, 16984, 16990, 16996, 17009,
>> +  17022, 17031, 17042, 17048, 17050, 17058, 17061, 17062, 17069, 17075,
>> +  17079, 17084, 17086, 17092, 17097.
>>
>>  * Optimized strchr implementation for AArch64.  Contributed by ARM Ltd.
>>
>> diff --git a/include/stdio.h b/include/stdio.h
>> index 9f2ea31..94ba5a5 100644
>> --- a/include/stdio.h
>> +++ b/include/stdio.h
>> @@ -152,7 +152,6 @@ libc_hidden_proto (fread_unlocked)
>>  libc_hidden_proto (fwrite_unlocked)
>>  libc_hidden_proto (fgets_unlocked)
>>  libc_hidden_proto (fputs_unlocked)
>> -libc_hidden_proto (fmemopen)
>>  libc_hidden_proto (open_memstream)
>>  libc_hidden_proto (__libc_fatal)
>>  libc_hidden_proto (__vsprintf_chk)
>> @@ -180,6 +179,9 @@ gets (char *__str)
>>  }
>>  #  endif
>>
>> +extern FILE * __fmemopen (void *buf, size_t len, const char *mode);
>> +libc_hidden_proto (__fmemopen)
>> +
>>  __END_DECLS
>>  # endif
>>
>> diff --git a/libio/Makefile b/libio/Makefile
>> index 56952ce..c76b37e 100644
>> --- a/libio/Makefile
>> +++ b/libio/Makefile
>> @@ -46,7 +46,7 @@ routines	:=							      \
>>  	__fbufsize __freading __fwriting __freadable __fwritable __flbf	      \
>>  	__fpurge __fpending __fsetlocking				      \
>>  									      \
>> -	libc_fatal fmemopen
>> +	libc_fatal fmemopen oldfmemopen
>>
>>  tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
>>  	tst_wprintf2 tst-widetext test-fmemopen tst-ext tst-ext2 \
>> diff --git a/libio/Versions b/libio/Versions
>> index 8df89d2..7ffa64d 100644
>> --- a/libio/Versions
>> +++ b/libio/Versions
>> @@ -148,6 +148,10 @@ libc {
>>    GLIBC_2.4 {
>>      open_wmemstream;
>>    }
>> +  GLIBC_2.20 {
>> +    # f*
>> +    fmemopen;
>> +  }
>>    GLIBC_PRIVATE {
>>      # Used by NPTL and librt
>>      __libc_fatal;
>> diff --git a/libio/fmemopen.c b/libio/fmemopen.c
>> index aee2696..53e9d57 100644
>> --- a/libio/fmemopen.c
>> +++ b/libio/fmemopen.c
>> @@ -1,7 +1,6 @@
>> -/* Fmemopen implementation.
>> -   Copyright (C) 2000-2014 Free Software Foundation, Inc.
>> +/* fmemopen implementation.
>> +   Copyright (C) 2014 Free Software Foundation, Inc.
>>     This file is part of the GNU C Library.
>> -   Contributed by Hanno Mueller, kontakt@hanno.de, 2000.
>>
>>     The GNU C Library is free software; you can redistribute it and/or
>>     modify it under the terms of the GNU Lesser General Public
>> @@ -17,54 +16,10 @@
>>     License along with the GNU C Library; if not, see
>>     <http://www.gnu.org/licenses/>.  */
>>
>> -/*
>> - * fmemopen() - "my" version of a string stream
>> - * Hanno Mueller, kontakt@hanno.de
>> - *
>> - *
>> - * I needed fmemopen() for an application that I currently work on,
>> - * but couldn't find it in libio. The following snippet of code is an
>> - * attempt to implement what glibc's documentation describes.
>> - *
>> - *
>> - *
>> - * I already see some potential problems:
>> - *
>> - * - I never used the "original" fmemopen(). I am sure that "my"
>> - *   fmemopen() behaves differently than the original version.
>> - *
>> - * - The documentation doesn't say wether a string stream allows
>> - *   seeks. I checked the old fmemopen implementation in glibc's stdio
>> - *   directory, wasn't quite able to see what is going on in that
>> - *   source, but as far as I understand there was no seek there. For
>> - *   my application, I needed fseek() and ftell(), so it's here.
>> - *
>> - * - "append" mode and fseek(p, SEEK_END) have two different ideas
>> - *   about the "end" of the stream.
>> - *
>> - *   As described in the documentation, when opening the file in
>> - *   "append" mode, the position pointer will be set to the first null
>> - *   character of the string buffer (yet the buffer may already
>> - *   contain more data). For fseek(), the last byte of the buffer is
>> - *   used as the end of the stream.
>> - *
>> - * - It is unclear to me what the documentation tries to say when it
>> - *   explains what happens when you use fmemopen with a NULL
>> - *   buffer.
>> - *
>> - *   Quote: "fmemopen [then] allocates an array SIZE bytes long. This
>> - *   is really only useful if you are going to write things to the
>> - *   buffer and then read them back in again."
>> - *
>> - *   What does that mean if the original fmemopen() did not allow
>> - *   seeking? How do you read what you just wrote without seeking back
>> - *   to the beginning of the stream?
>> - *
>> - * - I think there should be a second version of fmemopen() that does
>> - *   not add null characters for each write. (At least in my
>> - *   application, I am not actually using strings but binary data and
>> - *   so I don't need the stream to add null characters on its own.)
>> - */
>> +/* fmemopen() from 2.20 and forward works as defined by POSIX.  It also
>> +   provides an older symbol, version 2.2.5, that behaves different regarding
>> +   SEEK_END (libio/oldfmemopen.c).  */
>> +
>>
>>  #include <errno.h>
>>  #include <libio.h>
>> @@ -79,25 +34,23 @@
>>  typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
>>  struct fmemopen_cookie_struct
>>  {
>> -  char *buffer;
>> -  int mybuffer;
>> -  int binmode;
>> -  size_t size;
>> -  _IO_off64_t pos;
>> -  size_t maxpos;
>> +  char        *buffer;   /* memory buffer.  */
>> +  int         mybuffer;  /* own allocated buffer?  */
>> +  int         append;    /* buffer openened for append?  */
>> +  size_t      size;      /* buffer length in bytes.  */
>> +  _IO_off64_t pos;       /* current position at the buffer.  */
>> +  size_t      maxpos;    /* max position in buffer.  */
>>  };
>>
>>
>>  static ssize_t
>>  fmemopen_read (void *cookie, char *b, size_t s)
>>  {
>> -  fmemopen_cookie_t *c;
>> -
>> -  c = (fmemopen_cookie_t *) cookie;
>> +  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
>>
>> -  if (c->pos + s > c->size)
>> +  if (c->pos + s > c->maxpos)
>>      {
>> -      if ((size_t) c->pos == c->size)
>> +      if ((size_t) c->pos == c->maxpos)
>>  	return 0;
>>        s = c->size - c->pos;
>>      }
>> @@ -115,29 +68,28 @@ fmemopen_read (void *cookie, char *b, size_t s)
>>  static ssize_t
>>  fmemopen_write (void *cookie, const char *b, size_t s)
>>  {
>> -  fmemopen_cookie_t *c;
>> +  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
>> +  _IO_off64_t pos = c->append ? c->maxpos : c->pos;
>>    int addnullc;
>>
>> -  c = (fmemopen_cookie_t *) cookie;
>> -
>> -  addnullc = c->binmode == 0 && (s == 0 || b[s - 1] != '\0');
>> +  addnullc = (s == 0 || b[s - 1] != '\0');
>>
>> -  if (c->pos + s + addnullc > c->size)
>> +  if (pos + s + addnullc > c->size)
>>      {
>> -      if ((size_t) (c->pos + addnullc) == c->size)
>> +      if ((size_t) (pos + addnullc) >= c->size)
>>  	{
>>  	  __set_errno (ENOSPC);
>>  	  return 0;
>>  	}
>> -      s = c->size - c->pos - addnullc;
>> +      s = c->size - pos - addnullc;
>>      }
>>
>> -  memcpy (&(c->buffer[c->pos]), b, s);
>> +  memcpy (&(c->buffer[pos]), b, s);
>>
>> -  c->pos += s;
>> -  if ((size_t) c->pos > c->maxpos)
>> +  pos += s;
>> +  if ((size_t) pos > c->maxpos)
>>      {
>> -      c->maxpos = c->pos;
>> +      c->maxpos = pos;
>>        if (addnullc)
>>  	c->buffer[c->maxpos] = '\0';
>>      }
>> @@ -150,9 +102,7 @@ static int
>>  fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
>>  {
>>    _IO_off64_t np;
>> -  fmemopen_cookie_t *c;
>> -
>> -  c = (fmemopen_cookie_t *) cookie;
>> +  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
>>
>>    switch (w)
>>      {
>> @@ -165,7 +115,7 @@ fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
>>        break;
>>
>>      case SEEK_END:
>> -      np = (c->binmode ? c->size : c->maxpos) - *p;
>> +      np = c->maxpos + *p;
>>        break;
>>
>>      default:
>> @@ -184,9 +134,7 @@ fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
>>  static int
>>  fmemopen_close (void *cookie)
>>  {
>> -  fmemopen_cookie_t *c;
>> -
>> -  c = (fmemopen_cookie_t *) cookie;
>> +  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;
>>
>>    if (c->mybuffer)
>>      free (c->buffer);
>> @@ -197,18 +145,11 @@ fmemopen_close (void *cookie)
>>
>>
>>  FILE *
>> -fmemopen (void *buf, size_t len, const char *mode)
>> +__fmemopen (void *buf, size_t len, const char *mode)
>>  {
>>    cookie_io_functions_t iof;
>>    fmemopen_cookie_t *c;
>>
>> -  if (__glibc_unlikely (len == 0))
>> -    {
>> -    einval:
>> -      __set_errno (EINVAL);
>> -      return NULL;
>> -    }
>> -
>>    c = (fmemopen_cookie_t *) malloc (sizeof (fmemopen_cookie_t));
>>    if (c == NULL)
>>      return NULL;
>> @@ -231,26 +172,38 @@ fmemopen (void *buf, size_t len, const char *mode)
>>        if (__glibc_unlikely ((uintptr_t) len > -(uintptr_t) buf))
>>  	{
>>  	  free (c);
>> -	  goto einval;
>> +	  __set_errno (EINVAL);
>> +	  return NULL;
>>  	}
>>
>>        c->buffer = buf;
>>
>> -      if (mode[0] == 'w')
>> +      /* POSIX states that w+ mode should truncate the buffer.  */
>> +      if (mode[0] == 'w' && mode[1] == '+')
>>  	c->buffer[0] = '\0';
>>
>>        c->maxpos = strnlen (c->buffer, len);
>>      }
>>
>> +
>> +  /* Mode   |  starting position (cookie::pos) |          size (cookie::size)
>> +   * ------ |----------------------------------|-----------------------------
>> +   * read   |          beginning of the buffer |                size argument
>> +   * write  |          beginning of the buffer |                         zero
>> +   * append |    first null or size buffer + 1 |  first null or size argument
>> +   */
>> +
>>    c->size = len;
>>
>> -  if (mode[0] == 'a')
>> +  if (mode[0] == 'r')
>> +    c->maxpos = len;
>> +
>> +  c->append = mode[0] == 'a';
>> +  if (c->append)
>>      c->pos = c->maxpos;
>>    else
>>      c->pos = 0;
>>
>> -  c->binmode = mode[0] != '\0' && mode[1] == 'b';
>> -
>>    iof.read = fmemopen_read;
>>    iof.write = fmemopen_write;
>>    iof.seek = fmemopen_seek;
>> @@ -258,4 +211,5 @@ fmemopen (void *buf, size_t len, const char *mode)
>>
>>    return _IO_fopencookie (c, mode, iof);
>>  }
>> -libc_hidden_def (fmemopen)
>> +libc_hidden_def (__fmemopen)
>> +versioned_symbol (libc, __fmemopen, fmemopen, GLIBC_2_20);
>> diff --git a/libio/oldfmemopen.c b/libio/oldfmemopen.c
>> new file mode 100644
>> index 0000000..4e85ebe
>> --- /dev/null
>> +++ b/libio/oldfmemopen.c
>> @@ -0,0 +1,265 @@
>> +/* Fmemopen implementation.
>> +   Copyright (C) 2000-2014 Free Software Foundation, Inc.
>> +   This file is part of the GNU C Library.
>> +   Contributed by Hanno Mueller, kontakt@hanno.de, 2000.
>> +
>> +   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/>.  */
>> +
>> +/*
>> + * fmemopen() - "my" version of a string stream
>> + * Hanno Mueller, kontakt@hanno.de
>> + *
>> + *
>> + * I needed fmemopen() for an application that I currently work on,
>> + * but couldn't find it in libio. The following snippet of code is an
>> + * attempt to implement what glibc's documentation describes.
>> + *
>> + *
>> + *
>> + * I already see some potential problems:
>> + *
>> + * - I never used the "original" fmemopen(). I am sure that "my"
>> + *   fmemopen() behaves differently than the original version.
>> + *
>> + * - The documentation doesn't say wether a string stream allows
>> + *   seeks. I checked the old fmemopen implementation in glibc's stdio
>> + *   directory, wasn't quite able to see what is going on in that
>> + *   source, but as far as I understand there was no seek there. For
>> + *   my application, I needed fseek() and ftell(), so it's here.
>> + *
>> + * - "append" mode and fseek(p, SEEK_END) have two different ideas
>> + *   about the "end" of the stream.
>> + *
>> + *   As described in the documentation, when opening the file in
>> + *   "append" mode, the position pointer will be set to the first null
>> + *   character of the string buffer (yet the buffer may already
>> + *   contain more data). For fseek(), the last byte of the buffer is
>> + *   used as the end of the stream.
>> + *
>> + * - It is unclear to me what the documentation tries to say when it
>> + *   explains what happens when you use fmemopen with a NULL
>> + *   buffer.
>> + *
>> + *   Quote: "fmemopen [then] allocates an array SIZE bytes long. This
>> + *   is really only useful if you are going to write things to the
>> + *   buffer and then read them back in again."
>> + *
>> + *   What does that mean if the original fmemopen() did not allow
>> + *   seeking? How do you read what you just wrote without seeking back
>> + *   to the beginning of the stream?
>> + *
>> + * - I think there should be a second version of fmemopen() that does
>> + *   not add null characters for each write. (At least in my
>> + *   application, I am not actually using strings but binary data and
>> + *   so I don't need the stream to add null characters on its own.)
>> + */
>> +
>> +#include "libioP.h"
>> +
>> +#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_20)
>> +
>> +#include <errno.h>
>> +#include <libio.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <stdint.h>
>> +#include <string.h>
>> +#include <sys/types.h>
>> +
>> +
>> +typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
>> +struct fmemopen_cookie_struct
>> +{
>> +  char *buffer;
>> +  int mybuffer;
>> +  int binmode;
>> +  size_t size;
>> +  _IO_off64_t pos;
>> +  size_t maxpos;
>> +};
>> +
>> +
>> +static ssize_t
>> +fmemopen_read (void *cookie, char *b, size_t s)
>> +{
>> +  fmemopen_cookie_t *c;
>> +
>> +  c = (fmemopen_cookie_t *) cookie;
>> +
>> +  if (c->pos + s > c->size)
>> +    {
>> +      if ((size_t) c->pos == c->size)
>> +	return 0;
>> +      s = c->size - c->pos;
>> +    }
>> +
>> +  memcpy (b, &(c->buffer[c->pos]), s);
>> +
>> +  c->pos += s;
>> +  if ((size_t) c->pos > c->maxpos)
>> +    c->maxpos = c->pos;
>> +
>> +  return s;
>> +}
>> +
>> +
>> +static ssize_t
>> +fmemopen_write (void *cookie, const char *b, size_t s)
>> +{
>> +  fmemopen_cookie_t *c;
>> +  int addnullc;
>> +
>> +  c = (fmemopen_cookie_t *) cookie;
>> +
>> +  addnullc = c->binmode == 0 && (s == 0 || b[s - 1] != '\0');
>> +
>> +  if (c->pos + s + addnullc > c->size)
>> +    {
>> +      if ((size_t) (c->pos + addnullc) == c->size)
>> +	{
>> +	  __set_errno (ENOSPC);
>> +	  return 0;
>> +	}
>> +      s = c->size - c->pos - addnullc;
>> +    }
>> +
>> +  memcpy (&(c->buffer[c->pos]), b, s);
>> +
>> +  c->pos += s;
>> +  if ((size_t) c->pos > c->maxpos)
>> +    {
>> +      c->maxpos = c->pos;
>> +      if (addnullc)
>> +	c->buffer[c->maxpos] = '\0';
>> +    }
>> +
>> +  return s;
>> +}
>> +
>> +
>> +static int
>> +fmemopen_seek (void *cookie, _IO_off64_t *p, int w)
>> +{
>> +  _IO_off64_t np;
>> +  fmemopen_cookie_t *c;
>> +
>> +  c = (fmemopen_cookie_t *) cookie;
>> +
>> +  switch (w)
>> +    {
>> +    case SEEK_SET:
>> +      np = *p;
>> +      break;
>> +
>> +    case SEEK_CUR:
>> +      np = c->pos + *p;
>> +      break;
>> +
>> +    case SEEK_END:
>> +      np = (c->binmode ? c->size : c->maxpos) - *p;
>> +      break;
>> +
>> +    default:
>> +      return -1;
>> +    }
>> +
>> +  if (np < 0 || (size_t) np > c->size)
>> +    return -1;
>> +
>> +  *p = c->pos = np;
>> +
>> +  return 0;
>> +}
>> +
>> +
>> +static int
>> +fmemopen_close (void *cookie)
>> +{
>> +  fmemopen_cookie_t *c;
>> +
>> +  c = (fmemopen_cookie_t *) cookie;
>> +
>> +  if (c->mybuffer)
>> +    free (c->buffer);
>> +  free (c);
>> +
>> +  return 0;
>> +}
>> +
>> +
>> +FILE *
>> +__old_fmemopen (void *buf, size_t len, const char *mode)
>> +{
>> +  cookie_io_functions_t iof;
>> +  fmemopen_cookie_t *c;
>> +
>> +  if (__glibc_unlikely (len == 0))
>> +    {
>> +    einval:
>> +      __set_errno (EINVAL);
>> +      return NULL;
>> +    }
>> +
>> +  c = (fmemopen_cookie_t *) malloc (sizeof (fmemopen_cookie_t));
>> +  if (c == NULL)
>> +    return NULL;
>> +
>> +  c->mybuffer = (buf == NULL);
>> +
>> +  if (c->mybuffer)
>> +    {
>> +      c->buffer = (char *) malloc (len);
>> +      if (c->buffer == NULL)
>> +	{
>> +	  free (c);
>> +	  return NULL;
>> +	}
>> +      c->buffer[0] = '\0';
>> +      c->maxpos = 0;
>> +    }
>> +  else
>> +    {
>> +      if (__glibc_unlikely ((uintptr_t) len > -(uintptr_t) buf))
>> +	{
>> +	  free (c);
>> +	  goto einval;
>> +	}
>> +
>> +      c->buffer = buf;
>> +
>> +      if (mode[0] == 'w')
>> +	c->buffer[0] = '\0';
>> +
>> +      c->maxpos = strnlen (c->buffer, len);
>> +    }
>> +
>> +  c->size = len;
>> +
>> +  if (mode[0] == 'a')
>> +    c->pos = c->maxpos;
>> +  else
>> +    c->pos = 0;
>> +
>> +  c->binmode = mode[0] != '\0' && mode[1] == 'b';
>> +
>> +  iof.read = fmemopen_read;
>> +  iof.write = fmemopen_write;
>> +  iof.seek = fmemopen_seek;
>> +  iof.close = fmemopen_close;
>> +
>> +  return _IO_fopencookie (c, mode, iof);
>> +}
>> +compat_symbol (libc, __old_fmemopen, fmemopen, GLIBC_2_2);
>> +#endif
>> diff --git a/stdio-common/Makefile b/stdio-common/Makefile
>> index 5f8e534..5971e65 100644
>> --- a/stdio-common/Makefile
>> +++ b/stdio-common/Makefile
>> @@ -57,7 +57,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \
>>  	 bug19 bug19a tst-popen2 scanf13 scanf14 scanf15 bug20 bug21 bug22 \
>>  	 scanf16 scanf17 tst-setvbuf1 tst-grouping bug23 bug24 \
>>  	 bug-vfprintf-nargs tst-long-dbl-fphex tst-fphex-wide tst-sprintf3 \
>> -	 bug25 tst-printf-round bug26
>> +	 bug25 tst-printf-round bug26 tst-fmemopen3
>>
>>  test-srcs = tst-unbputc tst-printf
>>
>> diff --git a/stdio-common/psiginfo.c b/stdio-common/psiginfo.c
>> index 564d237..62a9671 100644
>> --- a/stdio-common/psiginfo.c
>> +++ b/stdio-common/psiginfo.c
>> @@ -60,7 +60,7 @@ void
>>  psiginfo (const siginfo_t *pinfo, const char *s)
>>  {
>>    char buf[512];
>> -  FILE *fp = fmemopen (buf, sizeof (buf), "w");
>> +  FILE *fp = __fmemopen (buf, sizeof (buf), "w");
>>    if (fp == NULL)
>>      {
>>        const char *colon;
>> diff --git a/stdio-common/tst-fmemopen3.c b/stdio-common/tst-fmemopen3.c
>> new file mode 100644
>> index 0000000..1ff0920
>> --- /dev/null
>> +++ b/stdio-common/tst-fmemopen3.c
>> @@ -0,0 +1,206 @@
>> +/* fmemopen tests for append and read mode.
>> +   Copyright (C) 2014 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 <assert.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <sys/types.h>
>> +
>> +static void
>> +print_buffer (const char *s, size_t n)
>> +{
>> +  size_t i;
>> +  for (i=0; i<n; ++i)
>> +    printf ("0x%02X (%c), ", s[i], s[i]);
>> +}
>> +
>> +/* This test check append mode initial position (a/a+) based on POSIX defition
>> +   (BZ#6544 and BZ#13151).  */
>> +static int
>> +do_test_write_append (const char *mode)
>> +{
>> +  char buf[32] = "testing buffer";
>> +  char exp[32] = "testing bufferXX";
>> +
>> +  FILE *fp = fmemopen (buf, sizeof (buf), mode);
>> +
>> +  fflush (fp);
>> +  fprintf (fp, "X");
>> +  fseek (fp, 0, SEEK_SET);
>> +  fprintf (fp, "X");
>> +  fclose (fp);
>> +
>> +  if (strcmp (buf, exp) != 0)
>> +    {
>> +      printf ("%s: check failed: %s != %s\n", __FUNCTION__, buf, exp);
>> +      return 1;
>> +    }
>> +
>> +  return 0;
>> +}
>> +
>> +/* This test check append mode initial position (a/a+) based on POSIX defition
>> +   (BZ#6544 and BZ#13151) for buffer without null byte end.  */
>> +static int
>> +do_test_write_append_without_null (const char *mode)
>> +{
>> +  char buf[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
>> +  char exp[] = { 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 };
>> +
>> +  /* If '\0' is not found in buffer, POSIX states that SEEK_SET should be
>> +     the size argument.  */
>> +  FILE *fp = fmemopen (buf, sizeof (buf) - 2, "a");
>> +
>> +  fflush (fp);
>> +  fputc (0x70, fp);
>> +  fseek (fp, 0, SEEK_SET);
>> +  fputc (0x70, fp);
>> +  fputc (0x70, fp);
>> +  fclose (fp);
>> +
>> +  /* POSIX also states that a write operation on the stream shall not advance
>> +     the current buffer size beyond the size given in fmemopen, so the string
>> +     should be same.  */
>> +  if (memcmp (buf, exp, sizeof (buf)) != 0)
>> +    {
>> +      printf ("%s: check failed: ", __FUNCTION__);
>> +      print_buffer (buf, sizeof (buf));
>> +      printf ("!= ");
>> +      print_buffer (exp, sizeof (exp));
>> +      printf ("\n");
>> +      return 1;
>> +    }
>> +
>> +  return 0;
>> +}
>> +
>> +/* This test check for initial position and feek value for fmemopen objects
>> +   opened with append mode.  */
>> +static int
>> +do_test_read_append (void)
>> +{
>> +  char buf[32] = "testing buffer";
>> +  size_t buflen = strlen (buf);
>> +  long fpos;
>> +
>> +  /* POSIX defines for 'a+' the initial position is the first null byte.  */
>> +  FILE *fp = fmemopen (buf, sizeof (buf), "a+");
>> +
>> +  fpos = ftell (fp);
>> +  if (fpos != buflen)
>> +    {
>> +      printf ("%s: ftell|SEEK_SET (fp) %li != strlen (%s) %li\n",
>> +	      __FUNCTION__, fpos, buf, buflen);
>> +      fclose (fp);
>> +      return 1;
>> +    }
>> +
>> +  fseek (fp, 0, SEEK_END);
>> +
>> +  if (fpos != buflen)
>> +    {
>> +      printf ("%s: ftell|SEEK_END (fp) %li != strlen (%s) %li\n",
>> +	      __FUNCTION__, fpos, buf, buflen);
>> +      fclose (fp);
>> +      return 1;
>> +    }
>> +  fclose (fp);
>> +
>> +  /* Check if attempting to read past the current size, defined as strlen (buf)
>> +     yield an EOF.  */
>> +  fp = fmemopen (buf, sizeof (buf), "a+");
>> +  if (getc(fp) != EOF)
>> +    {
>> +      printf ("%s: getc(fp) != EOF\n", __FUNCTION__);
>> +      fclose (fp);
>> +      return -1;
>> +    }
>> +
>> +  fclose (fp);
>> +
>> +  return 0;
>> +}
>> +
>> +/* This test check for fseek (SEEK_END) using negative offsets (BZ#14292).  The
>> +   starting position of descriptor is different base on the opening mode.  */
>> +static int
>> +do_test_read_seek_neg (const char *mode, const char *expected)
>> +{
>> +  char buf[] = "abcdefghijklmnopqrstuvxz0123456789";
>> +  char tmp[10];
>> +  size_t tmps = sizeof (tmps);
>> +  long offset = -11;
>> +
>> +  FILE *fp = fmemopen (buf, sizeof (buf), mode);
>> +  fseek (fp, offset, SEEK_END);
>> +  fread (tmp, tmps, 1, fp);
>> +  
>> +  if (memcmp (tmp, expected, tmps) != 0)
>> +    {
>> +      printf ("%s: fmemopen(%s) - fseek (fp, %li, SEEK_END):\n",
>> +	      __FUNCTION__, mode, offset);
>> +      printf ("  returned: ");
>> +      print_buffer (tmp, tmps);
>> +      printf ("\n");
>> +      printf ("  expected: ");
>> +      print_buffer (expected, tmps);
>> +      printf ("\n");
>> +      return 1;
>> +    }
>> +  
>> +  fclose (fp);
>> +
>> +  return 0;
>> +}
>> +
>> +static int
>> +do_test_read_seek_negative (void)
>> +{
>> +  int ret = 0;
>> +
>> +  /* 'r' and 'w' modes defines the initial position at the buffer start and
>> +     seek with SEEK_END shall seek relative to its size give in fmemopen
>> +     call.  The expected tmp result is 0 to 9 *without* the ending null  */
>> +  ret += do_test_read_seek_neg ("r", "0123456789");
>> +  /* 'a+' mode sets the initial position at the first null byte in buffer and
>> +    SEEK_END shall seek relative to its size as well.  The expected result is
>> +    z012345678, since SEEK_END plus a+ start at '\0', not size.  */
>> +  ret += do_test_read_seek_neg ("a+", "z012345678");
>> +
>> +  return ret;
>> +}
>> +
>> +static int
>> +do_test (void)
>> +{
>> +  int ret = 0;
>> +
>> +  ret += do_test_write_append ("a");
>> +  ret += do_test_write_append_without_null ("a");
>> +  ret += do_test_write_append ("a+");
>> +  ret += do_test_write_append_without_null ("a+");
>> +
>> +  ret += do_test_read_append ();
>> +
>> +  ret += do_test_read_seek_negative ();
>> +
>> +  return ret;
>> +}
>> +
>> +#define TEST_FUNCTION do_test ()
>> +#include "../test-skeleton.c"
>> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> index aeee312..6cf2ddd 100644
>> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
>> @@ -2081,3 +2081,6 @@ GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>>   _mcount F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> index 980e088..11f03a5 100644
>> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
>> @@ -1822,6 +1822,9 @@ GLIBC_2.17
>>  GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.2
>>   GLIBC_2.2 A
>>   _IO_adjust_wcolumn F
>> diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
>> index ce45208..0a6ef89 100644
>> --- a/sysdeps/unix/sysv/linux/arm/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
>> @@ -89,6 +89,9 @@ GLIBC_2.17
>>  GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.4
>>   GLIBC_2.4 A
>>   _Exit F
>> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
>> index 3cb314d..af60934 100644
>> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
>> @@ -2023,6 +2023,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist b/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
>> index 067552d..afe6f4b 100644
>> --- a/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/ia64/nptl/libc.abilist
>> @@ -1881,6 +1881,9 @@ GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>>   getunwind F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> index f06cc8e..2bc1ce4 100644
>> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
>> @@ -90,6 +90,9 @@ GLIBC_2.17
>>  GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.4
>>   GLIBC_2.4 A
>>   _Exit F
>> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> index 9010ea7..48c25b4 100644
>> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
>> @@ -1979,6 +1979,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
>> index 6e8d993..8b506ed 100644
>> --- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
>> @@ -2080,3 +2080,6 @@ GLIBC_2.18
>>   xencrypt F
>>   xprt_register F
>>   xprt_unregister F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> index 1c3490c..eb7860e 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
>> @@ -1951,6 +1951,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> index d8fd823..e4385d2 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
>> @@ -1949,6 +1949,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> index 3e6ed35..44b4f20 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
>> @@ -1947,6 +1947,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> index c7e46aa..2c00ad7 100644
>> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
>> @@ -1941,6 +1941,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> index f27b48b..29b9695 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
>> @@ -1983,6 +1983,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> index a54382e..b57f378 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
>> @@ -1989,6 +1989,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
>> index 195b587..7a1deff 100644
>> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
>> @@ -90,6 +90,9 @@ GLIBC_2.17
>>  GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   _Exit F
>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> index 03f2e83..d23377d 100644
>> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
>> @@ -1985,6 +1985,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> index 4576fc8..7a4081e 100644
>> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
>> @@ -1881,6 +1881,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
>> index a653292..51f8707 100644
>> --- a/sysdeps/unix/sysv/linux/sh/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
>> @@ -1864,6 +1864,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> index 9defbdf..46490a7 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
>> @@ -1975,6 +1975,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> index 35987fa..540bc1c 100644
>> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
>> @@ -1908,6 +1908,9 @@ GLIBC_2.2.4
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
>> index caf74b8..a473437 100644
>> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libc.abilist
>> @@ -2091,3 +2091,6 @@ GLIBC_2.17
>>  GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>> diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
>> index 68d975b..16bd028 100644
>> --- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libc.abilist
>> @@ -2091,3 +2091,6 @@ GLIBC_2.17
>>  GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>> diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
>> index caf74b8..a473437 100644
>> --- a/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/tile/tilepro/libc.abilist
>> @@ -2091,3 +2091,6 @@ GLIBC_2.17
>>  GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> index 914b590..b77feba 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
>> @@ -1854,6 +1854,9 @@ GLIBC_2.2.5
>>  GLIBC_2.2.6
>>   GLIBC_2.2.6 A
>>   __nanosleep F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>  GLIBC_2.3
>>   GLIBC_2.3 A
>>   __ctype_b_loc F
>> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> index 0f64c8d..f638884 100644
>> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
>> @@ -2089,3 +2089,6 @@ GLIBC_2.17
>>  GLIBC_2.18
>>   GLIBC_2.18 A
>>   __cxa_thread_atexit_impl F
>> +GLIBC_2.20
>> + GLIBC_2.20 A
>> + fmemopen F
>>
>>
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-14 11:39   ` Adhemerval Zanella
@ 2014-07-16 21:20     ` Joseph S. Myers
  2014-07-17 18:49       ` Adhemerval Zanella
  0 siblings, 1 reply; 13+ messages in thread
From: Joseph S. Myers @ 2014-07-16 21:20 UTC (permalink / raw)
  To: Adhemerval Zanella; +Cc: libc-alpha

This patch looks like it needs updating for hppa now having its own 
libc.abilist.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-16 21:20     ` Joseph S. Myers
@ 2014-07-17 18:49       ` Adhemerval Zanella
  2014-07-22 12:59         ` Adhemerval Zanella
  0 siblings, 1 reply; 13+ messages in thread
From: Adhemerval Zanella @ 2014-07-17 18:49 UTC (permalink / raw)
  To: libc-alpha

On 16-07-2014 18:20, Joseph S. Myers wrote:
> This patch looks like it needs updating for hppa now having its own 
> libc.abilist.
>
Thanks, I though I have covered all abi files. What about the implementation itself?

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-17 18:49       ` Adhemerval Zanella
@ 2014-07-22 12:59         ` Adhemerval Zanella
  2014-07-28 12:05           ` Adhemerval Zanella
  0 siblings, 1 reply; 13+ messages in thread
From: Adhemerval Zanella @ 2014-07-22 12:59 UTC (permalink / raw)
  To: libc-alpha

On 17-07-2014 15:49, Adhemerval Zanella wrote:
> On 16-07-2014 18:20, Joseph S. Myers wrote:
>> This patch looks like it needs updating for hppa now having its own 
>> libc.abilist.
>>
> Thanks, I though I have covered all abi files. What about the implementation itself?
>
Ping about patch contents.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-22 12:59         ` Adhemerval Zanella
@ 2014-07-28 12:05           ` Adhemerval Zanella
  2014-07-30  3:56             ` Carlos O'Donell
  0 siblings, 1 reply; 13+ messages in thread
From: Adhemerval Zanella @ 2014-07-28 12:05 UTC (permalink / raw)
  To: libc-alpha

On 22-07-2014 09:59, Adhemerval Zanella wrote:
> On 17-07-2014 15:49, Adhemerval Zanella wrote:
>> On 16-07-2014 18:20, Joseph S. Myers wrote:
>>> This patch looks like it needs updating for hppa now having its own 
>>> libc.abilist.
>>>
>> Thanks, I though I have covered all abi files. What about the implementation itself?
>>
> Ping about patch contents.
>
Ping.  I have update my branch azanella/fmemopen.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-28 12:05           ` Adhemerval Zanella
@ 2014-07-30  3:56             ` Carlos O'Donell
  2014-07-30 11:52               ` Adhemerval Zanella
  0 siblings, 1 reply; 13+ messages in thread
From: Carlos O'Donell @ 2014-07-30  3:56 UTC (permalink / raw)
  To: Adhemerval Zanella, libc-alpha, Siddhesh Poyarekar, Joseph S. Myers

On 07/28/2014 08:05 AM, Adhemerval Zanella wrote:
> On 22-07-2014 09:59, Adhemerval Zanella wrote:
>> On 17-07-2014 15:49, Adhemerval Zanella wrote:
>>> On 16-07-2014 18:20, Joseph S. Myers wrote:
>>>> This patch looks like it needs updating for hppa now having its own 
>>>> libc.abilist.
>>>>
>>> Thanks, I though I have covered all abi files. What about the implementation itself?
>>>
>> Ping about patch contents.
>>
> Ping.  I have update my branch azanella/fmemopen.
> 

I started reviewing this and IMO it's going to take
more time than we have during the freeze.

I see no strong or compelling argument to put it
into 2.20.

If it went into 2.21 we could test it in rawhide and
make sure nothing else was broken.

If I've learned anything from Siddhesh's changes
in the libio code it's that nothing is as easy as
you think and distribution testing is critical
to finding issues.

My strong recommendation is that this get deferred
until 2.21.

Unless you have done distribution testing already?

Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-30  3:56             ` Carlos O'Donell
@ 2014-07-30 11:52               ` Adhemerval Zanella
  2014-09-10 14:13                 ` Adhemerval Zanella
  0 siblings, 1 reply; 13+ messages in thread
From: Adhemerval Zanella @ 2014-07-30 11:52 UTC (permalink / raw)
  To: libc-alpha

On 30-07-2014 00:56, Carlos O'Donell wrote:
> On 07/28/2014 08:05 AM, Adhemerval Zanella wrote:
>> On 22-07-2014 09:59, Adhemerval Zanella wrote:
>>> On 17-07-2014 15:49, Adhemerval Zanella wrote:
>>>> On 16-07-2014 18:20, Joseph S. Myers wrote:
>>>>> This patch looks like it needs updating for hppa now having its own 
>>>>> libc.abilist.
>>>>>
>>>> Thanks, I though I have covered all abi files. What about the implementation itself?
>>>>
>>> Ping about patch contents.
>>>
>> Ping.  I have update my branch azanella/fmemopen.
>>
> I started reviewing this and IMO it's going to take
> more time than we have during the freeze.
>
> I see no strong or compelling argument to put it
> into 2.20.
>
> If it went into 2.21 we could test it in rawhide and
> make sure nothing else was broken.
>
> If I've learned anything from Siddhesh's changes
> in the libio code it's that nothing is as easy as
> you think and distribution testing is critical
> to finding issues.
>
> My strong recommendation is that this get deferred
> until 2.21.
>
> Unless you have done distribution testing already?

I have not and it is no problem to move it to 2.21.  I just a pity we 
can't add it on 2.20...

>
> Cheers,
> Carlos.
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-30 11:52               ` Adhemerval Zanella
@ 2014-09-10 14:13                 ` Adhemerval Zanella
  2014-09-22 15:00                   ` Adhemerval Zanella
  0 siblings, 1 reply; 13+ messages in thread
From: Adhemerval Zanella @ 2014-09-10 14:13 UTC (permalink / raw)
  To: libc-alpha

On 30-07-2014 08:52, Adhemerval Zanella wrote:
> On 30-07-2014 00:56, Carlos O'Donell wrote:
>> On 07/28/2014 08:05 AM, Adhemerval Zanella wrote:
>>> On 22-07-2014 09:59, Adhemerval Zanella wrote:
>>>> On 17-07-2014 15:49, Adhemerval Zanella wrote:
>>>>> On 16-07-2014 18:20, Joseph S. Myers wrote:
>>>>>> This patch looks like it needs updating for hppa now having its own 
>>>>>> libc.abilist.
>>>>>>
>>>>> Thanks, I though I have covered all abi files. What about the implementation itself?
>>>>>
>>>> Ping about patch contents.
>>>>
>>> Ping.  I have update my branch azanella/fmemopen.
>>>
>> I started reviewing this and IMO it's going to take
>> more time than we have during the freeze.
>>
>> I see no strong or compelling argument to put it
>> into 2.20.
>>
>> If it went into 2.21 we could test it in rawhide and
>> make sure nothing else was broken.
>>
>> If I've learned anything from Siddhesh's changes
>> in the libio code it's that nothing is as easy as
>> you think and distribution testing is critical
>> to finding issues.
>>
>> My strong recommendation is that this get deferred
>> until 2.21.
>>
>> Unless you have done distribution testing already?
> I have not and it is no problem to move it to 2.21.  I just a pity we 
> can't add it on 2.20...
>
>> Cheers,
>> Carlos.
>>
I have update the symbol versioning and abilist for 2.21 and pushed it to
branch [1].


[1] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/fmemopen 

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-09-10 14:13                 ` Adhemerval Zanella
@ 2014-09-22 15:00                   ` Adhemerval Zanella
  2014-10-07 12:44                     ` Adhemerval Zanella
  0 siblings, 1 reply; 13+ messages in thread
From: Adhemerval Zanella @ 2014-09-22 15:00 UTC (permalink / raw)
  To: libc-alpha

On 10-09-2014 11:13, Adhemerval Zanella wrote:
> On 30-07-2014 08:52, Adhemerval Zanella wrote:
>> On 30-07-2014 00:56, Carlos O'Donell wrote:
>>> On 07/28/2014 08:05 AM, Adhemerval Zanella wrote:
>>>> On 22-07-2014 09:59, Adhemerval Zanella wrote:
>>>>> On 17-07-2014 15:49, Adhemerval Zanella wrote:
>>>>>> On 16-07-2014 18:20, Joseph S. Myers wrote:
>>>>>>> This patch looks like it needs updating for hppa now having its own 
>>>>>>> libc.abilist.
>>>>>>>
>>>>>> Thanks, I though I have covered all abi files. What about the implementation itself?
>>>>>>
>>>>> Ping about patch contents.
>>>>>
>>>> Ping.  I have update my branch azanella/fmemopen.
>>>>
>>> I started reviewing this and IMO it's going to take
>>> more time than we have during the freeze.
>>>
>>> I see no strong or compelling argument to put it
>>> into 2.20.
>>>
>>> If it went into 2.21 we could test it in rawhide and
>>> make sure nothing else was broken.
>>>
>>> If I've learned anything from Siddhesh's changes
>>> in the libio code it's that nothing is as easy as
>>> you think and distribution testing is critical
>>> to finding issues.
>>>
>>> My strong recommendation is that this get deferred
>>> until 2.21.
>>>
>>> Unless you have done distribution testing already?
>> I have not and it is no problem to move it to 2.21.  I just a pity we 
>> can't add it on 2.20...
>>
>>> Cheers,
>>> Carlos.
>>>
> I have update the symbol versioning and abilist for 2.21 and pushed it to
> branch [1].
>
>
> [1] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/fmemopen 
>
Ping.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-09-22 15:00                   ` Adhemerval Zanella
@ 2014-10-07 12:44                     ` Adhemerval Zanella
  0 siblings, 0 replies; 13+ messages in thread
From: Adhemerval Zanella @ 2014-10-07 12:44 UTC (permalink / raw)
  To: libc-alpha

On 22-09-2014 12:00, Adhemerval Zanella wrote:
> On 10-09-2014 11:13, Adhemerval Zanella wrote:
>> On 30-07-2014 08:52, Adhemerval Zanella wrote:
>>> On 30-07-2014 00:56, Carlos O'Donell wrote:
>>>> On 07/28/2014 08:05 AM, Adhemerval Zanella wrote:
>>>>> On 22-07-2014 09:59, Adhemerval Zanella wrote:
>>>>>> On 17-07-2014 15:49, Adhemerval Zanella wrote:
>>>>>>> On 16-07-2014 18:20, Joseph S. Myers wrote:
>>>>>>>> This patch looks like it needs updating for hppa now having its own 
>>>>>>>> libc.abilist.
>>>>>>>>
>>>>>>> Thanks, I though I have covered all abi files. What about the implementation itself?
>>>>>>>
>>>>>> Ping about patch contents.
>>>>>>
>>>>> Ping.  I have update my branch azanella/fmemopen.
>>>>>
>>>> I started reviewing this and IMO it's going to take
>>>> more time than we have during the freeze.
>>>>
>>>> I see no strong or compelling argument to put it
>>>> into 2.20.
>>>>
>>>> If it went into 2.21 we could test it in rawhide and
>>>> make sure nothing else was broken.
>>>>
>>>> If I've learned anything from Siddhesh's changes
>>>> in the libio code it's that nothing is as easy as
>>>> you think and distribution testing is critical
>>>> to finding issues.
>>>>
>>>> My strong recommendation is that this get deferred
>>>> until 2.21.
>>>>
>>>> Unless you have done distribution testing already?
>>> I have not and it is no problem to move it to 2.21.  I just a pity we 
>>> can't add it on 2.20...
>>>
>>>> Cheers,
>>>> Carlos.
>>>>
>> I have update the symbol versioning and abilist for 2.21 and pushed it to
>> branch [1].
>>
>>
>> [1] https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/azanella/fmemopen 
>>
> Ping.
>
Ping.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance
  2014-07-02 12:30 [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance Adhemerval Zanella
  2014-07-07 18:01 ` Adhemerval Zanella
@ 2014-10-20 23:00 ` Rich Felker
  1 sibling, 0 replies; 13+ messages in thread
From: Rich Felker @ 2014-10-20 23:00 UTC (permalink / raw)
  To: libc-alpha

On Wed, Jul 02, 2014 at 09:29:36AM -0300, Adhemerval Zanella wrote:
> Hi,
> 
> This is a small update on the previous fmemopen patch I have sent [1].
> the change is basically:
> 
> * 'w' mode does not truncate the buffer, only 'w+'
> 
> I also rebased against master to adjust NEWS file.

Are you aware of the issues raised here?

http://www.austingroupbugs.net/view.php?id=657

While you're changing the behavior, it would be nice to resolve this
issue too. POSIX currently specifies some nonsense with regard to how
null termination happens for "w" mode, and it doesn't match the
current glibc behavior.

Rich

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2014-10-20 23:00 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-02 12:30 [PATCH v3 3/3] libio: fmemopen rewrite to POSIX compliance Adhemerval Zanella
2014-07-07 18:01 ` Adhemerval Zanella
2014-07-14 11:39   ` Adhemerval Zanella
2014-07-16 21:20     ` Joseph S. Myers
2014-07-17 18:49       ` Adhemerval Zanella
2014-07-22 12:59         ` Adhemerval Zanella
2014-07-28 12:05           ` Adhemerval Zanella
2014-07-30  3:56             ` Carlos O'Donell
2014-07-30 11:52               ` Adhemerval Zanella
2014-09-10 14:13                 ` Adhemerval Zanella
2014-09-22 15:00                   ` Adhemerval Zanella
2014-10-07 12:44                     ` Adhemerval Zanella
2014-10-20 23:00 ` Rich Felker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).