Blame timezone/tst-tzset.c

Packit 6c4009
/* tzset tests with crafted time zone data.
Packit 6c4009
   Copyright (C) 2015-2018 Free Software Foundation, Inc.
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
#define _GNU_SOURCE 1
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <sys/resource.h>
Packit 6c4009
#include <time.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
Packit 6c4009
#define TIMEOUT 5
Packit 6c4009
static int do_test (void);
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"
Packit 6c4009
Packit 6c4009
/* Returns the name of a large TZ file.  */
Packit 6c4009
static char *
Packit 6c4009
create_tz_file (off64_t size)
Packit 6c4009
{
Packit 6c4009
  char *path;
Packit 6c4009
  int fd = create_temp_file ("tst-tzset-", &path);
Packit 6c4009
  if (fd < 0)
Packit 6c4009
    exit (1);
Packit 6c4009
Packit 6c4009
  // Reopen for large-file support.
Packit 6c4009
  close (fd);
Packit 6c4009
  fd = open64 (path, O_WRONLY);
Packit 6c4009
  if (fd < 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("open64 (%s) failed: %m\n", path);
Packit 6c4009
      exit (1);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  static const char data[] = {
Packit 6c4009
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
Packit 6c4009
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
Packit 6c4009
    0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x58, 0x54, 0x47, 0x00, 0x00, 0x00,
Packit 6c4009
    0x54, 0x5a, 0x69, 0x66, 0x32, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
Packit 6c4009
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01,
Packit 6c4009
    0x00, 0x00, 0x00, 0x04, 0xf8, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Packit 6c4009
    0x00, 0x00, 0x00, 0x58, 0x54, 0x47, 0x00, 0x00,
Packit 6c4009
    0x00, 0x0a, 0x58, 0x54, 0x47, 0x30, 0x0a
Packit 6c4009
  };
Packit 6c4009
  ssize_t ret = write (fd, data, sizeof (data));
Packit 6c4009
  if (ret < 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("write failed: %m\n");
Packit 6c4009
      exit (1);
Packit 6c4009
    }
Packit 6c4009
  if ((size_t) ret != sizeof (data))
Packit 6c4009
    {
Packit 6c4009
      printf ("Short write\n");
Packit 6c4009
      exit (1);
Packit 6c4009
    }
Packit 6c4009
  if (lseek64 (fd, size, SEEK_CUR) < 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("lseek failed: %m\n");
Packit 6c4009
      close (fd);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  if (write (fd, "", 1) != 1)
Packit 6c4009
    {
Packit 6c4009
      printf ("Single-byte write failed\n");
Packit 6c4009
      close (fd);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
  if (close (fd) != 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("close failed: %m\n");
Packit 6c4009
      exit (1);
Packit 6c4009
    }
Packit 6c4009
  return path;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
test_tz_file (off64_t size)
Packit 6c4009
{
Packit 6c4009
  char *path = create_tz_file (size);
Packit 6c4009
  if (setenv ("TZ", path, 1) < 0)
Packit 6c4009
    {
Packit 6c4009
      printf ("setenv failed: %m\n");
Packit 6c4009
      exit (1);
Packit 6c4009
    }
Packit 6c4009
  tzset ();
Packit 6c4009
  free (path);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  /* Limit the size of the process.  Otherwise, some of the tests will
Packit 6c4009
     consume a lot of resources.  */
Packit 6c4009
  {
Packit 6c4009
    struct rlimit limit;
Packit 6c4009
    if (getrlimit (RLIMIT_AS, &limit) != 0)
Packit 6c4009
      {
Packit 6c4009
	printf ("getrlimit (RLIMIT_AS) failed: %m\n");
Packit 6c4009
	return 1;
Packit 6c4009
      }
Packit 6c4009
    long target = 512 * 1024 * 1024;
Packit 6c4009
    if (limit.rlim_cur == RLIM_INFINITY || limit.rlim_cur > target)
Packit 6c4009
      {
Packit 6c4009
	limit.rlim_cur = 512 * 1024 * 1024;
Packit 6c4009
	if (setrlimit (RLIMIT_AS, &limit) != 0)
Packit 6c4009
	  {
Packit 6c4009
	    printf ("setrlimit (RLIMIT_AS) failed: %m\n");
Packit 6c4009
	    return 1;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  int errors = 0;
Packit 6c4009
  for (int i = 1; i <= 4; ++i)
Packit 6c4009
    {
Packit 6c4009
      char tz[16];
Packit 6c4009
      snprintf (tz, sizeof (tz), "XT%d", i);
Packit 6c4009
      if (setenv ("TZ", tz, 1) < 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("setenv failed: %m\n");
Packit 6c4009
	  return 1;
Packit 6c4009
	}
Packit 6c4009
      tzset ();
Packit 6c4009
      if (strcmp (tzname[0], tz) == 0)
Packit 6c4009
	{
Packit 6c4009
	  printf ("Unexpected success for %s\n", tz);
Packit 6c4009
	  ++errors;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Large TZ files.  */
Packit 6c4009
Packit 6c4009
  /* This will succeed on 64-bit architectures, and fail on 32-bit
Packit 6c4009
     architectures.  It used to crash on 32-bit.  */
Packit 6c4009
  test_tz_file (64 * 1024 * 1024);
Packit 6c4009
Packit 6c4009
  /* This will fail on 64-bit and 32-bit architectures.  It used to
Packit 6c4009
     cause a test timeout on 64-bit and crash on 32-bit if the TZ file
Packit 6c4009
     open succeeded for some reason (it does not use O_LARGEFILE in
Packit 6c4009
     regular builds).  */
Packit 6c4009
  test_tz_file (4LL * 1024 * 1024 * 1024 - 6);
Packit 6c4009
Packit 6c4009
  /* Large TZ variables.  */
Packit 6c4009
  {
Packit 6c4009
    size_t length = 64 * 1024 * 1024;
Packit 6c4009
    char *value = malloc (length + 1);
Packit 6c4009
    if (value == NULL)
Packit 6c4009
      {
Packit 6c4009
	puts ("malloc failed: %m");
Packit 6c4009
	return 1;
Packit 6c4009
      }
Packit 6c4009
    value[length] = '\0';
Packit 6c4009
Packit 6c4009
    memset (value, ' ', length);
Packit 6c4009
    value[0] = 'U';
Packit 6c4009
    value[1] = 'T';
Packit 6c4009
    value[2] = 'C';
Packit 6c4009
    if (setenv ("TZ", value, 1) < 0)
Packit 6c4009
      {
Packit 6c4009
	printf ("setenv failed: %m\n");
Packit 6c4009
	return 1;
Packit 6c4009
      }
Packit 6c4009
    tzset ();
Packit 6c4009
Packit 6c4009
    memset (value, '0', length);
Packit 6c4009
    value[0] = '<';
Packit 6c4009
    value[length - 1] = '>';
Packit 6c4009
    if (setenv ("TZ", value, 1) < 0)
Packit 6c4009
      {
Packit 6c4009
	printf ("setenv failed: %m\n");
Packit 6c4009
	return 1;
Packit 6c4009
      }
Packit 6c4009
    tzset ();
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
  return errors > 0;
Packit 6c4009
}