diff mbox series

[v3,2/3] string: Add tests for strdup (BZ #30266)

Message ID 20230404190040.2507343-3-josimmon@redhat.com
State New
Headers show
Series string: Add tests for strdup and strndup (BZ #30266) | expand

Commit Message

Joe Simmons-Talbott April 4, 2023, 7 p.m. UTC
Copy strcpy tests for strdup.  Covers some basic testcases with random
strings.  Add a zero-length string testcase.
---
 string/Makefile      |   1 +
 string/test-strdup.c | 201 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 202 insertions(+)
 create mode 100644 string/test-strdup.c

Comments

Noah Goldstein April 4, 2023, 7:17 p.m. UTC | #1
On Tue, Apr 4, 2023 at 2:02 PM Joe Simmons-Talbott via Libc-alpha
<libc-alpha@sourceware.org> wrote:
>
> Copy strcpy tests for strdup.  Covers some basic testcases with random
> strings.  Add a zero-length string testcase.
> ---
>  string/Makefile      |   1 +
>  string/test-strdup.c | 201 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 202 insertions(+)
>  create mode 100644 string/test-strdup.c
>
> diff --git a/string/Makefile b/string/Makefile
> index c84b49aaa5..472e318aea 100644
> --- a/string/Makefile
> +++ b/string/Makefile
> @@ -157,6 +157,7 @@ tests := \
>    test-strcmp \
>    test-strcpy \
>    test-strcspn \
> +  test-strdup \
>    test-strlen \
>    test-strncasecmp \
>    test-strncat \
> diff --git a/string/test-strdup.c b/string/test-strdup.c
> new file mode 100644
> index 0000000000..f45fb4c852
> --- /dev/null
> +++ b/string/test-strdup.c
> @@ -0,0 +1,201 @@
> +/* Test and measure strdup functions.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <support/check.h>
> +
> +#ifdef WIDE
> +# include <wchar.h>
> +# define CHAR wchar_t
> +# define UCHAR wchar_t
> +# define sfmt "ls"
> +# define BIG_CHAR WCHAR_MAX
> +# define SMALL_CHAR 1273
> +# define STRCMP wcscmp
> +# define MEMCMP wmemcmp
> +# define MEMSET wmemset
> +#else
> +# define CHAR char
> +# define UCHAR unsigned char
> +# define sfmt "s"
> +# define BIG_CHAR CHAR_MAX
> +# define SMALL_CHAR 127
> +# define STRCMP strcmp
> +# define MEMCMP memcmp
> +# define MEMSET memset
> +#endif
> +
> +#ifndef STRDUP_RESULT
> +# define STRDUP_RESULT(dst, len) dst
> +# define TEST_MAIN
> +# ifndef WIDE
> +#  define TEST_NAME "strdup"
> +# else
> +#  define TEST_NAME "wcsdup"
> +# endif
> +# include "test-string.h"
> +# ifndef WIDE
> +#  define STRDUP strdup
> +# else
> +#  define STRDUP wcsdup
> +# endif
> +#endif
> +
> +typedef CHAR *(*proto_t) (const CHAR *);
> +
> +static void
> +do_zero_len_test (void)
> +{
> +  char src[1] = { '\0' };
> +  char *dst = STRDUP (src);
> +
> +  TEST_COMPARE_STRING (dst, src);
> +  free(dst);
> +}
> +
> +static void
> +do_one_test (const CHAR *src,
> +            size_t len __attribute__((unused)))
> +{
> +  char *dst = STRDUP (src);
> +
> +  if (STRCMP (dst, src) != 0)
> +    {
> +      error (0, 0,
> +            "Wrong result in function %s dst \"%" sfmt "\" src \"%" sfmt "\"",
> +            TEST_NAME, dst, src);
> +      ret = 1;
> +         free(dst);
> +      return;
> +    }
> +  free(dst);
> +}
> +
> +static void
> +do_test (size_t align1, size_t align2, size_t len, int max_char)
> +{
> +  size_t i;
> +  CHAR *s1;
> +/* For wcsdup: align1 and align2 here mean alignment not in bytes,
> +   but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t))
> +   len for wcschr here isn't in bytes but it's number of wchar_t symbols.  */
> +  align1 &= 7;
> +  if ((align1 + len) * sizeof (CHAR) >= page_size)
> +    return;
> +
> +  align2 &= 7;
> +  if ((align2 + len) * sizeof (CHAR) >= page_size)
> +    return;
> +
> +  s1 = (CHAR *) (buf1) + align1;
> +
> +  for (i = 0; i < len; i++)
> +    s1[i] = 32 + 23 * i % (max_char - 32);
> +  s1[len] = 0;
> +
> +  do_one_test (s1, len);
> +}
> +
> +static void
> +do_random_tests (void)
> +{
> +  size_t i, j, n, align1, align2, len;
> +  UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512;
> +  UCHAR *res;
> +
> +  for (n = 0; n < ITERATIONS; n++)
> +    {
> +      /* align1 and align2 are expressed as wchar_t and not in bytes for wide
> +     char test, and thus it will be equal to align times wchar_t size.
> +
> +     For non wide version we need to check all alignments from 0 to 63
> +     since some assembly implementations have separate prolog for alignments
> +     more 48.  */
> +
> +      align1 = random () & (63 / sizeof (CHAR));
> +      if (random () & 1)
> +       align2 = random () & (63 / sizeof (CHAR));
> +      else
> +       align2 = align1 + (random () & 24);
> +      len = random () & 511;
> +      j = align1;
> +      if (align2 > j)
> +       j = align2;
> +      if (len + j >= 511)
> +       len = 510 - j - (random () & 7);
> +      j = len + align1 + 64;
> +      if (j > 512)
> +       j = 512;
> +      for (i = 0; i < j; i++)
> +       {
> +         if (i == len + align1)
> +           p1[i] = 0;
> +         else
> +           {
> +             p1[i] = random () & BIG_CHAR;
> +             if (i >= align1 && i < len + align1 && !p1[i])
> +               p1[i] = (random () & SMALL_CHAR) + 3;
> +           }
> +       }
> +
> +    res = (UCHAR *) STRDUP((CHAR *) p1 + align1);
> +       TEST_COMPARE_STRING((CHAR *) res, (CHAR *) (p1 + align1));
> +       free(res);
> +    }
> +}
> +
> +
> +int
> +test_main (void)
> +{
> +  size_t i;
> +
> +  test_init ();
> +
> +  printf ("%23s", "");
> +  printf ("\t%s", TEST_NAME);
> +  putchar ('\n');
> +
> +  for (i = 0; i < 16; ++i)
> +    {
> +      do_test (0, 0, i, SMALL_CHAR);
> +      do_test (0, 0, i, BIG_CHAR);
> +      do_test (0, i, i, SMALL_CHAR);
> +      do_test (i, 0, i, BIG_CHAR);
> +    }
> +
> +  for (i = 1; i < 8; ++i)
> +    {
> +      do_test (0, 0, 8 << i, SMALL_CHAR);
> +      do_test (8 - i, 2 * i, 8 << i, SMALL_CHAR);
> +    }
> +
> +  for (i = 1; i < 8; ++i)
> +    {
> +      do_test (i, 2 * i, 8 << i, SMALL_CHAR);
> +      do_test (2 * i, i, 8 << i, BIG_CHAR);
> +      do_test (i, i, 8 << i, SMALL_CHAR);
> +      do_test (i, i, 8 << i, BIG_CHAR);
> +    }
> +
> +  do_zero_len_test ();
> +  do_random_tests ();
> +
> +  return ret;
> +}
> +
> +#include <support/test-driver.c>
> --
> 2.39.2
>
What about including test-strcpy and just creating macros for FREE?
Adhemerval Zanella Netto April 4, 2023, 7:40 p.m. UTC | #2
On 04/04/23 16:17, Noah Goldstein via Libc-alpha wrote:


> What about including test-strcpy and just creating macros for FREE?

test-strcpy add extra complexity to handle ifunc and uses an external
mmap buffer to check of OOB access, which for strdup does not add much.
Adhemerval Zanella Netto April 7, 2023, 6:19 p.m. UTC | #3
On 04/04/23 16:00, Joe Simmons-Talbott via Libc-alpha wrote:
> Copy strcpy tests for strdup.  Covers some basic testcases with random
> strings.  Add a zero-length string testcase.

Just minor style issue.

LGTM, thanks.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

> ---
>  string/Makefile      |   1 +
>  string/test-strdup.c | 201 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 202 insertions(+)
>  create mode 100644 string/test-strdup.c
> 
> diff --git a/string/Makefile b/string/Makefile
> index c84b49aaa5..472e318aea 100644
> --- a/string/Makefile
> +++ b/string/Makefile
> @@ -157,6 +157,7 @@ tests := \
>    test-strcmp \
>    test-strcpy \
>    test-strcspn \
> +  test-strdup \
>    test-strlen \
>    test-strncasecmp \
>    test-strncat \
> diff --git a/string/test-strdup.c b/string/test-strdup.c
> new file mode 100644
> index 0000000000..f45fb4c852
> --- /dev/null
> +++ b/string/test-strdup.c
> @@ -0,0 +1,201 @@
> +/* Test and measure strdup functions.
> +   Copyright (C) 2023 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <support/check.h>
> +
> +#ifdef WIDE
> +# include <wchar.h>
> +# define CHAR wchar_t
> +# define UCHAR wchar_t
> +# define sfmt "ls"
> +# define BIG_CHAR WCHAR_MAX
> +# define SMALL_CHAR 1273
> +# define STRCMP wcscmp
> +# define MEMCMP wmemcmp
> +# define MEMSET wmemset
> +#else
> +# define CHAR char
> +# define UCHAR unsigned char
> +# define sfmt "s"
> +# define BIG_CHAR CHAR_MAX
> +# define SMALL_CHAR 127
> +# define STRCMP strcmp
> +# define MEMCMP memcmp
> +# define MEMSET memset
> +#endif

Do you plan to add wcsdup tests as well?

> +
> +#ifndef STRDUP_RESULT
> +# define STRDUP_RESULT(dst, len) dst
> +# define TEST_MAIN
> +# ifndef WIDE
> +#  define TEST_NAME "strdup"
> +# else
> +#  define TEST_NAME "wcsdup"
> +# endif
> +# include "test-string.h"
> +# ifndef WIDE
> +#  define STRDUP strdup
> +# else
> +#  define STRDUP wcsdup
> +# endif
> +#endif
> +
> +typedef CHAR *(*proto_t) (const CHAR *);
> +
> +static void
> +do_zero_len_test (void)
> +{
> +  char src[1] = { '\0' };
> +  char *dst = STRDUP (src);
> +
> +  TEST_COMPARE_STRING (dst, src);
> +  free(dst);
> +}
> +
> +static void
> +do_one_test (const CHAR *src,
> +	     size_t len __attribute__((unused)))
> +{
> +  char *dst = STRDUP (src);
> +
> +  if (STRCMP (dst, src) != 0)
> +    {
> +      error (0, 0,
> +	     "Wrong result in function %s dst \"%" sfmt "\" src \"%" sfmt "\"",
> +	     TEST_NAME, dst, src);
> +      ret = 1;
> +	  free(dst);

Indentation seems off here.

> +      return;
> +    }
> +  free(dst);
> +}
> +
> +static void
> +do_test (size_t align1, size_t align2, size_t len, int max_char)
> +{
> +  size_t i;
> +  CHAR *s1;
> +/* For wcsdup: align1 and align2 here mean alignment not in bytes,
> +   but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t))
> +   len for wcschr here isn't in bytes but it's number of wchar_t symbols.  */
> +  align1 &= 7;
> +  if ((align1 + len) * sizeof (CHAR) >= page_size)
> +    return;
> +
> +  align2 &= 7;
> +  if ((align2 + len) * sizeof (CHAR) >= page_size)
> +    return;
> +
> +  s1 = (CHAR *) (buf1) + align1;
> +
> +  for (i = 0; i < len; i++)
> +    s1[i] = 32 + 23 * i % (max_char - 32);
> +  s1[len] = 0;
> +
> +  do_one_test (s1, len);
> +}
> +
> +static void
> +do_random_tests (void)
> +{
> +  size_t i, j, n, align1, align2, len;
> +  UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512;
> +  UCHAR *res;
> +
> +  for (n = 0; n < ITERATIONS; n++)
> +    {
> +      /* align1 and align2 are expressed as wchar_t and not in bytes for wide
> +     char test, and thus it will be equal to align times wchar_t size.
> +
> +     For non wide version we need to check all alignments from 0 to 63
> +     since some assembly implementations have separate prolog for alignments
> +     more 48.  */
> +
> +      align1 = random () & (63 / sizeof (CHAR));
> +      if (random () & 1)
> +	align2 = random () & (63 / sizeof (CHAR));
> +      else
> +	align2 = align1 + (random () & 24);
> +      len = random () & 511;
> +      j = align1;
> +      if (align2 > j)
> +	j = align2;
> +      if (len + j >= 511)
> +	len = 510 - j - (random () & 7);
> +      j = len + align1 + 64;
> +      if (j > 512)
> +	j = 512;
> +      for (i = 0; i < j; i++)
> +	{
> +	  if (i == len + align1)
> +	    p1[i] = 0;
> +	  else
> +	    {
> +	      p1[i] = random () & BIG_CHAR;
> +	      if (i >= align1 && i < len + align1 && !p1[i])
> +		p1[i] = (random () & SMALL_CHAR) + 3;
> +	    }
> +	}
> +
> +    res = (UCHAR *) STRDUP((CHAR *) p1 + align1);

Indentation seems off.

> +	TEST_COMPARE_STRING((CHAR *) res, (CHAR *) (p1 + align1));
> +	free(res);

Missing space before '('.

> +    }
> +}
> +
> +
> +int
> +test_main (void)
> +{
> +  size_t i;
> +
> +  test_init ();
> +
> +  printf ("%23s", "");
> +  printf ("\t%s", TEST_NAME);
> +  putchar ('\n');
> +
> +  for (i = 0; i < 16; ++i)
> +    {
> +      do_test (0, 0, i, SMALL_CHAR);
> +      do_test (0, 0, i, BIG_CHAR);
> +      do_test (0, i, i, SMALL_CHAR);
> +      do_test (i, 0, i, BIG_CHAR);
> +    }
> +
> +  for (i = 1; i < 8; ++i)
> +    {
> +      do_test (0, 0, 8 << i, SMALL_CHAR);
> +      do_test (8 - i, 2 * i, 8 << i, SMALL_CHAR);
> +    }
> +
> +  for (i = 1; i < 8; ++i)
> +    {
> +      do_test (i, 2 * i, 8 << i, SMALL_CHAR);
> +      do_test (2 * i, i, 8 << i, BIG_CHAR);
> +      do_test (i, i, 8 << i, SMALL_CHAR);
> +      do_test (i, i, 8 << i, BIG_CHAR);
> +    }
> +
> +  do_zero_len_test ();
> +  do_random_tests ();
> +
> +  return ret;
> +}
> +
> +#include <support/test-driver.c>
Joe Simmons-Talbott April 10, 2023, 1:53 p.m. UTC | #4
On Fri, Apr 07, 2023 at 03:19:38PM -0300, Adhemerval Zanella Netto wrote:
> 
> 
> On 04/04/23 16:00, Joe Simmons-Talbott via Libc-alpha wrote:
> > Copy strcpy tests for strdup.  Covers some basic testcases with random
> > strings.  Add a zero-length string testcase.
> 
> Just minor style issue.
> 
> LGTM, thanks.
> 
> Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
> 
> > ---
> >  string/Makefile      |   1 +
> >  string/test-strdup.c | 201 +++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 202 insertions(+)
> >  create mode 100644 string/test-strdup.c
> > 
> > diff --git a/string/Makefile b/string/Makefile
> > index c84b49aaa5..472e318aea 100644
> > --- a/string/Makefile
> > +++ b/string/Makefile
> > @@ -157,6 +157,7 @@ tests := \
> >    test-strcmp \
> >    test-strcpy \
> >    test-strcspn \
> > +  test-strdup \
> >    test-strlen \
> >    test-strncasecmp \
> >    test-strncat \
> > diff --git a/string/test-strdup.c b/string/test-strdup.c
> > new file mode 100644
> > index 0000000000..f45fb4c852
> > --- /dev/null
> > +++ b/string/test-strdup.c
> > @@ -0,0 +1,201 @@
> > +/* Test and measure strdup functions.
> > +   Copyright (C) 2023 Free Software Foundation, Inc.
> > +   This file is part of the GNU C Library.
> > +
> > +   The GNU C Library is free software; you can redistribute it and/or
> > +   modify it under the terms of the GNU Lesser General Public
> > +   License as published by the Free Software Foundation; either
> > +   version 2.1 of the License, or (at your option) any later version.
> > +
> > +   The GNU C Library is distributed in the hope that it will be useful,
> > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > +   Lesser General Public License for more details.
> > +
> > +   You should have received a copy of the GNU Lesser General Public
> > +   License along with the GNU C Library; if not, see
> > +   <https://www.gnu.org/licenses/>.  */
> > +
> > +#include <support/check.h>
> > +
> > +#ifdef WIDE
> > +# include <wchar.h>
> > +# define CHAR wchar_t
> > +# define UCHAR wchar_t
> > +# define sfmt "ls"
> > +# define BIG_CHAR WCHAR_MAX
> > +# define SMALL_CHAR 1273
> > +# define STRCMP wcscmp
> > +# define MEMCMP wmemcmp
> > +# define MEMSET wmemset
> > +#else
> > +# define CHAR char
> > +# define UCHAR unsigned char
> > +# define sfmt "s"
> > +# define BIG_CHAR CHAR_MAX
> > +# define SMALL_CHAR 127
> > +# define STRCMP strcmp
> > +# define MEMCMP memcmp
> > +# define MEMSET memset
> > +#endif
> 
> Do you plan to add wcsdup tests as well?

I assumed the above would cover that as well.  Do I need to indicate in
the Makefile to run these tests with and without WIDE defined?  Does
TEST_COMPARE_STRING handle wide strings as well?

Thanks,
Joe
Adhemerval Zanella Netto April 10, 2023, 2:44 p.m. UTC | #5
On 10/04/23 10:53, Joe Simmons-Talbott wrote:
> On Fri, Apr 07, 2023 at 03:19:38PM -0300, Adhemerval Zanella Netto wrote:
>>
>>
>> On 04/04/23 16:00, Joe Simmons-Talbott via Libc-alpha wrote:
>>> Copy strcpy tests for strdup.  Covers some basic testcases with random
>>> strings.  Add a zero-length string testcase.
>>
>> Just minor style issue.
>>
>> LGTM, thanks.
>>
>> Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
>>
>>> ---
>>>  string/Makefile      |   1 +
>>>  string/test-strdup.c | 201 +++++++++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 202 insertions(+)
>>>  create mode 100644 string/test-strdup.c
>>>
>>> diff --git a/string/Makefile b/string/Makefile
>>> index c84b49aaa5..472e318aea 100644
>>> --- a/string/Makefile
>>> +++ b/string/Makefile
>>> @@ -157,6 +157,7 @@ tests := \
>>>    test-strcmp \
>>>    test-strcpy \
>>>    test-strcspn \
>>> +  test-strdup \
>>>    test-strlen \
>>>    test-strncasecmp \
>>>    test-strncat \
>>> diff --git a/string/test-strdup.c b/string/test-strdup.c
>>> new file mode 100644
>>> index 0000000000..f45fb4c852
>>> --- /dev/null
>>> +++ b/string/test-strdup.c
>>> @@ -0,0 +1,201 @@
>>> +/* Test and measure strdup functions.
>>> +   Copyright (C) 2023 Free Software Foundation, Inc.
>>> +   This file is part of the GNU C Library.
>>> +
>>> +   The GNU C Library is free software; you can redistribute it and/or
>>> +   modify it under the terms of the GNU Lesser General Public
>>> +   License as published by the Free Software Foundation; either
>>> +   version 2.1 of the License, or (at your option) any later version.
>>> +
>>> +   The GNU C Library is distributed in the hope that it will be useful,
>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> +   Lesser General Public License for more details.
>>> +
>>> +   You should have received a copy of the GNU Lesser General Public
>>> +   License along with the GNU C Library; if not, see
>>> +   <https://www.gnu.org/licenses/>.  */
>>> +
>>> +#include <support/check.h>
>>> +
>>> +#ifdef WIDE
>>> +# include <wchar.h>
>>> +# define CHAR wchar_t
>>> +# define UCHAR wchar_t
>>> +# define sfmt "ls"
>>> +# define BIG_CHAR WCHAR_MAX
>>> +# define SMALL_CHAR 1273
>>> +# define STRCMP wcscmp
>>> +# define MEMCMP wmemcmp
>>> +# define MEMSET wmemset
>>> +#else
>>> +# define CHAR char
>>> +# define UCHAR unsigned char
>>> +# define sfmt "s"
>>> +# define BIG_CHAR CHAR_MAX
>>> +# define SMALL_CHAR 127
>>> +# define STRCMP strcmp
>>> +# define MEMCMP memcmp
>>> +# define MEMSET memset
>>> +#endif
>>
>> Do you plan to add wcsdup tests as well?
> 
> I assumed the above would cover that as well.  Do I need to indicate in
> the Makefile to run these tests with and without WIDE defined?  Does
> TEST_COMPARE_STRING handle wide strings as well?

You need to actually enable by adding it on wcsmbs/Makefile.
diff mbox series

Patch

diff --git a/string/Makefile b/string/Makefile
index c84b49aaa5..472e318aea 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -157,6 +157,7 @@  tests := \
   test-strcmp \
   test-strcpy \
   test-strcspn \
+  test-strdup \
   test-strlen \
   test-strncasecmp \
   test-strncat \
diff --git a/string/test-strdup.c b/string/test-strdup.c
new file mode 100644
index 0000000000..f45fb4c852
--- /dev/null
+++ b/string/test-strdup.c
@@ -0,0 +1,201 @@ 
+/* Test and measure strdup functions.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+
+#ifdef WIDE
+# include <wchar.h>
+# define CHAR wchar_t
+# define UCHAR wchar_t
+# define sfmt "ls"
+# define BIG_CHAR WCHAR_MAX
+# define SMALL_CHAR 1273
+# define STRCMP wcscmp
+# define MEMCMP wmemcmp
+# define MEMSET wmemset
+#else
+# define CHAR char
+# define UCHAR unsigned char
+# define sfmt "s"
+# define BIG_CHAR CHAR_MAX
+# define SMALL_CHAR 127
+# define STRCMP strcmp
+# define MEMCMP memcmp
+# define MEMSET memset
+#endif
+
+#ifndef STRDUP_RESULT
+# define STRDUP_RESULT(dst, len) dst
+# define TEST_MAIN
+# ifndef WIDE
+#  define TEST_NAME "strdup"
+# else
+#  define TEST_NAME "wcsdup"
+# endif
+# include "test-string.h"
+# ifndef WIDE
+#  define STRDUP strdup
+# else
+#  define STRDUP wcsdup
+# endif
+#endif
+
+typedef CHAR *(*proto_t) (const CHAR *);
+
+static void
+do_zero_len_test (void)
+{
+  char src[1] = { '\0' };
+  char *dst = STRDUP (src);
+
+  TEST_COMPARE_STRING (dst, src);
+  free(dst);
+}
+
+static void
+do_one_test (const CHAR *src,
+	     size_t len __attribute__((unused)))
+{
+  char *dst = STRDUP (src);
+
+  if (STRCMP (dst, src) != 0)
+    {
+      error (0, 0,
+	     "Wrong result in function %s dst \"%" sfmt "\" src \"%" sfmt "\"",
+	     TEST_NAME, dst, src);
+      ret = 1;
+	  free(dst);
+      return;
+    }
+  free(dst);
+}
+
+static void
+do_test (size_t align1, size_t align2, size_t len, int max_char)
+{
+  size_t i;
+  CHAR *s1;
+/* For wcsdup: align1 and align2 here mean alignment not in bytes,
+   but in wchar_ts, in bytes it will equal to align * (sizeof (wchar_t))
+   len for wcschr here isn't in bytes but it's number of wchar_t symbols.  */
+  align1 &= 7;
+  if ((align1 + len) * sizeof (CHAR) >= page_size)
+    return;
+
+  align2 &= 7;
+  if ((align2 + len) * sizeof (CHAR) >= page_size)
+    return;
+
+  s1 = (CHAR *) (buf1) + align1;
+
+  for (i = 0; i < len; i++)
+    s1[i] = 32 + 23 * i % (max_char - 32);
+  s1[len] = 0;
+
+  do_one_test (s1, len);
+}
+
+static void
+do_random_tests (void)
+{
+  size_t i, j, n, align1, align2, len;
+  UCHAR *p1 = (UCHAR *) (buf1 + page_size) - 512;
+  UCHAR *res;
+
+  for (n = 0; n < ITERATIONS; n++)
+    {
+      /* align1 and align2 are expressed as wchar_t and not in bytes for wide
+     char test, and thus it will be equal to align times wchar_t size.
+
+     For non wide version we need to check all alignments from 0 to 63
+     since some assembly implementations have separate prolog for alignments
+     more 48.  */
+
+      align1 = random () & (63 / sizeof (CHAR));
+      if (random () & 1)
+	align2 = random () & (63 / sizeof (CHAR));
+      else
+	align2 = align1 + (random () & 24);
+      len = random () & 511;
+      j = align1;
+      if (align2 > j)
+	j = align2;
+      if (len + j >= 511)
+	len = 510 - j - (random () & 7);
+      j = len + align1 + 64;
+      if (j > 512)
+	j = 512;
+      for (i = 0; i < j; i++)
+	{
+	  if (i == len + align1)
+	    p1[i] = 0;
+	  else
+	    {
+	      p1[i] = random () & BIG_CHAR;
+	      if (i >= align1 && i < len + align1 && !p1[i])
+		p1[i] = (random () & SMALL_CHAR) + 3;
+	    }
+	}
+
+    res = (UCHAR *) STRDUP((CHAR *) p1 + align1);
+	TEST_COMPARE_STRING((CHAR *) res, (CHAR *) (p1 + align1));
+	free(res);
+    }
+}
+
+
+int
+test_main (void)
+{
+  size_t i;
+
+  test_init ();
+
+  printf ("%23s", "");
+  printf ("\t%s", TEST_NAME);
+  putchar ('\n');
+
+  for (i = 0; i < 16; ++i)
+    {
+      do_test (0, 0, i, SMALL_CHAR);
+      do_test (0, 0, i, BIG_CHAR);
+      do_test (0, i, i, SMALL_CHAR);
+      do_test (i, 0, i, BIG_CHAR);
+    }
+
+  for (i = 1; i < 8; ++i)
+    {
+      do_test (0, 0, 8 << i, SMALL_CHAR);
+      do_test (8 - i, 2 * i, 8 << i, SMALL_CHAR);
+    }
+
+  for (i = 1; i < 8; ++i)
+    {
+      do_test (i, 2 * i, 8 << i, SMALL_CHAR);
+      do_test (2 * i, i, 8 << i, BIG_CHAR);
+      do_test (i, i, 8 << i, SMALL_CHAR);
+      do_test (i, i, 8 << i, BIG_CHAR);
+    }
+
+  do_zero_len_test ();
+  do_random_tests ();
+
+  return ret;
+}
+
+#include <support/test-driver.c>