1  /* Test strndup functions.
       2     Copyright (C) 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  #include <support/check.h>
      20  
      21  #define TEST_MAIN
      22  #include "test-string.h"
      23  
      24  static void
      25  do_one_test (const char *src, size_t len, size_t n)
      26  {
      27    char *dst = strndup (src, n);
      28    size_t s = (len > n ? n: len) * sizeof (char);
      29  
      30    TEST_COMPARE_BLOB (dst, s, src, s);
      31  
      32    free (dst);
      33  }
      34  
      35  static void
      36  do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char)
      37  {
      38    size_t i;
      39    char *s1;
      40  
      41    align1 &= 7;
      42    if ((align1 + len) * sizeof (char) >= page_size)
      43      return;
      44  
      45    align2 &= 7;
      46    if ((align2 + len) * sizeof (char) >= page_size)
      47      return;
      48  
      49    s1 = (char *) (buf1) + align1;
      50  
      51    for (i = 0; i < len; ++i)
      52      s1[i] = 32 + 23 * i % (max_char - 32);
      53    s1[len] = 0;
      54    for (i = len + 1; (i + align1) * sizeof (char) < page_size && i < len + 64;
      55         ++i)
      56      s1[i] = 32 + 32 * i % (max_char - 32);
      57  
      58    do_one_test (s1, len, n);
      59  }
      60  
      61  static void
      62  do_page_tests (void)
      63  {
      64    char *s1;
      65    const size_t maxoffset = 64;
      66  
      67    /* Put s1 at the maxoffset from the edge of buf1's last page.  */
      68    s1 = (char *) buf1 + BUF1PAGES * page_size / sizeof (char) - maxoffset;
      69  
      70    memset (s1, 'a', maxoffset - 1);
      71    s1[maxoffset - 1] = '\0';
      72  
      73    /* Both strings are bounded to a page with read/write access and the next
      74       page is protected with PROT_NONE (meaning that any access outside of the
      75       page regions will trigger an invalid memory access).
      76  
      77       The loop copies the string s1 for all possible offsets up to maxoffset
      78       for both inputs with a size larger than s1 (so memory access outside the
      79       expected memory regions might trigger invalid access).  */
      80  
      81    for (size_t off1 = 0; off1 < maxoffset; off1++)
      82      for (size_t off2 = 0; off2 < maxoffset; off2++)
      83        do_one_test (s1 + off1, maxoffset - off1 - 1,
      84  		   maxoffset + (maxoffset - off2));
      85  }
      86  
      87  static void
      88  do_random_tests (void)
      89  {
      90    size_t i, j, n, align1, align2, len, size, mode;
      91    char *p1 = (char *) (buf1 + page_size) - 512;
      92    char *res;
      93  
      94    for (n = 0; n < ITERATIONS; n++)
      95      {
      96        mode = random ();
      97        if (mode & 1)
      98  	{
      99  	  size = random () & 255;
     100  	  align1 = 512 - size - (random () & 15);
     101  	  if (mode & 2)
     102  	    align2 = align1 - (random () & 24);
     103  	  else
     104  	    align2 = align1 - (random () & 31);
     105  	  if (mode & 4)
     106  	    {
     107  	      j = align1;
     108  	      align1 = align2;
     109  	      align2 = j;
     110  	    }
     111  	  if (mode & 8)
     112  	    len = size - (random () & 31);
     113  	  else
     114  	    len = 512;
     115  	  if (len >= 512)
     116  	    len = random () & 511;
     117  	}
     118        else
     119  	{
     120  	  align1 = random () & 31;
     121  	  if (mode & 2)
     122  	    align2 = random () & 31;
     123  	  else
     124  	    align2 = align1 + (random () & 24);
     125  	  len = random () & 511;
     126  	  j = align1;
     127  	  if (align2 > j)
     128  	    j = align2;
     129  	  if (mode & 4)
     130  	    {
     131  	      size = random () & 511;
     132  	      if (size + j > 512)
     133  		size = 512 - j - (random () & 31);
     134  	    }
     135  	  else
     136  	    size = 512 - j;
     137  	  if ((mode & 8) && len + j >= 512)
     138  	    len = 512 - j - (random () & 7);
     139  	}
     140        j = len + align1 + 64;
     141        if (j > 512)
     142  	j = 512;
     143        for (i = 0; i < j; i++)
     144  	{
     145  	  if (i == len + align1)
     146  	    p1[i] = 0;
     147  	  else
     148  	    {
     149  	      p1[i] = random () & CHAR_MAX;
     150  	      if (i >= align1 && i < len + align1 && !p1[i])
     151  		p1[i] = (random () & 127) + 3;
     152  	    }
     153  	}
     154  
     155  	res = (char *) strndup ((char *) (p1 + align1), size);
     156  	j = len + 1;
     157  	if (size < j)
     158  	  j = size;
     159  	TEST_COMPARE_BLOB (res, j, (char *) (p1 + align1), j);
     160  	free (res);
     161      }
     162  }
     163  
     164  int
     165  test_main (void)
     166  {
     167    size_t i;
     168  
     169    test_init ();
     170  
     171    printf ("%28s", "");
     172    printf ("\t%s", "strndup");
     173    putchar ('\n');
     174  
     175    for (i = 1; i < 8; ++i)
     176      {
     177        do_test (i, i, 16, 16, 127);
     178        do_test (i, i, 16, 16, CHAR_MAX);
     179        do_test (i, 2 * i, 16, 16, 127);
     180        do_test (2 * i, i, 16, 16, CHAR_MAX);
     181        do_test (8 - i, 2 * i, 1 << i, 2 << i, 127);
     182        do_test (2 * i, 8 - i, 2 << i, 1 << i, 127);
     183        do_test (8 - i, 2 * i, 1 << i, 2 << i, CHAR_MAX);
     184        do_test (2 * i, 8 - i, 2 << i, 1 << i, CHAR_MAX);
     185      }
     186  
     187    for (i = 1; i < 8; ++i)
     188      {
     189        do_test (0, 0, 4 << i, 8 << i, 127);
     190        do_test (0, 0, 16 << i, 8 << i, 127);
     191        do_test (8 - i, 2 * i, 4 << i, 8 << i, 127);
     192        do_test (8 - i, 2 * i, 16 << i, 8 << i, 127);
     193      }
     194  
     195    do_random_tests ();
     196    do_page_tests ();
     197    return ret;
     198  }
     199  
     200  #include <support/test-driver.c>