|
Packit |
6c4009 |
/* Test for libio vtables and their validation. Common code.
|
|
Packit |
6c4009 |
Copyright (C) 2018 Free Software Foundation, Inc.
|
|
Packit |
6c4009 |
This file is part of the GNU C Library.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is free software; you can redistribute it and/or
|
|
Packit |
6c4009 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License as published by the Free Software Foundation; either
|
|
Packit |
6c4009 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is distributed in the hope that it will be useful,
|
|
Packit |
6c4009 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6c4009 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6c4009 |
Lesser General Public License for more details.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License along with the GNU C Library; if not, see
|
|
Packit |
6c4009 |
<http://www.gnu.org/licenses/>. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* This test provides some coverage for how various stdio functions
|
|
Packit |
6c4009 |
use the vtables in FILE * objects. The focus is mostly on which
|
|
Packit |
6c4009 |
functions call which methods, not so much on validating data
|
|
Packit |
6c4009 |
processing. An initial series of tests check that custom vtables
|
|
Packit |
6c4009 |
do not work without activation through _IO_init.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
Note: libio vtables are deprecated feature. Do not use this test
|
|
Packit |
6c4009 |
as a documentation source for writing custom vtables. See
|
|
Packit |
6c4009 |
fopencookie for a different way of creating custom stdio
|
|
Packit |
6c4009 |
streams. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#include <stdbool.h>
|
|
Packit |
6c4009 |
#include <string.h>
|
|
Packit |
6c4009 |
#include <support/capture_subprocess.h>
|
|
Packit |
6c4009 |
#include <support/check.h>
|
|
Packit |
6c4009 |
#include <support/namespace.h>
|
|
Packit |
6c4009 |
#include <support/support.h>
|
|
Packit |
6c4009 |
#include <support/test-driver.h>
|
|
Packit |
6c4009 |
#include <support/xunistd.h>
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#include "libioP.h"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Data shared between the test subprocess and the test driver in the
|
|
Packit |
6c4009 |
parent. Note that *shared is reset at the start of the check_call
|
|
Packit |
6c4009 |
function. */
|
|
Packit |
6c4009 |
struct shared
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* Expected file pointer for method calls. */
|
|
Packit |
6c4009 |
FILE *fp;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* If true, assume that a call to _IO_init is needed to enable
|
|
Packit |
6c4009 |
custom vtables. */
|
|
Packit |
6c4009 |
bool initially_disabled;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Requested return value for the methods which have one. */
|
|
Packit |
6c4009 |
int return_value;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* A value (usually a character) recorded by some of the methods
|
|
Packit |
6c4009 |
below. */
|
|
Packit |
6c4009 |
int value;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Likewise, for some data. */
|
|
Packit |
6c4009 |
char buffer[16];
|
|
Packit |
6c4009 |
size_t buffer_length;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Total number of method calls. */
|
|
Packit |
6c4009 |
unsigned int calls;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Individual method call counts. */
|
|
Packit |
6c4009 |
unsigned int calls_finish;
|
|
Packit |
6c4009 |
unsigned int calls_overflow;
|
|
Packit |
6c4009 |
unsigned int calls_underflow;
|
|
Packit |
6c4009 |
unsigned int calls_uflow;
|
|
Packit |
6c4009 |
unsigned int calls_pbackfail;
|
|
Packit |
6c4009 |
unsigned int calls_xsputn;
|
|
Packit |
6c4009 |
unsigned int calls_xsgetn;
|
|
Packit |
6c4009 |
unsigned int calls_seekoff;
|
|
Packit |
6c4009 |
unsigned int calls_seekpos;
|
|
Packit |
6c4009 |
unsigned int calls_setbuf;
|
|
Packit |
6c4009 |
unsigned int calls_sync;
|
|
Packit |
6c4009 |
unsigned int calls_doallocate;
|
|
Packit |
6c4009 |
unsigned int calls_read;
|
|
Packit |
6c4009 |
unsigned int calls_write;
|
|
Packit |
6c4009 |
unsigned int calls_seek;
|
|
Packit |
6c4009 |
unsigned int calls_close;
|
|
Packit |
6c4009 |
unsigned int calls_stat;
|
|
Packit |
6c4009 |
unsigned int calls_showmanyc;
|
|
Packit |
6c4009 |
unsigned int calls_imbue;
|
|
Packit |
6c4009 |
} *shared;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Method implementations which increment the counters in *shared. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
log_method (FILE *fp, const char *name)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (test_verbose > 0)
|
|
Packit |
6c4009 |
printf ("info: %s (%p) called\n", name, fp);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
method_finish (FILE *fp, int dummy)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_finish;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_overflow (FILE *fp, int ch)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_overflow;
|
|
Packit |
6c4009 |
shared->value = ch;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_underflow (FILE *fp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_underflow;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_uflow (FILE *fp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_uflow;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_pbackfail (FILE *fp, int ch)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_pbackfail;
|
|
Packit |
6c4009 |
shared->value = ch;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static size_t
|
|
Packit |
6c4009 |
method_xsputn (FILE *fp, const void *data, size_t n)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_xsputn;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
size_t to_copy = n;
|
|
Packit |
6c4009 |
if (n > sizeof (shared->buffer))
|
|
Packit |
6c4009 |
to_copy = sizeof (shared->buffer);
|
|
Packit |
6c4009 |
memcpy (shared->buffer, data, to_copy);
|
|
Packit |
6c4009 |
shared->buffer_length = to_copy;
|
|
Packit |
6c4009 |
return to_copy;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static size_t
|
|
Packit |
6c4009 |
method_xsgetn (FILE *fp, void *data, size_t n)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_xsgetn;
|
|
Packit |
6c4009 |
return 0;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static off64_t
|
|
Packit |
6c4009 |
method_seekoff (FILE *fp, off64_t offset, int dir, int mode)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_seekoff;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static off64_t
|
|
Packit |
6c4009 |
method_seekpos (FILE *fp, off64_t offset, int mode)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_seekpos;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static FILE *
|
|
Packit |
6c4009 |
method_setbuf (FILE *fp, char *buffer, ssize_t length)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_setbuf;
|
|
Packit |
6c4009 |
return fp;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_sync (FILE *fp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_sync;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_doallocate (FILE *fp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_doallocate;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static ssize_t
|
|
Packit |
6c4009 |
method_read (FILE *fp, void *data, ssize_t length)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_read;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static ssize_t
|
|
Packit |
6c4009 |
method_write (FILE *fp, const void *data, ssize_t length)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_write;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static off64_t
|
|
Packit |
6c4009 |
method_seek (FILE *fp, off64_t offset, int mode)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_seek;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_close (FILE *fp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_close;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_stat (FILE *fp, void *buffer)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_stat;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
method_showmanyc (FILE *fp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_showmanyc;
|
|
Packit |
6c4009 |
return shared->return_value;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
method_imbue (FILE *fp, void *locale)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
log_method (fp, __func__);
|
|
Packit |
6c4009 |
TEST_VERIFY (fp == shared->fp);
|
|
Packit |
6c4009 |
++shared->calls;
|
|
Packit |
6c4009 |
++shared->calls_imbue;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Our custom vtable. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static const struct _IO_jump_t jumps =
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
JUMP_INIT_DUMMY,
|
|
Packit |
6c4009 |
JUMP_INIT (finish, method_finish),
|
|
Packit |
6c4009 |
JUMP_INIT (overflow, method_overflow),
|
|
Packit |
6c4009 |
JUMP_INIT (underflow, method_underflow),
|
|
Packit |
6c4009 |
JUMP_INIT (uflow, method_uflow),
|
|
Packit |
6c4009 |
JUMP_INIT (pbackfail, method_pbackfail),
|
|
Packit |
6c4009 |
JUMP_INIT (xsputn, method_xsputn),
|
|
Packit |
6c4009 |
JUMP_INIT (xsgetn, method_xsgetn),
|
|
Packit |
6c4009 |
JUMP_INIT (seekoff, method_seekoff),
|
|
Packit |
6c4009 |
JUMP_INIT (seekpos, method_seekpos),
|
|
Packit |
6c4009 |
JUMP_INIT (setbuf, method_setbuf),
|
|
Packit |
6c4009 |
JUMP_INIT (sync, method_sync),
|
|
Packit |
6c4009 |
JUMP_INIT (doallocate, method_doallocate),
|
|
Packit |
6c4009 |
JUMP_INIT (read, method_read),
|
|
Packit |
6c4009 |
JUMP_INIT (write, method_write),
|
|
Packit |
6c4009 |
JUMP_INIT (seek, method_seek),
|
|
Packit |
6c4009 |
JUMP_INIT (close, method_close),
|
|
Packit |
6c4009 |
JUMP_INIT (stat, method_stat),
|
|
Packit |
6c4009 |
JUMP_INIT (showmanyc, method_showmanyc),
|
|
Packit |
6c4009 |
JUMP_INIT (imbue, method_imbue)
|
|
Packit |
6c4009 |
};
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Our file implementation. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
struct my_file
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
FILE f;
|
|
Packit |
6c4009 |
const struct _IO_jump_t *vtable;
|
|
Packit |
6c4009 |
};
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
struct my_file
|
|
Packit |
6c4009 |
my_file_create (void)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
return (struct my_file)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* Disable locking, so that we do not have to set up a lock
|
|
Packit |
6c4009 |
pointer. */
|
|
Packit |
6c4009 |
.f._flags = _IO_USER_LOCK,
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Copy the offset from the an initialized handle, instead of
|
|
Packit |
6c4009 |
figuring it out from scratch. */
|
|
Packit |
6c4009 |
.f._vtable_offset = stdin->_vtable_offset,
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
.vtable = &jumps,
|
|
Packit |
6c4009 |
};
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Initial tests which do not enable vtable compatibility. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Inhibit GCC optimization of fprintf. */
|
|
Packit |
6c4009 |
typedef int (*fprintf_type) (FILE *, const char *, ...);
|
|
Packit |
6c4009 |
static const volatile fprintf_type fprintf_ptr = &fprintf;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
without_compatibility_fprintf (void *closure)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* This call should abort. */
|
|
Packit |
6c4009 |
fprintf_ptr (shared->fp, " ");
|
|
Packit |
6c4009 |
_exit (1);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
without_compatibility_fputc (void *closure)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* This call should abort. */
|
|
Packit |
6c4009 |
fputc (' ', shared->fp);
|
|
Packit |
6c4009 |
_exit (1);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
without_compatibility_fgetc (void *closure)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* This call should abort. */
|
|
Packit |
6c4009 |
fgetc (shared->fp);
|
|
Packit |
6c4009 |
_exit (1);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
without_compatibility_fflush (void *closure)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* This call should abort. */
|
|
Packit |
6c4009 |
fflush (shared->fp);
|
|
Packit |
6c4009 |
_exit (1);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Exit status after abnormal termination. */
|
|
Packit |
6c4009 |
static int termination_status;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
init_termination_status (void)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
pid_t pid = xfork ();
|
|
Packit |
6c4009 |
if (pid == 0)
|
|
Packit |
6c4009 |
abort ();
|
|
Packit |
6c4009 |
xwaitpid (pid, &termination_status, 0);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
TEST_VERIFY (WIFSIGNALED (termination_status));
|
|
Packit |
6c4009 |
TEST_COMPARE (WTERMSIG (termination_status), SIGABRT);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
check_for_termination (const char *name, void (*callback) (void *))
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct my_file file = my_file_create ();
|
|
Packit |
6c4009 |
shared->fp = &file.f;
|
|
Packit |
6c4009 |
shared->return_value = -1;
|
|
Packit |
6c4009 |
shared->calls = 0;
|
|
Packit |
6c4009 |
struct support_capture_subprocess proc
|
|
Packit |
6c4009 |
= support_capture_subprocess (callback, NULL);
|
|
Packit |
6c4009 |
support_capture_subprocess_check (&proc, name, termination_status,
|
|
Packit |
6c4009 |
sc_allow_stderr);
|
|
Packit |
6c4009 |
const char *message
|
|
Packit |
6c4009 |
= "Fatal error: glibc detected an invalid stdio handle\n";
|
|
Packit |
6c4009 |
TEST_COMPARE_BLOB (proc.err.buffer, proc.err.length,
|
|
Packit |
6c4009 |
message, strlen (message));
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls, 0);
|
|
Packit |
6c4009 |
support_capture_subprocess_free (&proc;;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* The test with vtable validation disabled. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* This function does not have a prototype in libioP.h to prevent
|
|
Packit |
6c4009 |
accidental use from within the library (which would disable vtable
|
|
Packit |
6c4009 |
verification). */
|
|
Packit |
6c4009 |
void _IO_init (FILE *fp, int flags);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
with_compatibility_fprintf (void *closure)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
TEST_COMPARE (fprintf_ptr (shared->fp, "A%sCD", "B"), 4);
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls, 3);
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls_xsputn, 3);
|
|
Packit |
6c4009 |
TEST_COMPARE_BLOB (shared->buffer, shared->buffer_length,
|
|
Packit |
6c4009 |
"CD", 2);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
with_compatibility_fputc (void *closure)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
shared->return_value = '@';
|
|
Packit |
6c4009 |
TEST_COMPARE (fputc ('@', shared->fp), '@');
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls, 1);
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls_overflow, 1);
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->value, '@');
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
with_compatibility_fgetc (void *closure)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
shared->return_value = 'X';
|
|
Packit |
6c4009 |
TEST_COMPARE (fgetc (shared->fp), 'X');
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls, 1);
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls_uflow, 1);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
with_compatibility_fflush (void *closure)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
TEST_COMPARE (fflush (shared->fp), 0);
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls, 1);
|
|
Packit |
6c4009 |
TEST_COMPARE (shared->calls_sync, 1);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Call CALLBACK in a subprocess, after setting up a custom file
|
|
Packit |
6c4009 |
object and updating shared->fp. */
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
check_call (const char *name, void (*callback) (void *),
|
|
Packit |
6c4009 |
bool initially_disabled)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
*shared = (struct shared)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
.initially_disabled = initially_disabled,
|
|
Packit |
6c4009 |
};
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Set up a custom file object. */
|
|
Packit |
6c4009 |
struct my_file file = my_file_create ();
|
|
Packit |
6c4009 |
shared->fp = &file.f;
|
|
Packit |
6c4009 |
if (shared->initially_disabled)
|
|
Packit |
6c4009 |
_IO_init (shared->fp, file.f._flags);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (test_verbose > 0)
|
|
Packit |
6c4009 |
printf ("info: calling test %s\n", name);
|
|
Packit |
6c4009 |
support_isolate_in_subprocess (callback, NULL);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Run the tests. INITIALLY_DISABLED indicates whether custom vtables
|
|
Packit |
6c4009 |
are disabled when the test starts. */
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
run_tests (bool initially_disabled)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* The test relies on fatal error messages being printed to standard
|
|
Packit |
6c4009 |
error. */
|
|
Packit |
6c4009 |
setenv ("LIBC_FATAL_STDERR_", "1", 1);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
shared = support_shared_allocate (sizeof (*shared));
|
|
Packit |
6c4009 |
shared->initially_disabled = initially_disabled;
|
|
Packit |
6c4009 |
init_termination_status ();
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (initially_disabled)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
check_for_termination ("fprintf", without_compatibility_fprintf);
|
|
Packit |
6c4009 |
check_for_termination ("fputc", without_compatibility_fputc);
|
|
Packit |
6c4009 |
check_for_termination ("fgetc", without_compatibility_fgetc);
|
|
Packit |
6c4009 |
check_for_termination ("fflush", without_compatibility_fflush);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
check_call ("fprintf", with_compatibility_fprintf, initially_disabled);
|
|
Packit |
6c4009 |
check_call ("fputc", with_compatibility_fputc, initially_disabled);
|
|
Packit |
6c4009 |
check_call ("fgetc", with_compatibility_fgetc, initially_disabled);
|
|
Packit |
6c4009 |
check_call ("fflush", with_compatibility_fflush, initially_disabled);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
support_shared_free (shared);
|
|
Packit |
6c4009 |
shared = NULL;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return 0;
|
|
Packit |
6c4009 |
}
|