>From 4110c01cb60ea810e5f4abb38224eac0b1560462 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Sun, 15 Dec 2019 21:48:05 +0100 Subject: [PATCH 2/2] setlocale-null: Add tests. * tests/test-setlocale_null.c: New file. * tests/test-setlocale_null-one.c: New file. * tests/test-setlocale_null-all.c: New file. * modules/setlocale-null-tests: New file. --- ChangeLog | 6 ++ modules/setlocale-null-tests | 23 +++++++ tests/test-setlocale_null-all.c | 148 ++++++++++++++++++++++++++++++++++++++++ tests/test-setlocale_null-one.c | 148 ++++++++++++++++++++++++++++++++++++++++ tests/test-setlocale_null.c | 32 +++++++++ 5 files changed, 357 insertions(+) create mode 100644 modules/setlocale-null-tests create mode 100644 tests/test-setlocale_null-all.c create mode 100644 tests/test-setlocale_null-one.c create mode 100644 tests/test-setlocale_null.c diff --git a/ChangeLog b/ChangeLog index 51f367c..af1d5bf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2019-12-15 Bruno Haible + setlocale-null: Add tests. + * tests/test-setlocale_null.c: New file. + * tests/test-setlocale_null-one.c: New file. + * tests/test-setlocale_null-all.c: New file. + * modules/setlocale-null-tests: New file. + setlocale-null: New module. * lib/locale.in.h (SETLOCALE_NULL_MAX, SETLOCALE_NULL_ALL_MAX, setlocale_null): New declarations. diff --git a/modules/setlocale-null-tests b/modules/setlocale-null-tests new file mode 100644 index 0000000..2114848 --- /dev/null +++ b/modules/setlocale-null-tests @@ -0,0 +1,23 @@ +Files: +tests/test-setlocale_null.c +tests/test-setlocale_null-one.c +tests/test-setlocale_null-all.c + +Depends-on: +thread +nanosleep + +configure.ac: + +Makefile.am: +TESTS += \ + test-setlocale_null \ + test-setlocale_null-one \ + test-setlocale_null-all +check_PROGRAMS += \ + test-setlocale_null \ + test-setlocale_null-one \ + test-setlocale_null-all +test_setlocale_null_LDADD = $(LDADD) @LIB_SETLOCALE_NULL@ +test_setlocale_null_one_LDADD = $(LDADD) @LIB_SETLOCALE_NULL@ $(LIBMULTITHREAD) $(LIB_NANOSLEEP) +test_setlocale_null_all_LDADD = $(LDADD) @LIB_SETLOCALE_NULL@ $(LIBMULTITHREAD) $(LIB_NANOSLEEP) diff --git a/tests/test-setlocale_null-all.c b/tests/test-setlocale_null-all.c new file mode 100644 index 0000000..b3ebb13 --- /dev/null +++ b/tests/test-setlocale_null-all.c @@ -0,0 +1,148 @@ +/* Multithread-safety test for setlocale_null (LC_ALL, ...). + Copyright (C) 2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2019. */ + +#include + +/* Specification. */ +#include + +#include +#include +#include +#include + +#include "glthread/thread.h" + + +/* Some common locale names. */ + +#if defined _WIN32 && !defined __CYGWIN__ +# define ENGLISH "English_United States" +# define GERMAN "German_Germany" +# define FRENCH "French_France" +# define ENCODING ".1252" +#else +# define ENGLISH "en_US" +# define GERMAN "de_DE" +# define FRENCH "fr_FR" +# if defined __sgi +# define ENCODING ".ISO8859-15" +# elif defined __hpux +# define ENCODING ".utf8" +# else +# define ENCODING ".UTF-8" +# endif +#endif + +static const char LOCALE1[] = ENGLISH ENCODING; +static const char LOCALE2[] = GERMAN ENCODING; +static const char LOCALE3[] = FRENCH ENCODING; + +static char *expected; + +static void * +thread1_func (void *arg) +{ + for (;;) + { + char buf[SETLOCALE_NULL_ALL_MAX]; + + if (setlocale_null (LC_ALL, buf, sizeof (buf))) + abort (); + if (strcmp (expected, buf) != 0) + { + fprintf (stderr, "thread1 disturbed by thread2!\n"); fflush (stderr); + abort (); + } + } + + /*NOTREACHED*/ + return NULL; +} + +static void * +thread2_func (void *arg) +{ + for (;;) + { + char buf[SETLOCALE_NULL_ALL_MAX]; + + setlocale_null (LC_NUMERIC, buf, sizeof (buf)); + setlocale_null (LC_ALL, buf, sizeof (buf)); + } + + /*NOTREACHED*/ + return NULL; +} + +int +main (int argc, char *argv[]) +{ + if (setlocale (LC_ALL, LOCALE1) == NULL) + { + fprintf (stderr, "Skipping test: LOCALE1 not recognized\n"); + return 77; + } + if (setlocale (LC_NUMERIC, LOCALE2) == NULL) + { + fprintf (stderr, "Skipping test: LOCALE2 not recognized\n"); + return 77; + } + if (setlocale (LC_TIME, LOCALE3) == NULL) + { + fprintf (stderr, "Skipping test: LOCALE3 not recognized\n"); + return 77; + } + + expected = strdup (setlocale (LC_ALL, NULL)); + + /* Create the two threads. */ + gl_thread_create (thread1_func, NULL); + gl_thread_create (thread2_func, NULL); + + /* Let them run for 5 seconds. */ + { + struct timespec duration; + duration.tv_sec = 5; + duration.tv_nsec = 0; + + nanosleep (&duration, NULL); + } + + return 0; +} + +/* Without locking, the results of this test would be: +glibc OK +musl libc crash < 10 sec +macOS crash < 1 sec +FreeBSD crash < 1 sec +NetBSD crash < 2 sec +OpenBSD crash < 1 sec +AIX crash < 2 sec +HP-UX OK +IRIX OK +Solaris 10 OK +Solaris 11.0 OK +Solaris 11.4 OK +Solaris OpenIndiana OK +Haiku crash < 1 sec +Cygwin crash < 1 sec +mingw OK +MSVC OK (assuming compiler option /MD !) +*/ diff --git a/tests/test-setlocale_null-one.c b/tests/test-setlocale_null-one.c new file mode 100644 index 0000000..1aa5eaa --- /dev/null +++ b/tests/test-setlocale_null-one.c @@ -0,0 +1,148 @@ +/* Multithread-safety test for setlocale_null (LC_xxx, ...). + Copyright (C) 2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2019. */ + +#include + +/* Specification. */ +#include + +#include +#include +#include +#include + +#include "glthread/thread.h" + + +/* Some common locale names. */ + +#if defined _WIN32 && !defined __CYGWIN__ +# define ENGLISH "English_United States" +# define GERMAN "German_Germany" +# define FRENCH "French_France" +# define ENCODING ".1252" +#else +# define ENGLISH "en_US" +# define GERMAN "de_DE" +# define FRENCH "fr_FR" +# if defined __sgi +# define ENCODING ".ISO8859-15" +# elif defined __hpux +# define ENCODING ".utf8" +# else +# define ENCODING ".UTF-8" +# endif +#endif + +static const char LOCALE1[] = ENGLISH ENCODING; +static const char LOCALE2[] = GERMAN ENCODING; +static const char LOCALE3[] = FRENCH ENCODING; + +static char *expected; + +static void * +thread1_func (void *arg) +{ + for (;;) + { + char buf[SETLOCALE_NULL_MAX]; + + if (setlocale_null (LC_NUMERIC, buf, sizeof (buf))) + abort (); + if (strcmp (expected, buf) != 0) + { + fprintf (stderr, "thread1 disturbed by thread2!\n"); fflush (stderr); + abort (); + } + } + + /*NOTREACHED*/ + return NULL; +} + +static void * +thread2_func (void *arg) +{ + for (;;) + { + char buf[SETLOCALE_NULL_MAX]; + + setlocale_null (LC_NUMERIC, buf, sizeof (buf)); + setlocale_null (LC_TIME, buf, sizeof (buf)); + } + + /*NOTREACHED*/ + return NULL; +} + +int +main (int argc, char *argv[]) +{ + if (setlocale (LC_ALL, LOCALE1) == NULL) + { + fprintf (stderr, "Skipping test: LOCALE1 not recognized\n"); + return 77; + } + if (setlocale (LC_NUMERIC, LOCALE2) == NULL) + { + fprintf (stderr, "Skipping test: LOCALE2 not recognized\n"); + return 77; + } + if (setlocale (LC_TIME, LOCALE3) == NULL) + { + fprintf (stderr, "Skipping test: LOCALE3 not recognized\n"); + return 77; + } + + expected = strdup (setlocale (LC_NUMERIC, NULL)); + + /* Create the two threads. */ + gl_thread_create (thread1_func, NULL); + gl_thread_create (thread2_func, NULL); + + /* Let them run for 2 seconds. */ + { + struct timespec duration; + duration.tv_sec = 2; + duration.tv_nsec = 0; + + nanosleep (&duration, NULL); + } + + return 0; +} + +/* Without locking, the results of this test would be: +glibc OK +musl libc OK +macOS OK +FreeBSD OK +NetBSD OK +OpenBSD crash < 1 sec +AIX crash < 2 sec +HP-UX OK +IRIX OK +Solaris 10 OK +Solaris 11.0 OK +Solaris 11.4 OK +Solaris OpenIndiana OK +Haiku OK +Cygwin OK +mingw OK +MSVC OK (assuming compiler option /MD !) +*/ diff --git a/tests/test-setlocale_null.c b/tests/test-setlocale_null.c new file mode 100644 index 0000000..003cfc9 --- /dev/null +++ b/tests/test-setlocale_null.c @@ -0,0 +1,32 @@ +/* Test of setlocale_null function. + Copyright (C) 2019 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Written by Bruno Haible , 2019. */ + +#include + +/* Specification. */ +#include + +/* Check that SETLOCALE_NULL_ALL_MAX is a constant expression. */ +static char buf[SETLOCALE_NULL_ALL_MAX]; + +int +main () +{ + /* Check that setlocale_null () can be used with $(LIB_SETLOCALE_NULL). */ + return setlocale_null (LC_ALL, buf, sizeof (buf)) != 0; +} -- 2.7.4