(root)/
glibc-2.38/
string/
test-strcmp.c
       1  /* Test and measure strcmp and wcscmp functions.
       2     Copyright (C) 1999-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library 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 GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #define TEST_LEN (getpagesize () * 3)
      20  #define MIN_PAGE_SIZE (TEST_LEN + 2 * getpagesize ())
      21  
      22  #define TEST_MAIN
      23  #ifdef WIDE
      24  # define TEST_NAME "wcscmp"
      25  #else
      26  # define TEST_NAME "strcmp"
      27  #endif
      28  #include "test-string.h"
      29  #include <support/test-driver.h>
      30  
      31  #ifdef WIDE
      32  # include <wchar.h>
      33  
      34  # define L(str) L##str
      35  # define STRCMP wcscmp
      36  # define STRCPY wcscpy
      37  # define STRLEN wcslen
      38  # define MEMCPY wmemcpy
      39  # define SIMPLE_STRCMP simple_wcscmp
      40  # define CHAR wchar_t
      41  # define UCHAR wchar_t
      42  # define CHARBYTES 4
      43  # define CHARBYTESLOG 2
      44  # define CHARALIGN __alignof__ (CHAR)
      45  # define MIDCHAR 0x7fffffff
      46  # define LARGECHAR 0xfffffffe
      47  # define CHAR__MAX WCHAR_MAX
      48  # define CHAR__MIN WCHAR_MIN
      49  
      50  /* Wcscmp uses signed semantics for comparison, not unsigned */
      51  /* Avoid using subtraction since possible overflow */
      52  
      53  int
      54  simple_wcscmp (const wchar_t *s1, const wchar_t *s2)
      55  {
      56    wchar_t c1, c2;
      57    do
      58      {
      59        c1 = *s1++;
      60        c2 = *s2++;
      61        if (c2 == L'\0')
      62        return c1 - c2;
      63      }
      64    while (c1 == c2);
      65  
      66    return c1 < c2 ? -1 : 1;
      67  }
      68  
      69  #else
      70  # include <limits.h>
      71  
      72  # define L(str) str
      73  # define STRCMP strcmp
      74  # define STRCPY strcpy
      75  # define STRLEN strlen
      76  # define MEMCPY memcpy
      77  # define SIMPLE_STRCMP simple_strcmp
      78  # define CHAR char
      79  # define UCHAR unsigned char
      80  # define CHARBYTES 1
      81  # define CHARBYTESLOG 0
      82  # define CHARALIGN 1
      83  # define MIDCHAR 0x7f
      84  # define LARGECHAR 0xfe
      85  # define CHAR__MAX CHAR_MAX
      86  # define CHAR__MIN CHAR_MIN
      87  
      88  /* Strcmp uses unsigned semantics for comparison. */
      89  int
      90  simple_strcmp (const char *s1, const char *s2)
      91  {
      92    int ret;
      93  
      94    while ((ret = *(unsigned char *) s1 - *(unsigned char*) s2++) == 0 && *s1++);
      95    return ret;
      96  }
      97  
      98  #endif
      99  
     100  typedef int (*proto_t) (const CHAR *, const CHAR *);
     101  
     102  IMPL (STRCMP, 1)
     103  
     104  /* Also check the default implementation.  */
     105  #undef STRCMP
     106  #undef libc_hidden_builtin_def
     107  #define libc_hidden_builtin_def(a)
     108  #undef libc_hidden_def
     109  #define libc_hidden_def(a)
     110  #undef weak_alias
     111  #define weak_alias(a, b)
     112  #undef attribute_hidden
     113  #define attribute_hidden
     114  #ifndef WIDE
     115  # define STRCMP __strcmp_default
     116  # include "string/strcmp.c"
     117  # define STRCMP_DEFAULT STRCMP
     118  #else
     119  # define WCSCMP __wcscmp_default
     120  # include "wcsmbs/wcscmp.c"
     121  # define STRCMP_DEFAULT WCSCMP
     122  #endif
     123  IMPL (STRCMP_DEFAULT, 1)
     124  
     125  
     126  static int
     127  check_result (impl_t *impl,
     128  	     const CHAR *s1, const CHAR *s2,
     129  	     int exp_result)
     130  {
     131    int result = CALL (impl, s1, s2);
     132    if ((exp_result == 0 && result != 0)
     133        || (exp_result < 0 && result >= 0)
     134        || (exp_result > 0 && result <= 0))
     135      {
     136        error (0, 0, "Wrong result in function %s %d %d", impl->name,
     137  	     result, exp_result);
     138        ret = 1;
     139        return -1;
     140      }
     141  
     142    return 0;
     143  }
     144  
     145  static void
     146  do_one_test (impl_t *impl,
     147  	     const CHAR *s1, const CHAR *s2,
     148  	     int exp_result)
     149  {
     150    if (check_result (impl, s1, s2, exp_result) < 0)
     151      return;
     152  }
     153  
     154  static void
     155  do_test (size_t align1, size_t align2, size_t len, int max_char,
     156           int exp_result)
     157  {
     158    size_t i;
     159  
     160    CHAR *s1, *s2;
     161  
     162    if (len == 0)
     163      return;
     164  
     165    align1 &= ~(CHARBYTES - 1);
     166    align2 &= ~(CHARBYTES - 1);
     167  
     168    align1 &= getpagesize () - 1;
     169    if (align1 + (len + 1) * CHARBYTES >= page_size)
     170      return;
     171  
     172    align2 &= getpagesize () - 1;
     173    if (align2 + (len + 1) * CHARBYTES >= page_size)
     174      return;
     175  
     176    /* Put them close to the end of page.  */
     177    i = align1 + CHARBYTES * (len + 2);
     178    s1 = (CHAR *)(buf1 + ((page_size - i) / 16 * 16) + align1);
     179    i = align2 + CHARBYTES * (len + 2);
     180    s2 = (CHAR *)(buf2 + ((page_size - i) / 16 * 16) + align2);
     181  
     182    for (i = 0; i < len; i++)
     183      s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % max_char;
     184  
     185    s1[len] = s2[len] = 0;
     186    s1[len + 1] = 23;
     187    s2[len + 1] = 24 + exp_result;
     188    s2[len - 1] -= exp_result;
     189  
     190    FOR_EACH_IMPL (impl, 0)
     191    do_one_test (impl, s1, s2, exp_result);
     192  }
     193  
     194  
     195  static void
     196  do_random_tests (void)
     197  {
     198  	UCHAR *p1 = (UCHAR *) (buf1 + page_size - 512 * CHARBYTES);
     199  	UCHAR *p2 = (UCHAR *) (buf2 + page_size - 512 * CHARBYTES);
     200  
     201  	for (size_t n = 0; n < ITERATIONS; n++)
     202  	  {
     203  	    /* for wcscmp case align1 and align2 mean here alignment
     204  	       in wchar_t symbols, it equal 4*k alignment in bytes, we
     205  	       don't check other alignments like for example
     206  	       p1 = (wchar_t *)(buf1 + 1)
     207  	       because it's wrong using of wchar_t type.  */
     208  	    size_t align1 = random () & 31;
     209  	    size_t align2;
     210  	    if (random () & 1)
     211  	      align2 = random () & 31;
     212  	    else
     213  	      align2 = align1 + (random () & 24);
     214  	    size_t pos = random () & 511;
     215  	    size_t j = align1 > align2 ? align1 : align2;
     216  	    if (pos + j >= 511)
     217  	      pos = 510 - j - (random () & 7);
     218  	    size_t len1 = random () & 511;
     219  	    if (pos >= len1 && (random () & 1))
     220  	      len1 = pos + (random () & 7);
     221  	    if (len1 + j >= 512)
     222  	      len1 = 511 - j - (random () & 7);
     223  	    size_t len2;
     224  	    if (pos >= len1)
     225  	      len2 = len1;
     226  	    else
     227  	      len2 = len1 + (len1 != 511 - j ? random () % (511 - j - len1) : 0);
     228  	    j = (pos > len2 ? pos : len2) + align1 + 64;
     229  	    if (j > 512)
     230  	      j = 512;
     231  	    for (size_t i = 0; i < j; ++i)
     232  	      {
     233  		p1[i] = random () & 255;
     234  		if (i < len1 + align1 && !p1[i])
     235  		  {
     236  		    p1[i] = random () & 255;
     237  		    if (!p1[i])
     238  		      p1[i] = 1 + (random () & 127);
     239  		  }
     240  	      }
     241  	    for (size_t i = 0; i < j; ++i)
     242  	      {
     243  		p2[i] = random () & 255;
     244  		if (i < len2 + align2 && !p2[i])
     245  		  {
     246  		    p2[i] = random () & 255;
     247  		    if (!p2[i])
     248  		      p2[i] = 1 + (random () & 127);
     249  		  }
     250  	      }
     251  
     252  	    int result = 0;
     253  	    MEMCPY (p2 + align2, p1 + align1, pos);
     254  	    if (pos < len1)
     255  	      {
     256  		if (p2[align2 + pos] == p1[align1 + pos])
     257  		  {
     258  		    p2[align2 + pos] = random () & 255;
     259  		    if (p2[align2 + pos] == p1[align1 + pos])
     260  		      p2[align2 + pos] = p1[align1 + pos] + 3 + (random () & 127);
     261  		  }
     262  
     263  		if (p1[align1 + pos] < p2[align2 + pos])
     264  		  result = -1;
     265  		else
     266  		  result = 1;
     267  	      }
     268  	    p1[len1 + align1] = 0;
     269  	    p2[len2 + align2] = 0;
     270  
     271  	    FOR_EACH_IMPL (impl, 1)
     272  	      {
     273  		int r = CALL (impl, (CHAR *) (p1 + align1), (CHAR *) (p2 + align2));
     274  		/* Test whether on 64-bit architectures where ABI requires
     275  		   callee to promote has the promotion been done.  */
     276  		asm ("" : "=g" (r) : "0" (r));
     277  		if ((r == 0 && result)
     278  		    || (r < 0 && result >= 0)
     279  		    || (r > 0 && result <= 0))
     280  		  {
     281  		    error (0, 0, "Iteration %zd - wrong result in function %s (align in bytes: %zd, align in bytes: %zd, len1:  %zd, len2: %zd, pos: %zd) %d != %d, p1 %p p2 %p",
     282  			   n, impl->name, (size_t) (p1 + align1) & 63, (size_t) (p1 + align2) & 63, len1, len2, pos, r, result, p1, p2);
     283  		    ret = 1;
     284  		  }
     285  	      }
     286       }
     287  }
     288  
     289  static void
     290  check (void)
     291  {
     292    CHAR *s1 = (CHAR *) (buf1 + 0xb2c);
     293    CHAR *s2 = (CHAR *) (buf1 + 0xfd8);
     294  
     295    STRCPY(s1, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs"));
     296    STRCPY(s2, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV"));
     297  
     298    /* Check correct working for negatives values */
     299  
     300    s1[0] = 1;
     301    s2[0] = 1;
     302    s1[1] = 1;
     303    s2[1] = 1;
     304    s1[2] = -1;
     305    s2[2] = 3;
     306    s1[3] = 0;
     307    s2[3] = -1;
     308  
     309    /* Check possible overflow bug, actual more for wcscmp */
     310  
     311    s1[7] = CHAR__MIN;
     312    s2[7] = CHAR__MAX;
     313  
     314    size_t l1 = STRLEN (s1);
     315    size_t l2 = STRLEN (s2);
     316  
     317    for (size_t i1 = 0; i1 < l1; i1++)
     318      for (size_t i2 = 0; i2 < l2; i2++)
     319        {
     320  		int exp_result = SIMPLE_STRCMP (s1 + i1, s2 + i2);
     321  		FOR_EACH_IMPL (impl, 0)
     322  		check_result (impl, s1 + i1, s2 + i2, exp_result);
     323        }
     324  
     325    /* Test cases where there are multiple zero bytes after the first.  */
     326  
     327    for (size_t i = 0; i < 16 + 1; i++)
     328      {
     329        s1[i] = 0x00;
     330        s2[i] = 0x00;
     331      }
     332  
     333    for (size_t i = 0; i < 16; i++)
     334      {
     335        int exp_result;
     336  
     337        for (int val = 0x01; val < 0x100; val++)
     338  	{
     339  	  for (size_t j = 0; j < i; j++)
     340  	    {
     341  	      s1[j] = val;
     342  	      s2[j] = val;
     343  	    }
     344  
     345  	  s2[i] = val;
     346  
     347  	  exp_result = SIMPLE_STRCMP (s1, s2);
     348  	  FOR_EACH_IMPL (impl, 0)
     349  	    check_result (impl, s1, s2, exp_result);
     350  	}
     351      }
     352  }
     353  
     354  static void
     355  check2 (void)
     356  {
     357    /* To trigger bug 25933, we need a size that is equal to the vector
     358       length times 4. In the case of AVX2 for Intel, we need 32 * 4.  We
     359       make this test generic and run it for all architectures as additional
     360       boundary testing for such related algorithms.  */
     361    size_t size = 32 * 4;
     362    CHAR *s1 = (CHAR *) (buf1 + (BUF1PAGES - 1) * page_size);
     363    CHAR *s2 = (CHAR *) (buf2 + (BUF1PAGES - 1) * page_size);
     364    int exp_result;
     365  
     366    memset (s1, 'a', page_size);
     367    memset (s2, 'a', page_size);
     368    s1[(page_size / CHARBYTES) - 1] = (CHAR) 0;
     369    s2[(page_size / CHARBYTES) - 1] = (CHAR) 0;
     370  
     371    /* Iterate over a size that is just below where we expect the bug to
     372       trigger up to the size we expect will trigger the bug e.g. [99-128].
     373       Likewise iterate the start of two strings between 30 and 31 bytes
     374       away from the boundary to simulate alignment changes.  */
     375    for (size_t s = 99; s <= size; s++)
     376      for (size_t s1a = 30; s1a < 32; s1a++)
     377        for (size_t s2a = 30; s2a < 32; s2a++)
     378  	{
     379  	  CHAR *s1p = s1 + (page_size / CHARBYTES - s) - s1a;
     380  	  CHAR *s2p = s2 + (page_size / CHARBYTES - s) - s2a;
     381  	  exp_result = SIMPLE_STRCMP (s1p, s2p);
     382  	  FOR_EACH_IMPL (impl, 0)
     383  	    check_result (impl, s1p, s2p, exp_result);
     384  	}
     385  }
     386  
     387  static void
     388  check3 (void)
     389  {
     390    size_t size = 0xd000 + 0x4000;
     391    CHAR *s1, *s2;
     392    CHAR *buffer1 = mmap (NULL, size, PROT_READ | PROT_WRITE,
     393  			MAP_PRIVATE | MAP_ANON, -1, 0);
     394    CHAR *buffer2 = mmap (NULL, size, PROT_READ | PROT_WRITE,
     395  			MAP_PRIVATE | MAP_ANON, -1, 0);
     396    if (buffer1 == MAP_FAILED || buffer1 == MAP_FAILED)
     397      error (EXIT_UNSUPPORTED, errno, "mmap failed");
     398  
     399    s1 = (CHAR *) (buffer1 + 0x8f8 / sizeof (CHAR));
     400    s2 = (CHAR *) (buffer2 + 0xcff3 / sizeof (CHAR));
     401  
     402    STRCPY(s1, L("/export/redhat/rpms/BUILD/java-1.8.0-openjdk-1.8.0.312.b07-2.fc35.x86_64/openjdk/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/util/PathDocFileFactory.java"));
     403    STRCPY(s2, L("/export/redhat/rpms/BUILD/java-1.8.0-openjdk-1.8.0.312.b07-2.fc35.x86_64/openjdk/langtools/src/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/ThrowsTaglet.java"));
     404  
     405    int exp_result = SIMPLE_STRCMP (s1, s2);
     406    FOR_EACH_IMPL (impl, 0)
     407      check_result (impl, s1, s2, exp_result);
     408  
     409    munmap ((void *) buffer1, size);
     410    munmap ((void *) buffer2, size);
     411  }
     412  
     413  int
     414  test_main (void)
     415  {
     416    size_t i, j, k;
     417    const size_t test_len = MIN(TEST_LEN, 3 * 4096);
     418    test_init ();
     419    check();
     420    check2 ();
     421    check3 ();
     422  
     423    printf ("%23s", "");
     424    FOR_EACH_IMPL (impl, 0)
     425      printf ("\t%s", impl->name);
     426    putchar ('\n');
     427  
     428    for (i = 1; i < 32; ++i)
     429      {
     430        do_test (CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, 0);
     431        do_test (CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, 1);
     432        do_test (CHARBYTES * i, CHARBYTES * i, i, MIDCHAR, -1);
     433      }
     434  
     435    for (i = 1; i < 10 + CHARBYTESLOG; ++i)
     436      {
     437        do_test (0, 0, 2 << i, MIDCHAR, 0);
     438        do_test (0, 0, 2 << i, LARGECHAR, 0);
     439        do_test (0, 0, 2 << i, MIDCHAR, 1);
     440        do_test (0, 0, 2 << i, LARGECHAR, 1);
     441        do_test (0, 0, 2 << i, MIDCHAR, -1);
     442        do_test (0, 0, 2 << i, LARGECHAR, -1);
     443        do_test (0, CHARBYTES * i, 2 << i, MIDCHAR, 1);
     444        do_test (CHARBYTES * i, CHARBYTES * (i + 1), 2 << i, LARGECHAR, 1);
     445      }
     446  
     447    for (i = 1; i < 8; ++i)
     448      {
     449        do_test (CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, 0);
     450        do_test (2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, 0);
     451        do_test (CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, 1);
     452        do_test (2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, 1);
     453        do_test (CHARBYTES * i, 2 * CHARBYTES * i, 8 << i, MIDCHAR, -1);
     454        do_test (2 * CHARBYTES * i, CHARBYTES * i, 8 << i, LARGECHAR, -1);
     455      }
     456  
     457    for (j = 0; j < 160; ++j)
     458      {
     459        for (i = 0; i < test_len;)
     460          {
     461            do_test (getpagesize () - j - 1, 0, i, 127, 0);
     462            do_test (getpagesize () - j - 1, 0, i, 127, 1);
     463            do_test (getpagesize () - j - 1, 0, i, 127, -1);
     464  
     465            do_test (getpagesize () - j - 1, j, i, 127, 0);
     466            do_test (getpagesize () - j - 1, j, i, 127, 1);
     467            do_test (getpagesize () - j - 1, j, i, 127, -1);
     468  
     469            do_test (0, getpagesize () - j - 1, i, 127, 0);
     470            do_test (0, getpagesize () - j - 1, i, 127, 1);
     471            do_test (0, getpagesize () - j - 1, i, 127, -1);
     472  
     473            do_test (j, getpagesize () - j - 1, i, 127, 0);
     474            do_test (j, getpagesize () - j - 1, i, 127, 1);
     475            do_test (j, getpagesize () - j - 1, i, 127, -1);
     476  
     477            for (k = 2; k <= 128; k += k)
     478              {
     479                do_test (getpagesize () - k, getpagesize () - j - 1, i, 127, 0);
     480                do_test (getpagesize () - k - 1, getpagesize () - j - 1, i, 127,
     481                         0);
     482                do_test (getpagesize () - k, getpagesize () - j - 1, i, 127, 1);
     483                do_test (getpagesize () - k - 1, getpagesize () - j - 1, i, 127,
     484                         1);
     485                do_test (getpagesize () - k, getpagesize () - j - 1, i, 127, -1);
     486                do_test (getpagesize () - k - 1, getpagesize () - j - 1, i, 127,
     487                         -1);
     488              }
     489  
     490            if (i < 32)
     491              {
     492                i += 1;
     493              }
     494            else if (i < 161)
     495              {
     496                i += 7;
     497              }
     498            else if (i + 161 < test_len)
     499              {
     500                i += 31;
     501                i *= 17;
     502                i /= 16;
     503                if (i + 161 > test_len)
     504                  {
     505                    i = test_len - 160;
     506                  }
     507              }
     508            else if (i + 32 < test_len)
     509              {
     510                i += 7;
     511              }
     512            else
     513              {
     514                i += 1;
     515              }
     516          }
     517      }
     518  
     519    do_random_tests ();
     520    return ret;
     521  }
     522  
     523  #include <support/test-driver.c>