Blame sysdeps/wordsize-64/tst-writev.c

Packit 6c4009
/* Copyright (C) 2011-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ryan S. Arnold <rsa@us.ibm.com>, 2011.
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
#include <fcntl.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <paths.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The purpose of this test is to verify that the INTERNAL_[V]SYSCALL_NCS
Packit 6c4009
   macros on 64-bit platforms don't cast the return type to (int) which would
Packit 6c4009
   erroneously sign extend the return value should the high bit of the bottom
Packit 6c4009
   half of the word be '1'.  */
Packit 6c4009
Packit 6c4009
#if 0
Packit 6c4009
/* Used to test the non power-of-2 code path.  */
Packit 6c4009
#undef IOV_MAX
Packit 6c4009
#define IOV_MAX 1000
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* writev() should report that it has written EXPECTED number of bytes.  */
Packit 6c4009
#define EXPECTED ((size_t) INT32_MAX + 1)
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  struct iovec iv[IOV_MAX];
Packit 6c4009
  /* POSIX doesn't guarantee that IOV_MAX is pow of 2 but we're optimistic.  */
Packit 6c4009
  size_t bufsz = EXPECTED / IOV_MAX;
Packit 6c4009
  size_t bufrem = EXPECTED % IOV_MAX;
Packit 6c4009
Packit 6c4009
  /* If there's a remainder then IOV_MAX probably isn't a power of 2 and we
Packit 6c4009
     need to make bufsz bigger so that the last iovec, iv[IOV_MAX-1], is free
Packit 6c4009
     for the remainder.  */
Packit 6c4009
  if (bufrem)
Packit 6c4009
    {
Packit 6c4009
      bufsz = bufsz + 1;
Packit 6c4009
      bufrem = EXPECTED - (bufsz * (IOV_MAX - 1));
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We writev to /dev/null since we're just testing writev's return value.  */
Packit 6c4009
  int fd = open (_PATH_DEVNULL, O_WRONLY);
Packit 6c4009
  if (fd == -1)
Packit 6c4009
    {
Packit 6c4009
      printf ("Unable to open /dev/null for writing.\n");
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  iv[0].iov_base = malloc (bufsz);
Packit 6c4009
  if (iv[0].iov_base == NULL)
Packit 6c4009
    {
Packit 6c4009
      printf ("malloc (%zu) failed.\n", bufsz);
Packit 6c4009
      close (fd);
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
  iv[0].iov_len = bufsz;
Packit 6c4009
Packit 6c4009
  /* We optimistically presume that there isn't a remainder and set all iovec
Packit 6c4009
     instances to the same base and len as the first instance.  */
Packit 6c4009
  for (int i = 1; i < IOV_MAX; i++)
Packit 6c4009
    {
Packit 6c4009
      /* We don't care what the data is so reuse the allocation from iv[0];  */
Packit 6c4009
      iv[i].iov_base = iv[0].iov_base;
Packit 6c4009
      iv[i].iov_len = iv[0].iov_len;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* If there is a remainder then we correct the last iov_len.  */
Packit 6c4009
  if (bufrem)
Packit 6c4009
    iv[IOV_MAX - 1].iov_len = bufrem;
Packit 6c4009
Packit 6c4009
  /* Write junk to /dev/null with the writev syscall in order to get a return
Packit 6c4009
     of INT32_MAX+1 bytes to verify that the INTERNAL_SYSCALL wrappers aren't
Packit 6c4009
     mangling the result if the signbit of a 32-bit number is set.  */
Packit 6c4009
  ssize_t ret = writev (fd, iv, IOV_MAX);
Packit 6c4009
Packit 6c4009
  free (iv[0].iov_base);
Packit 6c4009
  close (fd);
Packit 6c4009
Packit 6c4009
  if (ret != (ssize_t) EXPECTED)
Packit 6c4009
    {
Packit 6c4009
#ifdef ARTIFICIAL_LIMIT
Packit 6c4009
      if (ret != (ssize_t) ARTIFICIAL_LIMIT)
Packit 6c4009
#endif
Packit 6c4009
	{
Packit 6c4009
	  printf ("writev() return value: %zd != EXPECTED: %zd\n",
Packit 6c4009
		  ret, EXPECTED);
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Time enough for a large writev syscall to complete.  */
Packit 6c4009
#define TIMEOUT 20
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"