Message ID | 20221214195134.4168417-1-hjl.tools@gmail.com |
---|---|
State | New |
Headers | show |
Series | [v2] x86: Add a testcase for BZ #29863 | expand |
On Wed, Dec 14, 2022 at 11:51 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > When a thread is updating the memory area of memcmp and another thread > is doing memcmp, the memcmp return value is undefined. Add a testcase > to verify that memcmp won't segfault in this case. > --- > sysdeps/x86/Makefile | 8 +++ > sysdeps/x86/tst-memcmp-race.c | 117 ++++++++++++++++++++++++++++++++++ > 2 files changed, 125 insertions(+) > create mode 100644 sysdeps/x86/tst-memcmp-race.c > > diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile > index 56fd5fc805..c3f05a06ab 100644 > --- a/sysdeps/x86/Makefile > +++ b/sysdeps/x86/Makefile > @@ -257,3 +257,11 @@ tests += \ > tests-static += \ > tst-sysconf-cache-linesize-static > endif > + > +ifeq ($(subdir),nptl) > +tests += \ > + tst-memcmp-race \ > +# tests > + > +CFLAGS-tst-memcmp-race.c += -O0 > +endif > diff --git a/sysdeps/x86/tst-memcmp-race.c b/sysdeps/x86/tst-memcmp-race.c > new file mode 100644 > index 0000000000..5630ae9472 > --- /dev/null > +++ b/sysdeps/x86/tst-memcmp-race.c > @@ -0,0 +1,117 @@ > +/* Test case for memcmp with race condition. > + Copyright (C) 2022 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/>. */ > + > +/* Verify that there is no segfault when one thread is updating the > + memory block of memcmp and the other thread is doing memcmp. */ > + > +#define TEST_MAIN > +#define TEST_NAME "memcmp" > + > +#include <stdio.h> > +#include <stdint.h> > +#include <string.h> > +#include <string/test-string.h> > +#include <support/xthread.h> > + > +#define NUM_THREADS 2 > +#define STR "abcdefghijklmnopq" Remove. > +#define LOOP1 100 > +#define LOOP2 1000000 > + > +typedef int (*proto_t) (const void *, const void *, size_t); > + > +IMPL (memcmp, 1) > + > +struct arg > +{ > + proto_t func; > + size_t len; > + int i; > +}; > + > +static void * > +childThread (void *tArgs) > +{ > + struct arg *a = (struct arg *) tArgs; > + int i; > + > + if (0 == a->i % 2) > + { > + for (i = 0; i < LOOP1; i++) > + { > + int result = a->func (buf1, buf2, a->len); > + printf ("i = %d : result = %d\n", i, result); > + } > + } > + else > + { > + for (i = 0; i < LOOP2; i++) > + buf1[1] = (0 == (i % 2)) ? 'b' : 'c'; buf1[1] = (i & 1); > + } > + > + return NULL; > +} > + > +static void > +do_one_test (proto_t func, size_t len) > +{ > + int i; > + pthread_t threads[NUM_THREADS]; > + struct arg a[NUM_THREADS]; > + > + for (i = 0; i < NUM_THREADS; ++i) > + { > + a[i].func = func; > + a[i].len = len; > + a[i].i = i; > + threads[i] = xpthread_create (NULL, childThread, (void *)&a[i]); > + } > + > + for (i = 0; i < NUM_THREADS; ++i) > + xpthread_join (threads[i]); > +} > + > +int > +test_main (void) > +{ > + test_init (); > + > + size_t remain = page_size; > + size_t offset = 0; > + do > + { > + size_t len = sizeof STR - 1; > + if (len > remain) > + len = remain; > + memcpy (buf1 + offset, STR, len); > + memcpy (buf2 + offset, STR, len); > + offset += len; > + remain -= len; > + } > + while (remain > 0); memset(buf1, 1, page_size); memset(buf2, 1, page_size); > + > + for (size_t i = 0; i <= 11; i++) > + { > + FOR_EACH_IMPL (impl, 0) > + do_one_test ((proto_t) impl->fn, (1 << i) + 1); > + } > + > + return 0; > +} > + > +#include <support/test-driver.c> > -- > 2.38.1 >
On Wed, Dec 14, 2022 at 12:06 PM Noah Goldstein <goldstein.w.n@gmail.com> wrote: > > On Wed, Dec 14, 2022 at 11:51 AM H.J. Lu <hjl.tools@gmail.com> wrote: > > > > When a thread is updating the memory area of memcmp and another thread > > is doing memcmp, the memcmp return value is undefined. Add a testcase > > to verify that memcmp won't segfault in this case. > > --- > > sysdeps/x86/Makefile | 8 +++ > > sysdeps/x86/tst-memcmp-race.c | 117 ++++++++++++++++++++++++++++++++++ > > 2 files changed, 125 insertions(+) > > create mode 100644 sysdeps/x86/tst-memcmp-race.c > > > > diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile > > index 56fd5fc805..c3f05a06ab 100644 > > --- a/sysdeps/x86/Makefile > > +++ b/sysdeps/x86/Makefile > > @@ -257,3 +257,11 @@ tests += \ > > tests-static += \ > > tst-sysconf-cache-linesize-static > > endif > > + > > +ifeq ($(subdir),nptl) > > +tests += \ > > + tst-memcmp-race \ > > +# tests > > + > > +CFLAGS-tst-memcmp-race.c += -O0 > > +endif > > diff --git a/sysdeps/x86/tst-memcmp-race.c b/sysdeps/x86/tst-memcmp-race.c > > new file mode 100644 > > index 0000000000..5630ae9472 > > --- /dev/null > > +++ b/sysdeps/x86/tst-memcmp-race.c > > @@ -0,0 +1,117 @@ > > +/* Test case for memcmp with race condition. > > + Copyright (C) 2022 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/>. */ > > + > > +/* Verify that there is no segfault when one thread is updating the > > + memory block of memcmp and the other thread is doing memcmp. */ > > + > > +#define TEST_MAIN > > +#define TEST_NAME "memcmp" > > + > > +#include <stdio.h> > > +#include <stdint.h> > > +#include <string.h> > > +#include <string/test-string.h> > > +#include <support/xthread.h> > > + > > +#define NUM_THREADS 2 > > +#define STR "abcdefghijklmnopq" > > Remove. > > > +#define LOOP1 100 > > +#define LOOP2 1000000 > > + > > +typedef int (*proto_t) (const void *, const void *, size_t); > > + > > +IMPL (memcmp, 1) > > + > > +struct arg > > +{ > > + proto_t func; > > + size_t len; > > + int i; > > +}; > > + > > +static void * > > +childThread (void *tArgs) > > +{ > > + struct arg *a = (struct arg *) tArgs; > > + int i; > > + > > + if (0 == a->i % 2) > > + { > > + for (i = 0; i < LOOP1; i++) > > + { > > + int result = a->func (buf1, buf2, a->len); > > + printf ("i = %d : result = %d\n", i, result); > > + } > > + } > > + else > > + { > > + for (i = 0; i < LOOP2; i++) > > + buf1[1] = (0 == (i % 2)) ? 'b' : 'c'; > > buf1[1] = (i & 1); Fixed in v4. > > + } > > + > > + return NULL; > > +} > > + > > +static void > > +do_one_test (proto_t func, size_t len) > > +{ > > + int i; > > + pthread_t threads[NUM_THREADS]; > > + struct arg a[NUM_THREADS]; > > + > > + for (i = 0; i < NUM_THREADS; ++i) > > + { > > + a[i].func = func; > > + a[i].len = len; > > + a[i].i = i; > > + threads[i] = xpthread_create (NULL, childThread, (void *)&a[i]); > > + } > > + > > + for (i = 0; i < NUM_THREADS; ++i) > > + xpthread_join (threads[i]); > > +} > > + > > +int > > +test_main (void) > > +{ > > + test_init (); > > + > > + size_t remain = page_size; > > + size_t offset = 0; > > + do > > + { > > + size_t len = sizeof STR - 1; > > + if (len > remain) > > + len = remain; > > + memcpy (buf1 + offset, STR, len); > > + memcpy (buf2 + offset, STR, len); > > + offset += len; > > + remain -= len; > > + } > > + while (remain > 0); > > memset(buf1, 1, page_size); > memset(buf2, 1, page_size); Fixed in v4. > > + > > + for (size_t i = 0; i <= 11; i++) > > + { > > + FOR_EACH_IMPL (impl, 0) > > + do_one_test ((proto_t) impl->fn, (1 << i) + 1); > > + } > > + > > + return 0; > > +} > > + > > +#include <support/test-driver.c> > > -- > > 2.38.1 > > Thanks.
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile index 56fd5fc805..c3f05a06ab 100644 --- a/sysdeps/x86/Makefile +++ b/sysdeps/x86/Makefile @@ -257,3 +257,11 @@ tests += \ tests-static += \ tst-sysconf-cache-linesize-static endif + +ifeq ($(subdir),nptl) +tests += \ + tst-memcmp-race \ +# tests + +CFLAGS-tst-memcmp-race.c += -O0 +endif diff --git a/sysdeps/x86/tst-memcmp-race.c b/sysdeps/x86/tst-memcmp-race.c new file mode 100644 index 0000000000..5630ae9472 --- /dev/null +++ b/sysdeps/x86/tst-memcmp-race.c @@ -0,0 +1,117 @@ +/* Test case for memcmp with race condition. + Copyright (C) 2022 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/>. */ + +/* Verify that there is no segfault when one thread is updating the + memory block of memcmp and the other thread is doing memcmp. */ + +#define TEST_MAIN +#define TEST_NAME "memcmp" + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <string/test-string.h> +#include <support/xthread.h> + +#define NUM_THREADS 2 +#define STR "abcdefghijklmnopq" +#define LOOP1 100 +#define LOOP2 1000000 + +typedef int (*proto_t) (const void *, const void *, size_t); + +IMPL (memcmp, 1) + +struct arg +{ + proto_t func; + size_t len; + int i; +}; + +static void * +childThread (void *tArgs) +{ + struct arg *a = (struct arg *) tArgs; + int i; + + if (0 == a->i % 2) + { + for (i = 0; i < LOOP1; i++) + { + int result = a->func (buf1, buf2, a->len); + printf ("i = %d : result = %d\n", i, result); + } + } + else + { + for (i = 0; i < LOOP2; i++) + buf1[1] = (0 == (i % 2)) ? 'b' : 'c'; + } + + return NULL; +} + +static void +do_one_test (proto_t func, size_t len) +{ + int i; + pthread_t threads[NUM_THREADS]; + struct arg a[NUM_THREADS]; + + for (i = 0; i < NUM_THREADS; ++i) + { + a[i].func = func; + a[i].len = len; + a[i].i = i; + threads[i] = xpthread_create (NULL, childThread, (void *)&a[i]); + } + + for (i = 0; i < NUM_THREADS; ++i) + xpthread_join (threads[i]); +} + +int +test_main (void) +{ + test_init (); + + size_t remain = page_size; + size_t offset = 0; + do + { + size_t len = sizeof STR - 1; + if (len > remain) + len = remain; + memcpy (buf1 + offset, STR, len); + memcpy (buf2 + offset, STR, len); + offset += len; + remain -= len; + } + while (remain > 0); + + for (size_t i = 0; i <= 11; i++) + { + FOR_EACH_IMPL (impl, 0) + do_one_test ((proto_t) impl->fn, (1 << i) + 1); + } + + return 0; +} + +#include <support/test-driver.c>