libio: use PTR_MANGLE/PTR_DEMANGLE for FILE vtables

Message ID 20150813005601.GJ6087@outflux.net
State Changes Requested, archived
Headers

Commit Message

Kees Cook Aug. 13, 2015, 12:56 a.m. UTC
  Hi!

This is a resend (from 2011!) of my PTR_MANGLE series for the FILE vtable.
It was previously discussed here: http://sourceware-org.1504.n7.nabble.com/PATCH-libio-use-PTR-MANGLE-PTR-DEMANGLE-for-FILE-vtables-td12300.html

It sounds like only very very old code was sharing FILE externally, so this
appears safe. "make xcheck" passes. If this is NOT okay for general use, I'd
like to make it a configure option, since for modern glibc users, it works
fine. (e.g. Chrome OS has been using this patch for 3 years now.)

Thanks!

-Kees

---
2015-08-12  Kees Cook <keescook@chromium.org>

	* libio/libioP.h: Create inline helpers to run the PTR_MANGLE and
	PTR_DEMANGLE routines on vtable pointers. Create _IO_JUMPS_SET and
	_IO_WIDE_JUMPS_SET macros to use the new inline helpers. Update the
	_IO_JUMPS_FUNC and _IO_WIDE_JUMPS_FUNC to use the new inline helpers.
	* debug/obprintf_chk.c: Replace direct vtable assignment with macro.
	* debug/vasprintf_chk.c: Likewise.
	* debug/vdprintf_chk.c: Likewise.
	* debug/vsnprintf_chk.c: Likewise.
	* debug/vsprintf_chk.c: Likewise.
	* libio/fileops.c: Likewise.
	* libio/freopen.c: Likewise.
	* libio/freopen64.c: Likewise.
	* libio/genops.c: Likewise.
	* libio/iofdopen.c: Likewise.
	* libio/iofopen.c: Likewise.
	* libio/iofopncook.c: Likewise.
	* libio/iofwide.c: Likewise.
	* libio/iopopen.c: Likewise.
	* libio/iovdprintf.c: Likewise.
	* libio/iovsprintf.c: Likewise.
	* libio/iovsscanf.c: Likewise.
	* libio/memstream.c: Likewise.
	* libio/obprintf.c: Likewise.
	* libio/oldiofdopen.c: Likewise.
	* libio/oldiofopen.c: Likewise.
	* libio/oldiopopen.c: Likewise.
	* libio/vasprintf.c: Likewise.
	* libio/vsnprintf.c: Likewise.
	* stdio-common/isoc99_vsscanf.c: Likewise.
	* stdio-common/vfprintf.c: Likewise.
	* stdlib/strfmon_l.c: Likewise.
	* misc/init-misc.c: Mangle predefined stdio FILE vtables at startup.
---
 debug/obprintf_chk.c          |  2 +-
 debug/vasprintf_chk.c         |  2 +-
 debug/vdprintf_chk.c          |  2 +-
 debug/vsnprintf_chk.c         |  2 +-
 debug/vsprintf_chk.c          |  2 +-
 libio/fileops.c               | 28 +++++++++----------
 libio/freopen.c               |  6 ++--
 libio/freopen64.c             |  4 +--
 libio/genops.c                |  2 +-
 libio/iofdopen.c              |  4 +--
 libio/iofopen.c               |  8 +++---
 libio/iofopncook.c            |  4 +--
 libio/iofwide.c               |  2 +-
 libio/iopopen.c               |  2 +-
 libio/iovdprintf.c            |  2 +-
 libio/iovsprintf.c            |  2 +-
 libio/iovsscanf.c             |  2 +-
 libio/libioP.h                | 64 ++++++++++++++++++++++++++++++-------------
 libio/memstream.c             |  2 +-
 libio/obprintf.c              |  2 +-
 libio/oldiofdopen.c           |  2 +-
 libio/oldiofopen.c            |  2 +-
 libio/oldiopopen.c            |  2 +-
 libio/vasprintf.c             |  2 +-
 libio/vsnprintf.c             |  2 +-
 misc/init-misc.c              | 13 +++++++++
 stdio-common/isoc99_vsscanf.c |  2 +-
 stdio-common/vfprintf.c       |  2 +-
 stdlib/strfmon_l.c            |  2 +-
 29 files changed, 106 insertions(+), 67 deletions(-)
  

Comments

Mike Frysinger Aug. 13, 2015, 3:34 a.m. UTC | #1
On 12 Aug 2015 17:56, Kees Cook wrote:
> This is a resend (from 2011!) of my PTR_MANGLE series for the FILE vtable.
> It was previously discussed here: http://sourceware-org.1504.n7.nabble.com/PATCH-libio-use-PTR-MANGLE-PTR-DEMANGLE-for-FILE-vtables-td12300.html

nabble sucks ;)
https://sourceware.org/ml/libc-alpha/2011-12/msg00073.html

> +static inline void
> +__mangle_vtable(const struct _IO_jump_t **vtable, const struct _IO_jump_t *table)
> +{
> +    struct _IO_jump_t *ptr;
> +    ptr = (struct _IO_jump_t *)table;
> +    PTR_MANGLE(ptr);
> +    *vtable = ptr;
> +}

this doesn't match GNU style -- there should be spaces before the (

also you can merge the first two statements

> +  __mangle_vtable(&_IO_JUMPS_RAW(THIS), (TABLE))

some more code where there should be a space before the ( ... i'll stop checking 
for that now ;)
-mike
  

Patch

diff --git a/debug/obprintf_chk.c b/debug/obprintf_chk.c
index c49d1e9..203b403 100644
--- a/debug/obprintf_chk.c
+++ b/debug/obprintf_chk.c
@@ -54,7 +54,7 @@  __obstack_vprintf_chk (struct obstack *obstack, int flags, const char *format,
 #endif
 
   _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
+  _IO_JUMPS_SET (&new_f.ofile.file, &_IO_obstack_jumps);
   room = obstack_room (obstack);
   size = obstack_object_size (obstack) + room;
   if (size == 0)
diff --git a/debug/vasprintf_chk.c b/debug/vasprintf_chk.c
index 8ecb9e8..4779836 100644
--- a/debug/vasprintf_chk.c
+++ b/debug/vasprintf_chk.c
@@ -52,7 +52,7 @@  __vasprintf_chk (char **result_ptr, int flags, const char *format,
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS_SET (&sf._sbf, &_IO_str_jumps);
   _IO_str_init_static_internal (&sf, string, init_string_size, string);
   sf._sbf._f._flags &= ~_IO_USER_BUF;
   sf._s._allocate_buffer = (_IO_alloc_type) malloc;
diff --git a/debug/vdprintf_chk.c b/debug/vdprintf_chk.c
index bf43ed8..eb86c0b 100644
--- a/debug/vdprintf_chk.c
+++ b/debug/vdprintf_chk.c
@@ -38,7 +38,7 @@  __vdprintf_chk (int d, int flags, const char *format, va_list arg)
   tmpfil.file._lock = NULL;
 #endif
   _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
-  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
+  _IO_JUMPS_SET (&tmpfil, &_IO_file_jumps);
   _IO_file_init (&tmpfil);
 #if  !_IO_UNIFIED_JUMPTABLES
   tmpfil.vtable = NULL;
diff --git a/debug/vsnprintf_chk.c b/debug/vsnprintf_chk.c
index c6cb383..5b09121 100644
--- a/debug/vsnprintf_chk.c
+++ b/debug/vsnprintf_chk.c
@@ -51,7 +51,7 @@  ___vsnprintf_chk (char *s, size_t maxlen, int flags, size_t slen,
     }
 
   _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
+  _IO_JUMPS_SET (&sf.f._sbf, &_IO_strn_jumps);
   s[0] = '\0';
 
   /* For flags > 0 (i.e. __USE_FORTIFY_LEVEL > 1) request that %n
diff --git a/debug/vsprintf_chk.c b/debug/vsprintf_chk.c
index 1ec67b5..3805788 100644
--- a/debug/vsprintf_chk.c
+++ b/debug/vsprintf_chk.c
@@ -73,7 +73,7 @@  ___vsprintf_chk (char *s, int flags, size_t slen, const char *format,
     __chk_fail ();
 
   _IO_no_init (&f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&f._sbf) = &_IO_str_chk_jumps;
+  _IO_JUMPS_SET (&f._sbf, &_IO_str_chk_jumps);
   s[0] = '\0';
   _IO_str_init_static_internal (&f, s, slen - 1, s);
 
diff --git a/libio/fileops.c b/libio/fileops.c
index cbcd6f5..1bfe883 100644
--- a/libio/fileops.c
+++ b/libio/fileops.c
@@ -414,7 +414,7 @@  _IO_new_file_fopen (_IO_FILE *fp, const char *filename, const char *mode,
 	    &result->_wide_data->_IO_state;
 
 	  /* From now on use the wide character callback functions.  */
-	  _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;
+	  _IO_JUMPS_FILE_plus_SET (fp, _IO_WIDE_JUMPS_FUNC (fp));
 
 	  /* Set the mode now.  */
 	  result->_mode = 1;
@@ -466,8 +466,8 @@  _IO_file_setbuf_mmap (_IO_FILE *fp, char *p, _IO_ssize_t len)
   _IO_FILE *result;
 
   /* Change the function table.  */
-  _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
-  fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+  _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps);
+  _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps);
 
   /* And perform the normal operation.  */
   result = _IO_new_file_setbuf (fp, p, len);
@@ -475,8 +475,8 @@  _IO_file_setbuf_mmap (_IO_FILE *fp, char *p, _IO_ssize_t len)
   /* If the call failed, restore to using mmap.  */
   if (result == NULL)
     {
-      _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap;
-      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
+      _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps_mmap);
+      _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps_mmap);
     }
 
   return result;
@@ -703,10 +703,10 @@  mmap_remap_check (_IO_FILE *fp)
       fp->_IO_buf_base = fp->_IO_buf_end = NULL;
       _IO_setg (fp, NULL, NULL, NULL);
       if (fp->_mode <= 0)
-	_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
+	_IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps);
       else
-	_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps;
-      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+	_IO_JUMPS_FILE_plus_SET (fp, &_IO_wfile_jumps);
+      _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps);
 
       return 1;
     }
@@ -773,10 +773,10 @@  decide_maybe_mmap (_IO_FILE *fp)
 	      fp->_offset = st.st_size;
 
 	      if (fp->_mode <= 0)
-		_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_mmap;
+		_IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps_mmap);
 	      else
-		_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_mmap;
-	      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_mmap;
+		_IO_JUMPS_FILE_plus_SET (fp, &_IO_wfile_jumps_mmap);
+	      _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps_mmap);
 
 	      return;
 	    }
@@ -786,10 +786,10 @@  decide_maybe_mmap (_IO_FILE *fp)
   /* We couldn't use mmap, so revert to the vanilla file operations.  */
 
   if (fp->_mode <= 0)
-    _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
+    _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps);
   else
-    _IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps;
-  fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+    _IO_JUMPS_FILE_plus_SET (fp, &_IO_wfile_jumps);
+  _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps);
 }
 
 int
diff --git a/libio/freopen.c b/libio/freopen.c
index 035fa1f..a9203fd 100644
--- a/libio/freopen.c
+++ b/libio/freopen.c
@@ -59,16 +59,16 @@  freopen (filename, mode, fp)
 	 to the old libio may be passed into shared C library and wind
 	 up here. */
       _IO_old_file_close_it (fp);
-      _IO_JUMPS_FILE_plus (fp) = &_IO_old_file_jumps;
+      _IO_JUMPS_FILE_plus_SET (fp, &_IO_old_file_jumps);
       result = _IO_old_file_fopen (fp, gfilename, mode);
     }
   else
 #endif
     {
       _IO_file_close_it (fp);
-      _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
+      _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps);
       if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
-	fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+	_IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps);
       result = _IO_file_fopen (fp, gfilename, mode, 1);
       if (result != NULL)
 	result = __fopen_maybe_mmap (result);
diff --git a/libio/freopen64.c b/libio/freopen64.c
index fc6ccb1..eb883d6 100644
--- a/libio/freopen64.c
+++ b/libio/freopen64.c
@@ -50,9 +50,9 @@  freopen64 (filename, mode, fp)
 			   ? fd_to_filename (fd) : filename);
   fp->_flags2 |= _IO_FLAGS2_NOCLOSE;
   _IO_file_close_it (fp);
-  _IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps;
+  _IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps);
   if (_IO_vtable_offset (fp) == 0 && fp->_wide_data != NULL)
-    fp->_wide_data->_wide_vtable = &_IO_wfile_jumps;
+    _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps);
   result = _IO_file_fopen (fp, gfilename, mode, 0);
   fp->_flags2 &= ~_IO_FLAGS2_NOCLOSE;
   if (result != NULL)
diff --git a/libio/genops.c b/libio/genops.c
index e13b3d1..224c3d2 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -659,7 +659,7 @@  _IO_no_init (fp, flags, orientation, wd, jmp)
       fp->_wide_data->_IO_backup_base = NULL;
       fp->_wide_data->_IO_save_end = NULL;
 
-      fp->_wide_data->_wide_vtable = jmp;
+      _IO_WIDE_JUMPS_SET (fp, jmp);
     }
   else
     /* Cause predictable crash when a wide function is called on a byte
diff --git a/libio/iofdopen.c b/libio/iofdopen.c
index e7d84ae..d272568 100644
--- a/libio/iofdopen.c
+++ b/libio/iofdopen.c
@@ -150,11 +150,11 @@  _IO_new_fdopen (fd, mode)
 	       ? &_IO_wfile_jumps_maybe_mmap :
 #endif
 	       &_IO_wfile_jumps);
-  _IO_JUMPS (&new_f->fp) =
+  _IO_JUMPS_SET (&new_f->fp,
 #ifdef _G_HAVE_MMAP
     (use_mmap && (read_write & _IO_NO_WRITES)) ? &_IO_file_jumps_maybe_mmap :
 #endif
-      &_IO_file_jumps;
+      &_IO_file_jumps);
   _IO_file_init (&new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
diff --git a/libio/iofopen.c b/libio/iofopen.c
index be2bbb6..2d9fc41 100644
--- a/libio/iofopen.c
+++ b/libio/iofopen.c
@@ -46,10 +46,10 @@  __fopen_maybe_mmap (_IO_FILE *fp)
 	 vanilla file operations and reset the jump table accordingly.  */
 
       if (fp->_mode <= 0)
-	_IO_JUMPS_FILE_plus (fp) = &_IO_file_jumps_maybe_mmap;
+	_IO_JUMPS_FILE_plus_SET (fp, &_IO_file_jumps_maybe_mmap);
       else
-	_IO_JUMPS_FILE_plus (fp) = &_IO_wfile_jumps_maybe_mmap;
-      fp->_wide_data->_wide_vtable = &_IO_wfile_jumps_maybe_mmap;
+	_IO_JUMPS_FILE_plus_SET (fp, &_IO_wfile_jumps_maybe_mmap);
+      _IO_WIDE_JUMPS_SET (fp, &_IO_wfile_jumps_maybe_mmap);
     }
 #endif
   return fp;
@@ -78,7 +78,7 @@  __fopen_internal (const char *filename, const char *mode, int is32)
 #else
   _IO_no_init (&new_f->fp.file, 1, 0, NULL, NULL);
 #endif
-  _IO_JUMPS (&new_f->fp) = &_IO_file_jumps;
+  _IO_JUMPS_SET (&new_f->fp, &_IO_file_jumps);
   _IO_file_init (&new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
diff --git a/libio/iofopncook.c b/libio/iofopncook.c
index b845d29..7ffdb42 100644
--- a/libio/iofopncook.c
+++ b/libio/iofopncook.c
@@ -145,7 +145,7 @@  _IO_cookie_init (struct _IO_cookie_file *cfile, int read_write,
 		 void *cookie, _IO_cookie_io_functions_t io_functions)
 {
   _IO_init (&cfile->__fp.file, 0);
-  _IO_JUMPS (&cfile->__fp) = &_IO_cookie_jumps;
+  _IO_JUMPS_SET (&cfile->__fp, &_IO_cookie_jumps);
 
   cfile->__cookie = cookie;
   cfile->__io_functions = io_functions;
@@ -269,7 +269,7 @@  _IO_old_fopencookie (cookie, mode, io_functions)
 
   ret = _IO_fopencookie (cookie, mode, io_functions);
   if (ret != NULL)
-    _IO_JUMPS_FILE_plus (ret) = &_IO_old_cookie_jumps;
+    _IO_JUMPS_FILE_plus_SET (ret, &_IO_old_cookie_jumps);
 
   return ret;
 }
diff --git a/libio/iofwide.c b/libio/iofwide.c
index 0c175d1..8d1c39a 100644
--- a/libio/iofwide.c
+++ b/libio/iofwide.c
@@ -184,7 +184,7 @@  _IO_fwide (fp, mode)
 #endif
 
       /* From now on use the wide character callback functions.  */
-      _IO_JUMPS_FILE_plus (fp) = fp->_wide_data->_wide_vtable;
+      _IO_JUMPS_FILE_plus_SET (fp, _IO_WIDE_JUMPS_FUNC (fp));
     }
 
   /* Set the mode now.  */
diff --git a/libio/iopopen.c b/libio/iopopen.c
index 53da776..b19e62f 100644
--- a/libio/iopopen.c
+++ b/libio/iopopen.c
@@ -293,7 +293,7 @@  _IO_new_popen (command, mode)
 #endif
   fp = &new_f->fpx.file.file;
   _IO_init (fp, 0);
-  _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps;
+  _IO_JUMPS_SET (&new_f->fpx.file, &_IO_proc_jumps);
   _IO_new_file_init (&new_f->fpx.file);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fpx.file.vtable = NULL;
diff --git a/libio/iovdprintf.c b/libio/iovdprintf.c
index 116912a..e449443 100644
--- a/libio/iovdprintf.c
+++ b/libio/iovdprintf.c
@@ -41,7 +41,7 @@  _IO_vdprintf (d, format, arg)
   tmpfil.file._lock = NULL;
 #endif
   _IO_no_init (&tmpfil.file, _IO_USER_LOCK, 0, &wd, &_IO_wfile_jumps);
-  _IO_JUMPS (&tmpfil) = &_IO_file_jumps;
+  _IO_JUMPS_SET (&tmpfil, &_IO_file_jumps);
   _IO_file_init (&tmpfil);
 #if  !_IO_UNIFIED_JUMPTABLES
   tmpfil.vtable = NULL;
diff --git a/libio/iovsprintf.c b/libio/iovsprintf.c
index b6cc6b3..e624b29 100644
--- a/libio/iovsprintf.c
+++ b/libio/iovsprintf.c
@@ -37,7 +37,7 @@  __IO_vsprintf (char *string, const char *format, _IO_va_list args)
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS_SET (&sf._sbf, &_IO_str_jumps);
   _IO_str_init_static_internal (&sf, string, -1, string);
   ret = _IO_vfprintf (&sf._sbf._f, format, args);
   _IO_putc_unlocked ('\0', &sf._sbf._f);
diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
index c4fbd1b..35330e2 100644
--- a/libio/iovsscanf.c
+++ b/libio/iovsscanf.c
@@ -39,7 +39,7 @@  _IO_vsscanf (string, format, args)
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS_SET (&sf._sbf, &_IO_str_jumps);
   _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
   ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
   return ret;
diff --git a/libio/libioP.h b/libio/libioP.h
index 0f16e2d..1b99da5 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -70,17 +70,16 @@  extern "C" {
 
 /* THE JUMPTABLE FUNCTIONS.
 
- * The _IO_FILE type is used to implement the FILE type in GNU libc,
- * as well as the streambuf class in GNU iostreams for C++.
- * These are all the same, just used differently.
- * An _IO_FILE (or FILE) object is allows followed by a pointer to
- * a jump table (of pointers to functions).  The pointer is accessed
- * with the _IO_JUMPS macro.  The jump table has an eccentric format,
- * so as to be compatible with the layout of a C++ virtual function table.
- * (as implemented by g++).  When a pointer to a streambuf object is
- * coerced to an (_IO_FILE*), then _IO_JUMPS on the result just
- * happens to point to the virtual function table of the streambuf.
- * Thus the _IO_JUMPS function table used for C stdio/libio does
+ * The _IO_FILE type is used to implement the FILE type in GNU libc, as well
+ * as the streambuf class in GNU iostreams for C++. These are all the same,
+ * just used differently. An _IO_FILE (or FILE) object is allows followed by
+ * a pointer to a jump table (of pointers to functions). The pointer is
+ * accessed with the _IO_JUMPS_SET and _IO_JUMPS_FUNC macros. The jump table
+ * has an eccentric format, so as to be compatible with the layout of a C++
+ * virtual function table. (as implemented by g++). When a pointer to a
+ * streambuf object is coerced to an (_IO_FILE*), then _IO_JUMPS on the
+ * result just happens to point to the virtual function table of the
+ * streambuf. Thus the _IO_JUMPS function table used for C stdio/libio does
  * double duty as the virtual function table for C++ streambuf.
  *
  * The entries in the _IO_JUMPS function table (and hence also the
@@ -106,6 +105,15 @@  extern "C" {
 # define _IO_JUMPS_OFFSET 0
 #endif
 
+static inline void
+__mangle_vtable(const struct _IO_jump_t **vtable, const struct _IO_jump_t *table)
+{
+    struct _IO_jump_t *ptr;
+    ptr = (struct _IO_jump_t *)table;
+    PTR_MANGLE(ptr);
+    *vtable = ptr;
+}
+
 /* Type of MEMBER in struct type TYPE.  */
 #define _IO_MEMBER_TYPE(TYPE, MEMBER) __typeof__ (((TYPE){}).MEMBER)
 
@@ -115,24 +123,42 @@  extern "C" {
   (*(_IO_MEMBER_TYPE (TYPE, MEMBER) *)(((char *) (THIS)) \
 				       + offsetof(TYPE, MEMBER)))
 
-#define _IO_JUMPS(THIS) (THIS)->vtable
-#define _IO_JUMPS_FILE_plus(THIS) \
+#define _IO_JUMPS_RAW(THIS) (THIS)->vtable
+#define _IO_JUMPS_SET(THIS, TABLE) \
+  __mangle_vtable(&_IO_JUMPS_RAW(THIS), (TABLE))
+
+#define _IO_JUMPS_FILE_plus_RAW(THIS) \
   _IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE_plus, vtable)
-#define _IO_WIDE_JUMPS(THIS) \
+#define _IO_JUMPS_FILE_plus_SET(THIS, TABLE) \
+  __mangle_vtable(&_IO_JUMPS_FILE_plus_RAW(THIS), (TABLE))
+
+#define _IO_WIDE_JUMPS_RAW(THIS) \
   _IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE, _wide_data)->_wide_vtable
+#define _IO_WIDE_JUMPS_SET(THIS, TABLE) \
+  __mangle_vtable(&_IO_WIDE_JUMPS_RAW(THIS), (TABLE))
+
 #define _IO_CHECK_WIDE(THIS) \
   (_IO_CAST_FIELD_ACCESS ((THIS), struct _IO_FILE, _wide_data) != NULL)
 
+static inline const struct _IO_jump_t *
+__demangle_vtable(const struct _IO_jump_t *vtable)
+{
+    struct _IO_jump_t *ptr;
+    ptr = (struct _IO_jump_t *)vtable;
+    PTR_DEMANGLE(ptr);
+    return (const struct _IO_jump_t *)ptr;
+}
+
 #if _IO_JUMPS_OFFSET
-# define _IO_JUMPS_FUNC(THIS) \
- (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus (THIS) \
-			   + (THIS)->_vtable_offset))
+# define _IO_JUMPS_FUNC(THIS) __demangle_vtable (\
+ (*(struct _IO_jump_t **) ((void *) &_IO_JUMPS_FILE_plus_RAW (THIS) \
+              + (THIS)->_vtable_offset)))
 # define _IO_vtable_offset(THIS) (THIS)->_vtable_offset
 #else
-# define _IO_JUMPS_FUNC(THIS) _IO_JUMPS_FILE_plus (THIS)
+# define _IO_JUMPS_FUNC(THIS) __demangle_vtable (_IO_JUMPS_FILE_plus_RAW (THIS))
 # define _IO_vtable_offset(THIS) 0
 #endif
-#define _IO_WIDE_JUMPS_FUNC(THIS) _IO_WIDE_JUMPS(THIS)
+#define _IO_WIDE_JUMPS_FUNC(THIS) __demangle_vtable (_IO_WIDE_JUMPS_RAW(THIS))
 #define JUMP_FIELD(TYPE, NAME) TYPE NAME
 #define JUMP0(FUNC, THIS) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS)
 #define JUMP1(FUNC, THIS, X1) (_IO_JUMPS_FUNC(THIS)->FUNC) (THIS, X1)
diff --git a/libio/memstream.c b/libio/memstream.c
index 84742d1..640740e 100644
--- a/libio/memstream.c
+++ b/libio/memstream.c
@@ -89,7 +89,7 @@  __open_memstream (bufloc, sizeloc)
       return NULL;
     }
   _IO_init (&new_f->fp._sf._sbf._f, 0);
-  _IO_JUMPS_FILE_plus (&new_f->fp._sf._sbf) = &_IO_mem_jumps;
+  _IO_JUMPS_FILE_plus_SET (&new_f->fp._sf._sbf, &_IO_mem_jumps);
   _IO_str_init_static_internal (&new_f->fp._sf, buf, _IO_BUFSIZ, buf);
   new_f->fp._sf._sbf._f._flags &= ~_IO_USER_BUF;
   new_f->fp._sf._s._allocate_buffer = (_IO_alloc_type) malloc;
diff --git a/libio/obprintf.c b/libio/obprintf.c
index d61de6a..b166362 100644
--- a/libio/obprintf.c
+++ b/libio/obprintf.c
@@ -132,7 +132,7 @@  _IO_obstack_vprintf (struct obstack *obstack, const char *format, va_list args)
 #endif
 
   _IO_no_init (&new_f.ofile.file.file, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&new_f.ofile.file) = &_IO_obstack_jumps;
+  _IO_JUMPS_SET (&new_f.ofile.file, &_IO_obstack_jumps);
   room = obstack_room (obstack);
   size = obstack_object_size (obstack) + room;
   if (size == 0)
diff --git a/libio/oldiofdopen.c b/libio/oldiofdopen.c
index e068ec7..5a571b5 100644
--- a/libio/oldiofdopen.c
+++ b/libio/oldiofdopen.c
@@ -113,7 +113,7 @@  _IO_old_fdopen (fd, mode)
   new_f->fp.file._file._lock = &new_f->lock;
 #endif
   _IO_old_init (&new_f->fp.file._file, 0);
-  _IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps;
+  _IO_JUMPS_FILE_plus_SET (&new_f->fp, &_IO_old_file_jumps);
   _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
diff --git a/libio/oldiofopen.c b/libio/oldiofopen.c
index a90a601..0b27b00 100644
--- a/libio/oldiofopen.c
+++ b/libio/oldiofopen.c
@@ -52,7 +52,7 @@  _IO_old_fopen (filename, mode)
   new_f->fp.file._file._lock = &new_f->lock;
 #endif
   _IO_old_init (&new_f->fp.file._file, 0);
-  _IO_JUMPS_FILE_plus (&new_f->fp) = &_IO_old_file_jumps;
+  _IO_JUMPS_FILE_plus_SET (&new_f->fp, &_IO_old_file_jumps);
   _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fp);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fp.vtable = NULL;
diff --git a/libio/oldiopopen.c b/libio/oldiopopen.c
index fb4c7b8..9d0b817 100644
--- a/libio/oldiopopen.c
+++ b/libio/oldiopopen.c
@@ -215,7 +215,7 @@  _IO_old_popen (command, mode)
 #endif
   fp = &new_f->fpx.file.file._file;
   _IO_old_init (fp, 0);
-  _IO_JUMPS_FILE_plus (&new_f->fpx.file) = &_IO_old_proc_jumps;
+  _IO_JUMPS_FILE_plus_SET (&new_f->fpx.file, &_IO_old_proc_jumps);
   _IO_old_file_init ((struct _IO_FILE_plus *) &new_f->fpx.file);
 #if  !_IO_UNIFIED_JUMPTABLES
   new_f->fpx.file.vtable = NULL;
diff --git a/libio/vasprintf.c b/libio/vasprintf.c
index 7f9c105..96e1d73 100644
--- a/libio/vasprintf.c
+++ b/libio/vasprintf.c
@@ -54,7 +54,7 @@  _IO_vasprintf (result_ptr, format, args)
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS_SET (&sf._sbf, &_IO_str_jumps);
   _IO_str_init_static_internal (&sf, string, init_string_size, string);
   sf._sbf._f._flags &= ~_IO_USER_BUF;
   sf._s._allocate_buffer = (_IO_alloc_type) malloc;
diff --git a/libio/vsnprintf.c b/libio/vsnprintf.c
index e2752d8..66f03cf 100644
--- a/libio/vsnprintf.c
+++ b/libio/vsnprintf.c
@@ -113,7 +113,7 @@  _IO_vsnprintf (string, maxlen, format, args)
     }
 
   _IO_no_init (&sf.f._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf.f._sbf) = &_IO_strn_jumps;
+  _IO_JUMPS_SET (&sf.f._sbf, &_IO_strn_jumps);
   string[0] = '\0';
   _IO_str_init_static_internal (&sf.f, string, maxlen - 1, string);
   ret = _IO_vfprintf (&sf.f._sbf._f, format, args);
diff --git a/misc/init-misc.c b/misc/init-misc.c
index 9254f02..bcf26a2 100644
--- a/misc/init-misc.c
+++ b/misc/init-misc.c
@@ -16,7 +16,11 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include "libioP.h"
+
 #include <string.h>
+#include <stdio.h>
+#include <sysdep.h>
 #include <libc-internal.h>
 
 char *__progname_full = (char *) "";
@@ -37,4 +41,13 @@  __init_misc (int argc, char **argv, char **envp)
 	__progname = p + 1;
       __progname_full = argv[0];
     }
+
+  PTR_MANGLE (_IO_JUMPS_FILE_plus_RAW (stdin));
+  PTR_MANGLE (_IO_WIDE_JUMPS_RAW (stdin));
+
+  PTR_MANGLE (_IO_JUMPS_FILE_plus_RAW (stdout));
+  PTR_MANGLE (_IO_WIDE_JUMPS_RAW (stdout));
+
+  PTR_MANGLE (_IO_JUMPS_FILE_plus_RAW (stderr));
+  PTR_MANGLE (_IO_WIDE_JUMPS_RAW (stderr));
 }
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index dadd125..513e065 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -37,7 +37,7 @@  __isoc99_vsscanf (const char *string, const char *format, _IO_va_list args)
   sf._sbf._f._lock = NULL;
 #endif
   _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
+  _IO_JUMPS_SET (&sf._sbf, &_IO_str_jumps);
   _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
   sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
   ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
diff --git a/stdio-common/vfprintf.c b/stdio-common/vfprintf.c
index 0592e70..50f67f1 100644
--- a/stdio-common/vfprintf.c
+++ b/stdio-common/vfprintf.c
@@ -2339,7 +2339,7 @@  buffered_vfprintf (_IO_FILE *s, const CHAR_T *format,
   hp->_lock = NULL;
 #endif
   hp->_flags2 = s->_flags2;
-  _IO_JUMPS (&helper._f) = (struct _IO_jump_t *) &_IO_helper_jumps;
+  _IO_JUMPS_SET (&helper._f, (struct _IO_jump_t *) &_IO_helper_jumps);
 
   /* Now print to helper instead.  */
 #ifndef COMPILE_WPRINTF
diff --git a/stdlib/strfmon_l.c b/stdlib/strfmon_l.c
index 3fae78b..ba734da 100644
--- a/stdlib/strfmon_l.c
+++ b/stdlib/strfmon_l.c
@@ -516,7 +516,7 @@  __vstrfmon_l (char *s, size_t maxsize, __locale_t loc, const char *format,
       f._sbf._f._lock = NULL;
 #endif
       _IO_init (&f._sbf._f, 0);
-      _IO_JUMPS (&f._sbf) = &_IO_str_jumps;
+      _IO_JUMPS_SET (&f._sbf, &_IO_str_jumps);
       _IO_str_init_static_internal (&f, dest, (s + maxsize) - dest, dest);
       /* We clear the last available byte so we can find out whether
 	 the numeric representation is too long.  */