Blame string/tst-cmp.c

Packit 6c4009
/* Alignment/padding coverage test for string comparison.
Packit 6c4009
   Copyright (C) 2016-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 performs test comparisons with various (mis)alignments and
Packit 6c4009
   characters in the padding.  It is partly a regression test for bug
Packit 6c4009
   20327.  */
Packit 6c4009
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <malloc.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <libc-diag.h>
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
signum (int val)
Packit 6c4009
{
Packit 6c4009
  if (val < 0)
Packit 6c4009
    return -1;
Packit 6c4009
  if (val > 0)
Packit 6c4009
    return 1;
Packit 6c4009
  else
Packit 6c4009
    return 0;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static size_t
Packit 6c4009
max_size_t (size_t left, size_t right)
Packit 6c4009
{
Packit 6c4009
  if (left > right)
Packit 6c4009
    return left;
Packit 6c4009
  else
Packit 6c4009
    return right;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Wrappers for strncmp and strncasecmp which determine the maximum
Packit 6c4009
   string length in some, either based on the input string length, or
Packit 6c4009
   using fixed constants.  */
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
strncmp_no_terminator (const char *left, const char *right)
Packit 6c4009
{
Packit 6c4009
  size_t left_len = strlen (left);
Packit 6c4009
  size_t right_len = strlen (right);
Packit 6c4009
  return strncmp (left, right, max_size_t (left_len, right_len));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
strncasecmp_no_terminator (const char *left, const char *right)
Packit 6c4009
{
Packit 6c4009
  size_t left_len = strlen (left);
Packit 6c4009
  size_t right_len = strlen (right);
Packit 6c4009
  return strncasecmp (left, right, max_size_t (left_len, right_len));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
strncmp_terminator (const char *left, const char *right)
Packit 6c4009
{
Packit 6c4009
  size_t left_len = strlen (left);
Packit 6c4009
  size_t right_len = strlen (right);
Packit 6c4009
  return strncmp (left, right, max_size_t (left_len, right_len));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
strncasecmp_terminator (const char *left, const char *right)
Packit 6c4009
{
Packit 6c4009
  size_t left_len = strlen (left);
Packit 6c4009
  size_t right_len = strlen (right);
Packit 6c4009
  return strncasecmp (left, right, max_size_t (left_len, right_len));
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
strncmp_64 (const char *left, const char *right)
Packit 6c4009
{
Packit 6c4009
  return strncmp (left, right, 64);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
strncasecmp_64 (const char *left, const char *right)
Packit 6c4009
{
Packit 6c4009
  return strncasecmp (left, right, 64);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
strncmp_max (const char *left, const char *right)
Packit 6c4009
{
Packit 6c4009
  DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
#if __GNUC_PREREQ (7, 0)
Packit 6c4009
  /* GCC 9 warns about the size passed to strncmp being larger than
Packit 6c4009
     PTRDIFF_MAX; the use of SIZE_MAX is deliberate here.  */
Packit 6c4009
  DIAG_IGNORE_NEEDS_COMMENT (9, "-Wstringop-overflow=");
Packit 6c4009
#endif
Packit 6c4009
  return strncmp (left, right, SIZE_MAX);
Packit 6c4009
  DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
strncasecmp_max (const char *left, const char *right)
Packit 6c4009
{
Packit 6c4009
  DIAG_PUSH_NEEDS_COMMENT;
Packit 6c4009
#if __GNUC_PREREQ (7, 0)
Packit 6c4009
  /* GCC 9 warns about the size passed to strncasecmp being larger
Packit 6c4009
     than PTRDIFF_MAX; the use of SIZE_MAX is deliberate here.  */
Packit 6c4009
  DIAG_IGNORE_NEEDS_COMMENT (9, "-Wstringop-overflow=");
Packit 6c4009
#endif
Packit 6c4009
  return strncasecmp (left, right, SIZE_MAX);
Packit 6c4009
  DIAG_POP_NEEDS_COMMENT;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  enum {
Packit 6c4009
    max_align = 64,
Packit 6c4009
    max_string_length = 33
Packit 6c4009
  };
Packit 6c4009
  size_t blob_size = max_align + max_string_length + 1;
Packit 6c4009
  char *left = memalign (max_align, blob_size);
Packit 6c4009
  char *right = memalign (max_align, blob_size);
Packit 6c4009
  if (left == NULL || right == NULL)
Packit 6c4009
    {
Packit 6c4009
      printf ("error: out of memory\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  const struct
Packit 6c4009
  {
Packit 6c4009
    const char *name;
Packit 6c4009
    int (*implementation) (const char *, const char *);
Packit 6c4009
  } functions[] =
Packit 6c4009
      {
Packit 6c4009
        { "strcmp", strcmp },
Packit 6c4009
        { "strcasecmp", strcasecmp },
Packit 6c4009
        { "strncmp (without NUL)", strncmp_no_terminator},
Packit 6c4009
        { "strncasecmp (without NUL)", strncasecmp_no_terminator},
Packit 6c4009
        { "strncmp (with NUL)", strncmp_terminator},
Packit 6c4009
        { "strncasecmp (with NUL)", strncasecmp_terminator},
Packit 6c4009
        { "strncmp (length 64)", strncmp_64},
Packit 6c4009
        { "strncasecmp (length 64)", strncasecmp_64},
Packit 6c4009
        { "strncmp (length SIZE_MAX)", strncmp_max},
Packit 6c4009
        { "strncasecmp (length SIZE_MAX)", strncasecmp_max},
Packit 6c4009
        { NULL, NULL }
Packit 6c4009
      };
Packit 6c4009
  const char *const strings[] =
Packit 6c4009
    {
Packit 6c4009
      "",
Packit 6c4009
      "0",
Packit 6c4009
      "01",
Packit 6c4009
      "01234567",
Packit 6c4009
      "0123456789abcde",
Packit 6c4009
      "0123456789abcdef",
Packit 6c4009
      "0123456789abcdefg",
Packit 6c4009
      "1",
Packit 6c4009
      "10",
Packit 6c4009
      "123456789abcdef",
Packit 6c4009
      "123456789abcdefg",
Packit 6c4009
      "23456789abcdef",
Packit 6c4009
      "23456789abcdefg",
Packit 6c4009
      "abcdefghijklmnopqrstuvwxyzABCDEF",
Packit 6c4009
      NULL
Packit 6c4009
    };
Packit 6c4009
  const unsigned char pads[] =
Packit 6c4009
    { 0, 1, 32, 64, 128, '0', '1', 'e', 'f', 'g', 127, 192, 255 };
Packit 6c4009
Packit 6c4009
  bool errors = false;
Packit 6c4009
  for (int left_idx = 0; strings[left_idx] != NULL; ++left_idx)
Packit 6c4009
    for (int left_align = 0; left_align < max_align; ++left_align)
Packit 6c4009
      for (unsigned pad_left = 0; pad_left < sizeof (pads); ++pad_left)
Packit 6c4009
        {
Packit 6c4009
          memset (left, pads[pad_left], blob_size);
Packit 6c4009
          strcpy (left + left_align, strings[left_idx]);
Packit 6c4009
Packit 6c4009
          for (int right_idx = 0; strings[right_idx] != NULL; ++right_idx)
Packit 6c4009
            for (unsigned pad_right = 0; pad_right < sizeof (pads);
Packit 6c4009
                 ++pad_right)
Packit 6c4009
              for (int right_align = 0; right_align < max_align;
Packit 6c4009
                   ++right_align)
Packit 6c4009
                {
Packit 6c4009
                  memset (right, pads[pad_right], blob_size);
Packit 6c4009
                  strcpy (right + right_align, strings[right_idx]);
Packit 6c4009
Packit 6c4009
                  for (int func = 0; functions[func].name != NULL; ++func)
Packit 6c4009
                    {
Packit 6c4009
                      int expected = left_idx - right_idx;
Packit 6c4009
                      int actual = functions[func].implementation
Packit 6c4009
                        (left + left_align, right + right_align);
Packit 6c4009
                      if (signum (actual) != signum (expected))
Packit 6c4009
                        {
Packit 6c4009
                          printf ("error: mismatch for %s: %d\n"
Packit 6c4009
                                  "  left:  \"%s\"\n"
Packit 6c4009
                                  "  right: \"%s\"\n"
Packit 6c4009
                                  "  pad_left = %u, pad_right = %u,\n"
Packit 6c4009
                                  "  left_align = %d, right_align = %d\n",
Packit 6c4009
                                  functions[func].name, actual,
Packit 6c4009
                                  strings[left_idx], strings[right_idx],
Packit 6c4009
                                  pad_left, pad_right,
Packit 6c4009
                                  left_align, right_align);
Packit 6c4009
                          errors = true;
Packit 6c4009
                        }
Packit 6c4009
                    }
Packit 6c4009
                }
Packit 6c4009
        }
Packit 6c4009
  free (right);
Packit 6c4009
  free (left);
Packit 6c4009
  return errors;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* The nested loops need a long time to complete on slower
Packit 6c4009
   machines.  */
Packit 6c4009
#define TIMEOUT 600
Packit 6c4009
Packit 6c4009
#include <support/test-driver.c>