[PATCH v2] x86: Fix page cross case in rawmemchr-avx2 [BZ #29234]

Sunil Pandey skpgkp2@gmail.com
Thu Jul 14 02:45:23 GMT 2022


On Wed, Jun 8, 2022 at 3:41 PM H.J. Lu via Libc-alpha
<libc-alpha@sourceware.org> wrote:
>
> On Wed, Jun 8, 2022 at 2:35 PM Noah Goldstein <goldstein.w.n@gmail.com> wrote:
> >
> > commit 6dcbb7d95dded20153b12d76d2f4e0ef0cda4f35
> > Author: Noah Goldstein <goldstein.w.n@gmail.com>
> > Date:   Mon Jun 6 21:11:33 2022 -0700
> >
> >     x86: Shrink code size of memchr-avx2.S
> >
> > Changed how the page cross case aligned string (rdi) in
> > rawmemchr. This was incompatible with how
> > `L(cross_page_continue)` expected the pointer to be aligned and
> > would cause rawmemchr to read data start started before the
> > beginning of the string. What it would read was in valid memory
> > but could count CHAR matches resulting in an incorrect return
> > value.
> >
> > This commit fixes that issue by essentially reverting the changes to
> > the L(page_cross) case as they didn't really matter.
> >
> > Test cases added and all pass with the new code (and where confirmed
> > to fail with the old code).
> > ---
> >  string/test-rawmemchr.c                | 57 +++++++++++++++++++++++++-
> >  sysdeps/x86_64/multiarch/memchr-avx2.S | 16 ++++----
> >  2 files changed, 64 insertions(+), 9 deletions(-)
> >
> > diff --git a/string/test-rawmemchr.c b/string/test-rawmemchr.c
> > index cafb75298a..703e8ec27c 100644
> > --- a/string/test-rawmemchr.c
> > +++ b/string/test-rawmemchr.c
> > @@ -17,6 +17,7 @@
> >     <https://www.gnu.org/licenses/>.  */
> >
> >  #include <assert.h>
> > +#include <support/xunistd.h>
> >
> >  #define TEST_MAIN
> >  #define TEST_NAME "rawmemchr"
> > @@ -50,13 +51,45 @@ do_one_test (impl_t *impl, const char *s, int c, char *exp_res)
> >      }
> >  }
> >
> > +static void
> > +do_test_bz29234 (void)
> > +{
> > +  size_t i, j;
> > +  char *ptr_start;
> > +  char *buf = xmmap (0, 8192, PROT_READ | PROT_WRITE,
> > +                    MAP_PRIVATE | MAP_ANONYMOUS, -1);
> > +
> > +  memset (buf, -1, 8192);
> > +
> > +  ptr_start = buf + 4096 - 8;
> > +
> > +  /* Out of range matches before the start of a page. */
> > +  memset (ptr_start - 8, 0x1, 8);
> > +
> > +  for (j = 0; j < 8; ++j)
> > +    {
> > +      for (i = 0; i < 128; ++i)
> > +       {
> > +         ptr_start[i + j] = 0x1;
> > +
> > +         FOR_EACH_IMPL (impl, 0)
> > +           do_one_test (impl, (char *) (ptr_start + j), 0x1,
> > +                        ptr_start + i + j);
> > +
> > +         ptr_start[i + j] = 0xff;
> > +       }
> > +    }
> > +
> > +  xmunmap (buf, 8192);
> > +}
> > +
> >  static void
> >  do_test (size_t align, size_t pos, size_t len, int seek_char)
> >  {
> >    size_t i;
> >    char *result;
> >
> > -  align &= 7;
> > +  align &= getpagesize () - 1;
> >    if (align + len >= page_size)
> >      return;
> >
> > @@ -114,6 +147,13 @@ do_random_tests (void)
> >             }
> >         }
> >
> > +      if (align)
> > +       {
> > +         p[align - 1] = seek_char;
> > +         if (align > 4)
> > +           p[align - 4] = seek_char;
> > +       }
> > +
> >        assert (pos < len);
> >        size_t r = random ();
> >        if ((r & 31) == 0)
> > @@ -129,6 +169,13 @@ do_random_tests (void)
> >                    result, p);
> >             ret = 1;
> >           }
> > +
> > +      if (align)
> > +       {
> > +         p[align - 1] = seek_char;
> > +         if (align > 4)
> > +           p[align - 4] = seek_char;
> > +       }
> >      }
> >  }
> >
> > @@ -150,14 +197,22 @@ test_main (void)
> >        do_test (i, 64, 256, 23);
> >        do_test (0, 16 << i, 2048, 0);
> >        do_test (i, 64, 256, 0);
> > +
> > +      do_test (getpagesize () - i, 64, 256, 23);
> > +      do_test (getpagesize () - i, 64, 256, 0);
> >      }
> >    for (i = 1; i < 32; ++i)
> >      {
> >        do_test (0, i, i + 1, 23);
> >        do_test (0, i, i + 1, 0);
> > +
> > +      do_test (getpagesize () - 7, i, i + 1, 23);
> > +      do_test (getpagesize () - i / 2, i, i + 1, 23);
> > +      do_test (getpagesize () - i, i, i + 1, 23);
> >      }
> >
> >    do_random_tests ();
> > +  do_test_bz29234 ();
> >    return ret;
> >  }
> >
> > diff --git a/sysdeps/x86_64/multiarch/memchr-avx2.S b/sysdeps/x86_64/multiarch/memchr-avx2.S
> > index 28a01280ec..c5a256eb37 100644
> > --- a/sysdeps/x86_64/multiarch/memchr-avx2.S
> > +++ b/sysdeps/x86_64/multiarch/memchr-avx2.S
> > @@ -409,19 +409,19 @@ L(cross_page_boundary):
> >            computer return address if byte is found or adjusting length if it
> >            is not and this is memchr.  */
> >         movq    %rdi, %rcx
> > -       /* Align data to VEC_SIZE. ALGN_PTR_REG is rcx for memchr and rdi for
> > -          rawmemchr.  */
> > -       andq    $-VEC_SIZE, %ALGN_PTR_REG
> > -       VPCMPEQ (%ALGN_PTR_REG), %ymm0, %ymm1
> > +       /* Align data to VEC_SIZE - 1. ALGN_PTR_REG is rcx for memchr
> > +          and rdi for rawmemchr.  */
> > +       orq     $(VEC_SIZE - 1), %ALGN_PTR_REG
> > +       VPCMPEQ -(VEC_SIZE - 1)(%ALGN_PTR_REG), %ymm0, %ymm1
> >         vpmovmskb %ymm1, %eax
> >  # ifndef USE_AS_RAWMEMCHR
> >         /* Calculate length until end of page (length checked for a match).  */
> > -       leal    VEC_SIZE(%ALGN_PTR_REG), %esi
> > -       subl    %ERAW_PTR_REG, %esi
> > -# ifdef USE_AS_WMEMCHR
> > +       leaq    1(%ALGN_PTR_REG), %rsi
> > +       subq    %RRAW_PTR_REG, %rsi
> > +#  ifdef USE_AS_WMEMCHR
> >         /* NB: Divide bytes by 4 to get wchar_t count.  */
> >         shrl    $2, %esi
> > -# endif
> > +#  endif
> >  # endif
> >         /* Remove the leading bytes.  */
> >         sarxl   %ERAW_PTR_REG, %eax, %eax
> > --
> > 2.34.1
> >
>
> LGTM.
>
> Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
>
> Thanks.
>
> --
> H.J.

I would like to backport this patch to release branches.
Any comments or objections?

--Sunil


More information about the Libc-alpha mailing list