4c174f
commit 44927211651adde42bbd431ef5ebe568186125e5
4c174f
Author: Florian Weimer <fweimer@redhat.com>
4c174f
Date:   Tue Jul 3 17:57:14 2018 +0200
4c174f
4c174f
    libio: Add tst-vtables, tst-vtables-interposed
978e96
    
4c174f
    (cherry picked from commit 29055464a03c72762969a2e8734d0d05d4d70e58)
978e96
    
4c174f
    Some adjustments were needed for a tricky multi-inclusion issue related
4c174f
    to libioP.h.
4c174f
978e96
Backported from the upsteam release/2.26/master branch, adjusted for
4c174f
lack of tests-internal support downstream.
4c174f
4c174f
diff --git a/libio/Makefile b/libio/Makefile
4c174f
index 0cef96141209fe99..1e923da42e45c492 100644
4c174f
--- a/libio/Makefile
4c174f
+++ b/libio/Makefile
4c174f
@@ -61,7 +61,9 @@ tests = tst_swprintf tst_wprintf tst_swscanf tst_wscanf tst_getwc tst_putwc   \
4c174f
 	bug-memstream1 bug-wmemstream1 \
4c174f
 	tst-setvbuf1 tst-popen1 tst-fgetwc bug-wsetpos tst-fseek \
4c174f
 	tst-fwrite-error tst-ftell-active-handler \
4c174f
-	tst-ftell-append
4c174f
+	tst-ftell-append \
4c174f
+	tst-vtables tst-vtables-interposed
4c174f
+
4c174f
 ifeq (yes,$(build-shared))
4c174f
 # Add test-fopenloc only if shared library is enabled since it depends on
4c174f
 # shared localedata objects.
4c174f
diff --git a/libio/tst-vtables-common.c b/libio/tst-vtables-common.c
4c174f
new file mode 100644
4c174f
index 0000000000000000..dc8d89c195b95b8d
4c174f
--- /dev/null
4c174f
+++ b/libio/tst-vtables-common.c
4c174f
@@ -0,0 +1,511 @@
4c174f
+/* Test for libio vtables and their validation.  Common code.
4c174f
+   Copyright (C) 2018 Free Software Foundation, Inc.
4c174f
+   This file is part of the GNU C Library.
4c174f
+
4c174f
+   The GNU C Library is free software; you can redistribute it and/or
4c174f
+   modify it under the terms of the GNU Lesser General Public
4c174f
+   License as published by the Free Software Foundation; either
4c174f
+   version 2.1 of the License, or (at your option) any later version.
4c174f
+
4c174f
+   The GNU C Library is distributed in the hope that it will be useful,
4c174f
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
4c174f
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
4c174f
+   Lesser General Public License for more details.
4c174f
+
4c174f
+   You should have received a copy of the GNU Lesser General Public
4c174f
+   License along with the GNU C Library; if not, see
4c174f
+   <http://www.gnu.org/licenses/>.  */
4c174f
+
4c174f
+/* This test provides some coverage for how various stdio functions
4c174f
+   use the vtables in FILE * objects.  The focus is mostly on which
4c174f
+   functions call which methods, not so much on validating data
4c174f
+   processing.  An initial series of tests check that custom vtables
4c174f
+   do not work without activation through _IO_init.
4c174f
+
4c174f
+   Note: libio vtables are deprecated feature.  Do not use this test
4c174f
+   as a documentation source for writing custom vtables.  See
4c174f
+   fopencookie for a different way of creating custom stdio
4c174f
+   streams.  */
4c174f
+
4c174f
+#include <stdbool.h>
4c174f
+#include <string.h>
4c174f
+#include <support/capture_subprocess.h>
4c174f
+#include <support/check.h>
4c174f
+#include <support/namespace.h>
4c174f
+#include <support/support.h>
4c174f
+#include <support/test-driver.h>
4c174f
+#include <support/xunistd.h>
4c174f
+
4c174f
+/* Data shared between the test subprocess and the test driver in the
4c174f
+   parent.  Note that *shared is reset at the start of the check_call
4c174f
+   function.  */
4c174f
+struct shared
4c174f
+{
4c174f
+  /* Expected file pointer for method calls.  */
4c174f
+  FILE *fp;
4c174f
+
4c174f
+  /* If true, assume that a call to _IO_init is needed to enable
4c174f
+     custom vtables.  */
4c174f
+  bool initially_disabled;
4c174f
+
4c174f
+  /* Requested return value for the methods which have one.  */
4c174f
+  int return_value;
4c174f
+
4c174f
+  /* A value (usually a character) recorded by some of the methods
4c174f
+     below.  */
4c174f
+  int value;
4c174f
+
4c174f
+  /* Likewise, for some data.  */
4c174f
+  char buffer[16];
4c174f
+  size_t buffer_length;
4c174f
+
4c174f
+  /* Total number of method calls.  */
4c174f
+  unsigned int calls;
4c174f
+
4c174f
+  /* Individual method call counts.  */
4c174f
+  unsigned int calls_finish;
4c174f
+  unsigned int calls_overflow;
4c174f
+  unsigned int calls_underflow;
4c174f
+  unsigned int calls_uflow;
4c174f
+  unsigned int calls_pbackfail;
4c174f
+  unsigned int calls_xsputn;
4c174f
+  unsigned int calls_xsgetn;
4c174f
+  unsigned int calls_seekoff;
4c174f
+  unsigned int calls_seekpos;
4c174f
+  unsigned int calls_setbuf;
4c174f
+  unsigned int calls_sync;
4c174f
+  unsigned int calls_doallocate;
4c174f
+  unsigned int calls_read;
4c174f
+  unsigned int calls_write;
4c174f
+  unsigned int calls_seek;
4c174f
+  unsigned int calls_close;
4c174f
+  unsigned int calls_stat;
4c174f
+  unsigned int calls_showmanyc;
4c174f
+  unsigned int calls_imbue;
4c174f
+} *shared;
4c174f
+
4c174f
+/* Method implementations which increment the counters in *shared.  */
4c174f
+
4c174f
+static void
4c174f
+log_method (FILE *fp, const char *name)
4c174f
+{
4c174f
+  if (test_verbose > 0)
4c174f
+    printf ("info: %s (%p) called\n", name, fp);
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+method_finish (FILE *fp, int dummy)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_finish;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_overflow (FILE *fp, int ch)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_overflow;
4c174f
+  shared->value = ch;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_underflow (FILE *fp)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_underflow;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_uflow (FILE *fp)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_uflow;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_pbackfail (FILE *fp, int ch)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_pbackfail;
4c174f
+  shared->value = ch;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static size_t
4c174f
+method_xsputn (FILE *fp, const void *data, size_t n)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_xsputn;
4c174f
+
4c174f
+  size_t to_copy = n;
4c174f
+  if (n > sizeof (shared->buffer))
4c174f
+    to_copy = sizeof (shared->buffer);
4c174f
+  memcpy (shared->buffer, data, to_copy);
4c174f
+  shared->buffer_length = to_copy;
4c174f
+  return to_copy;
4c174f
+}
4c174f
+
4c174f
+static size_t
4c174f
+method_xsgetn (FILE *fp, void *data, size_t n)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_xsgetn;
4c174f
+  return 0;
4c174f
+}
4c174f
+
4c174f
+static off64_t
4c174f
+method_seekoff (FILE *fp, off64_t offset, int dir, int mode)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_seekoff;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static off64_t
4c174f
+method_seekpos (FILE *fp, off64_t offset, int mode)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_seekpos;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static FILE *
4c174f
+method_setbuf (FILE *fp, char *buffer, ssize_t length)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_setbuf;
4c174f
+  return fp;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_sync (FILE *fp)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_sync;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_doallocate (FILE *fp)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_doallocate;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static ssize_t
4c174f
+method_read (FILE *fp, void *data, ssize_t length)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_read;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static ssize_t
4c174f
+method_write (FILE *fp, const void *data, ssize_t length)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_write;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static off64_t
4c174f
+method_seek (FILE *fp, off64_t offset, int mode)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_seek;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_close (FILE *fp)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_close;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_stat (FILE *fp, void *buffer)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_stat;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static int
4c174f
+method_showmanyc (FILE *fp)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_showmanyc;
4c174f
+  return shared->return_value;
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+method_imbue (FILE *fp, void *locale)
4c174f
+{
4c174f
+  log_method (fp, __func__);
4c174f
+  TEST_VERIFY (fp == shared->fp);
4c174f
+  ++shared->calls;
4c174f
+  ++shared->calls_imbue;
4c174f
+}
4c174f
+
4c174f
+/* Our custom vtable.  */
4c174f
+
4c174f
+static const struct _IO_jump_t jumps =
4c174f
+{
4c174f
+  JUMP_INIT_DUMMY,
4c174f
+  JUMP_INIT (finish, method_finish),
4c174f
+  JUMP_INIT (overflow, method_overflow),
4c174f
+  JUMP_INIT (underflow, method_underflow),
4c174f
+  JUMP_INIT (uflow, method_uflow),
4c174f
+  JUMP_INIT (pbackfail, method_pbackfail),
4c174f
+  JUMP_INIT (xsputn, method_xsputn),
4c174f
+  JUMP_INIT (xsgetn, method_xsgetn),
4c174f
+  JUMP_INIT (seekoff, method_seekoff),
4c174f
+  JUMP_INIT (seekpos, method_seekpos),
4c174f
+  JUMP_INIT (setbuf, method_setbuf),
4c174f
+  JUMP_INIT (sync, method_sync),
4c174f
+  JUMP_INIT (doallocate, method_doallocate),
4c174f
+  JUMP_INIT (read, method_read),
4c174f
+  JUMP_INIT (write, method_write),
4c174f
+  JUMP_INIT (seek, method_seek),
4c174f
+  JUMP_INIT (close, method_close),
4c174f
+  JUMP_INIT (stat, method_stat),
4c174f
+  JUMP_INIT (showmanyc, method_showmanyc),
4c174f
+  JUMP_INIT (imbue, method_imbue)
4c174f
+};
4c174f
+
4c174f
+/* Our file implementation.  */
4c174f
+
4c174f
+struct my_file
4c174f
+{
4c174f
+  FILE f;
4c174f
+  const struct _IO_jump_t *vtable;
4c174f
+};
4c174f
+
4c174f
+struct my_file
4c174f
+my_file_create (void)
4c174f
+{
4c174f
+  return (struct my_file)
4c174f
+    {
4c174f
+      /* Disable locking, so that we do not have to set up a lock
4c174f
+         pointer.  */
4c174f
+      .f._flags =  _IO_USER_LOCK,
4c174f
+
4c174f
+      /* Copy the offset from the an initialized handle, instead of
4c174f
+         figuring it out from scratch.  */
4c174f
+      .f._vtable_offset = stdin->_vtable_offset,
4c174f
+
4c174f
+      .vtable = &jumps,
4c174f
+    };
4c174f
+}
4c174f
+
4c174f
+/* Initial tests which do not enable vtable compatibility.  */
4c174f
+
4c174f
+/* Inhibit GCC optimization of fprintf.  */
4c174f
+typedef int (*fprintf_type) (FILE *, const char *, ...);
4c174f
+static const volatile fprintf_type fprintf_ptr = &fprintf;
4c174f
+
4c174f
+static void
4c174f
+without_compatibility_fprintf (void *closure)
4c174f
+{
4c174f
+  /* This call should abort.  */
4c174f
+  fprintf_ptr (shared->fp, " ");
4c174f
+  _exit (1);
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+without_compatibility_fputc (void *closure)
4c174f
+{
4c174f
+  /* This call should abort.  */
4c174f
+  fputc (' ', shared->fp);
4c174f
+  _exit (1);
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+without_compatibility_fgetc (void *closure)
4c174f
+{
4c174f
+  /* This call should abort.  */
4c174f
+  fgetc (shared->fp);
4c174f
+  _exit (1);
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+without_compatibility_fflush (void *closure)
4c174f
+{
4c174f
+  /* This call should abort.  */
4c174f
+  fflush (shared->fp);
4c174f
+  _exit (1);
4c174f
+}
4c174f
+
4c174f
+/* Exit status after abnormal termination.  */
4c174f
+static int termination_status;
4c174f
+
4c174f
+static void
4c174f
+init_termination_status (void)
4c174f
+{
4c174f
+  pid_t pid = xfork ();
4c174f
+  if (pid == 0)
4c174f
+    abort ();
4c174f
+  xwaitpid (pid, &termination_status, 0);
4c174f
+
4c174f
+  TEST_VERIFY (WIFSIGNALED (termination_status));
4c174f
+  TEST_COMPARE (WTERMSIG (termination_status), SIGABRT);
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+check_for_termination (const char *name, void (*callback) (void *))
4c174f
+{
4c174f
+  struct my_file file = my_file_create ();
4c174f
+  shared->fp = &file.f;
4c174f
+  shared->return_value = -1;
4c174f
+  shared->calls = 0;
4c174f
+  struct support_capture_subprocess proc
4c174f
+    = support_capture_subprocess (callback, NULL);
4c174f
+  support_capture_subprocess_check (&proc, name, termination_status,
4c174f
+                                    sc_allow_stderr);
4c174f
+  const char *message
4c174f
+    = "Fatal error: glibc detected an invalid stdio handle\n";
4c174f
+  TEST_COMPARE_BLOB (proc.err.buffer, proc.err.length,
4c174f
+                     message, strlen (message));
4c174f
+  TEST_COMPARE (shared->calls, 0);
4c174f
+  support_capture_subprocess_free (&proc;;
4c174f
+}
4c174f
+
4c174f
+/* The test with vtable validation disabled.  */
4c174f
+
4c174f
+/* This function does not have a prototype in libioP.h to prevent
4c174f
+   accidental use from within the library (which would disable vtable
4c174f
+   verification).  */
4c174f
+void _IO_init (FILE *fp, int flags);
4c174f
+
4c174f
+static void
4c174f
+with_compatibility_fprintf (void *closure)
4c174f
+{
4c174f
+  TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4);
4c174f
+  TEST_COMPARE (shared->calls, 3);
4c174f
+  TEST_COMPARE (shared->calls_xsputn, 3);
4c174f
+  TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length,
4c174f
+                     "CD", 2);
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+with_compatibility_fputc (void *closure)
4c174f
+{
4c174f
+  shared->return_value = '@';
4c174f
+  TEST_COMPARE (fputc ('@', shared->fp), '@');
4c174f
+  TEST_COMPARE (shared->calls, 1);
4c174f
+  TEST_COMPARE (shared->calls_overflow, 1);
4c174f
+  TEST_COMPARE (shared->value, '@');
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+with_compatibility_fgetc (void *closure)
4c174f
+{
4c174f
+  shared->return_value = 'X';
4c174f
+  TEST_COMPARE (fgetc (shared->fp), 'X');
4c174f
+  TEST_COMPARE (shared->calls, 1);
4c174f
+  TEST_COMPARE (shared->calls_uflow, 1);
4c174f
+}
4c174f
+
4c174f
+static void
4c174f
+with_compatibility_fflush (void *closure)
4c174f
+{
4c174f
+  TEST_COMPARE (fflush (shared->fp), 0);
4c174f
+  TEST_COMPARE (shared->calls, 1);
4c174f
+  TEST_COMPARE (shared->calls_sync, 1);
4c174f
+}
4c174f
+
4c174f
+/* Call CALLBACK in a subprocess, after setting up a custom file
4c174f
+   object and updating shared->fp.  */
4c174f
+static void
4c174f
+check_call (const char *name, void (*callback) (void *),
4c174f
+            bool initially_disabled)
4c174f
+{
4c174f
+  *shared = (struct shared)
4c174f
+    {
4c174f
+     .initially_disabled = initially_disabled,
4c174f
+    };
4c174f
+
4c174f
+  /* Set up a custom file object.  */
4c174f
+  struct my_file file = my_file_create ();
4c174f
+  shared->fp = &file.f;
4c174f
+  if (shared->initially_disabled)
4c174f
+    _IO_init (shared->fp, file.f._flags);
4c174f
+
4c174f
+  if (test_verbose > 0)
4c174f
+    printf ("info: calling test %s\n", name);
4c174f
+  support_isolate_in_subprocess (callback, NULL);
4c174f
+}
4c174f
+
4c174f
+/* Run the tests.  INITIALLY_DISABLED indicates whether custom vtables
4c174f
+   are disabled when the test starts.  */
4c174f
+static int
4c174f
+run_tests (bool initially_disabled)
4c174f
+{
4c174f
+  /* The test relies on fatal error messages being printed to standard
4c174f
+     error.  */
4c174f
+  setenv ("LIBC_FATAL_STDERR_", "1", 1);
4c174f
+
4c174f
+  shared = support_shared_allocate (sizeof (*shared));
4c174f
+  shared->initially_disabled = initially_disabled;
4c174f
+  init_termination_status ();
4c174f
+
4c174f
+  if (initially_disabled)
4c174f
+    {
4c174f
+      check_for_termination ("fprintf", without_compatibility_fprintf);
4c174f
+      check_for_termination ("fputc", without_compatibility_fputc);
4c174f
+      check_for_termination ("fgetc", without_compatibility_fgetc);
4c174f
+      check_for_termination ("fflush", without_compatibility_fflush);
4c174f
+    }
4c174f
+
4c174f
+  check_call ("fprintf", with_compatibility_fprintf, initially_disabled);
4c174f
+  check_call ("fputc", with_compatibility_fputc, initially_disabled);
4c174f
+  check_call ("fgetc", with_compatibility_fgetc, initially_disabled);
4c174f
+  check_call ("fflush", with_compatibility_fflush, initially_disabled);
4c174f
+
4c174f
+  support_shared_free (shared);
4c174f
+  shared = NULL;
4c174f
+
4c174f
+  return 0;
4c174f
+}
4c174f
diff --git a/libio/tst-vtables-interposed.c b/libio/tst-vtables-interposed.c
4c174f
new file mode 100644
4c174f
index 0000000000000000..c8f4e8c7c386af39
4c174f
--- /dev/null
4c174f
+++ b/libio/tst-vtables-interposed.c
4c174f
@@ -0,0 +1,37 @@
4c174f
+/* Test for libio vtables and their validation.  Enabled through interposition.
4c174f
+   Copyright (C) 2018 Free Software Foundation, Inc.
4c174f
+   This file is part of the GNU C Library.
4c174f
+
4c174f
+   The GNU C Library is free software; you can redistribute it and/or
4c174f
+   modify it under the terms of the GNU Lesser General Public
4c174f
+   License as published by the Free Software Foundation; either
4c174f
+   version 2.1 of the License, or (at your option) any later version.
4c174f
+
4c174f
+   The GNU C Library is distributed in the hope that it will be useful,
4c174f
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
4c174f
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
4c174f
+   Lesser General Public License for more details.
4c174f
+
4c174f
+   You should have received a copy of the GNU Lesser General Public
4c174f
+   License along with the GNU C Library; if not, see
4c174f
+   <http://www.gnu.org/licenses/>.  */
4c174f
+
4c174f
+/* Provide an interposed definition of the standard file handles with
4c174f
+   our own vtable.  stdout/stdin/stderr will not work as a result, but
4c174f
+   a succesful test does not print anything, so this is fine.  */
4c174f
+static const struct _IO_jump_t jumps;
4c174f
+#define _IO_file_jumps jumps
4c174f
+#include "stdfiles.c"
4c174f
+
4c174f
+#include "tst-vtables-common.c"
4c174f
+
4c174f
+static int
4c174f
+do_test (void)
4c174f
+{
4c174f
+  return run_tests (false);
4c174f
+}
4c174f
+
4c174f
+/* Calling setvbuf in the test driver is not supported with our
4c174f
+   interposed file handles.  */
4c174f
+#define TEST_NO_SETVBUF
4c174f
+#include <support/test-driver.c>
4c174f
diff --git a/libio/tst-vtables.c b/libio/tst-vtables.c
4c174f
new file mode 100644
4c174f
index 0000000000000000..f16acf5d23b0fff6
4c174f
--- /dev/null
4c174f
+++ b/libio/tst-vtables.c
4c174f
@@ -0,0 +1,29 @@
4c174f
+/* Test for libio vtables and their validation.  Initially disabled case.
4c174f
+   Copyright (C) 2018 Free Software Foundation, Inc.
4c174f
+   This file is part of the GNU C Library.
4c174f
+
4c174f
+   The GNU C Library is free software; you can redistribute it and/or
4c174f
+   modify it under the terms of the GNU Lesser General Public
4c174f
+   License as published by the Free Software Foundation; either
4c174f
+   version 2.1 of the License, or (at your option) any later version.
4c174f
+
4c174f
+   The GNU C Library is distributed in the hope that it will be useful,
4c174f
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
4c174f
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
4c174f
+   Lesser General Public License for more details.
4c174f
+
4c174f
+   You should have received a copy of the GNU Lesser General Public
4c174f
+   License along with the GNU C Library; if not, see
4c174f
+   <http://www.gnu.org/licenses/>.  */
4c174f
+
4c174f
+#include "libioP.h"
4c174f
+
4c174f
+#include "tst-vtables-common.c"
4c174f
+
4c174f
+static int
4c174f
+do_test (void)
4c174f
+{
4c174f
+  return run_tests (true);
4c174f
+}
4c174f
+
4c174f
+#include <support/test-driver.c>