(root)/
gettext-0.22.4/
gettext-tools/
gnulib-tests/
test-memchr.c
       1  /*
       2   * Copyright (C) 2008-2023 Free Software Foundation, Inc.
       3   * Written by Eric Blake and Bruno Haible
       4   *
       5   * This program is free software: you can redistribute it and/or modify
       6   * it under the terms of the GNU General Public License as published by
       7   * the Free Software Foundation, either version 3 of the License, or
       8   * (at your option) any later version.
       9   *
      10   * This program is distributed in the hope that it will be useful,
      11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13   * GNU General Public License for more details.
      14   *
      15   * You should have received a copy of the GNU General Public License
      16   * along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <config.h>
      19  
      20  #include <string.h>
      21  
      22  #include "signature.h"
      23  SIGNATURE_CHECK (memchr, void *, (void const *, int, size_t));
      24  
      25  #include <stdlib.h>
      26  
      27  #include "zerosize-ptr.h"
      28  #include "macros.h"
      29  
      30  /* Calculating void * + int is not portable, so this wrapper converts
      31     to char * to make the tests easier to write.  */
      32  #define MEMCHR (char *) memchr
      33  
      34  int
      35  main (void)
      36  {
      37    size_t n = 0x100000;
      38    char *input = malloc (n);
      39    ASSERT (input);
      40  
      41    input[0] = 'a';
      42    input[1] = 'b';
      43    memset (input + 2, 'c', 1024);
      44    memset (input + 1026, 'd', n - 1028);
      45    input[n - 2] = 'e';
      46    input[n - 1] = 'a';
      47  
      48    /* Basic behavior tests.  */
      49    ASSERT (MEMCHR (input, 'a', n) == input);
      50  
      51    ASSERT (MEMCHR (input, 'a', 0) == NULL);
      52  
      53    {
      54      void *page_boundary = zerosize_ptr ();
      55      if (page_boundary)
      56        ASSERT (MEMCHR (page_boundary, 'a', 0) == NULL);
      57    }
      58  
      59    ASSERT (MEMCHR (input, 'b', n) == input + 1);
      60    ASSERT (MEMCHR (input, 'c', n) == input + 2);
      61    ASSERT (MEMCHR (input, 'd', n) == input + 1026);
      62  
      63    ASSERT (MEMCHR (input + 1, 'a', n - 1) == input + n - 1);
      64    ASSERT (MEMCHR (input + 1, 'e', n - 1) == input + n - 2);
      65    ASSERT (MEMCHR (input + 1, 0x789abc00 | 'e', n - 1) == input + n - 2);
      66  
      67    ASSERT (MEMCHR (input, 'f', n) == NULL);
      68    ASSERT (MEMCHR (input, '\0', n) == NULL);
      69  
      70    /* Check that a very long haystack is handled quickly if the byte is
      71       found near the beginning.  */
      72    {
      73      size_t repeat = 10000;
      74      for (; repeat > 0; repeat--)
      75        {
      76          ASSERT (MEMCHR (input, 'c', n) == input + 2);
      77        }
      78    }
      79  
      80    /* Alignment tests.  */
      81    {
      82      int i, j;
      83      for (i = 0; i < 32; i++)
      84        {
      85          for (j = 0; j < 256; j++)
      86            input[i + j] = j;
      87          for (j = 0; j < 256; j++)
      88            {
      89              ASSERT (MEMCHR (input + i, j, 256) == input + i + j);
      90            }
      91        }
      92    }
      93  
      94    /* Check that memchr() does not read past the first occurrence of the
      95       byte being searched.  See the Austin Group's clarification
      96       <https://www.opengroup.org/austin/docs/austin_454.txt>.
      97       Test both '\0' and something else, since some implementations
      98       special-case searching for NUL.
      99    */
     100    {
     101      char *page_boundary = (char *) zerosize_ptr ();
     102      /* Too small, and we miss cache line boundary tests; too large,
     103         and the test takes cubically longer to complete.  */
     104      int limit = 257;
     105  
     106      if (page_boundary != NULL)
     107        {
     108          for (n = 1; n <= limit; n++)
     109            {
     110              char *mem = page_boundary - n;
     111              memset (mem, 'X', n);
     112              ASSERT (MEMCHR (mem, 'U', n) == NULL);
     113              ASSERT (MEMCHR (mem, 0, n) == NULL);
     114  
     115              {
     116                size_t i;
     117                size_t k;
     118  
     119                for (i = 0; i < n; i++)
     120                  {
     121                    mem[i] = 'U';
     122                    for (k = i + 1; k < n + limit; k++)
     123                      ASSERT (MEMCHR (mem, 'U', k) == mem + i);
     124                    mem[i] = 0;
     125                    for (k = i + 1; k < n + limit; k++)
     126                      ASSERT (MEMCHR (mem, 0, k) == mem + i);
     127                    mem[i] = 'X';
     128                  }
     129              }
     130            }
     131        }
     132    }
     133  
     134    free (input);
     135  
     136    return 0;
     137  }