1  /* { dg-do run { target { sysconf && mmap } } } */
       2  /* { dg-options "-O2 -minline-all-stringops" } */
       3  
       4  #include <stdint.h>
       5  #include <string.h>
       6  #include <stdlib.h>
       7  #include <unistd.h>
       8  #include <sys/mman.h>
       9  #ifndef MAP_ANON
      10  #define MAP_ANON 0
      11  #endif
      12  #ifndef MAP_FAILED
      13  #define MAP_FAILED ((void *)-1)
      14  #endif
      15  
      16  uint8_t shift[256];
      17  
      18  static size_t
      19  __attribute__ ((noclone, noinline))
      20  hash2(const unsigned char *p)
      21  {
      22    return (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift));
      23  }
      24  
      25  char *
      26  simple_strstr (const char *haystack, const char *needle)
      27  {
      28    const unsigned char *hs = (const unsigned char *) haystack;
      29    const unsigned char *ne = (const unsigned char *) needle;
      30    size_t ne_len = strlen ((const char*)ne);
      31    size_t hs_len = strnlen ((const char*)hs, ne_len | 512);
      32  
      33    if (hs_len < ne_len)
      34      return NULL;
      35  
      36    if (memcmp (hs, ne, ne_len) == 0)
      37      return (char *) hs;
      38  
      39    const unsigned char *end = hs + hs_len - ne_len;
      40    size_t tmp, shift1;
      41    size_t m1 = ne_len - 1;
      42    size_t offset = 0;
      43  
      44    memset (shift, 0, sizeof (shift));
      45    for (int i = 1; i < m1; i++)
      46      shift[hash2 (ne + i)] = i;
      47    shift1 = m1 - shift[hash2 (ne + m1)];
      48    shift[hash2 (ne + m1)] = m1;
      49  
      50    while (1)
      51      {
      52        if (__builtin_expect (hs > end, 0))
      53  	{
      54  	  end += strnlen ((const char*)end + m1 + 1, 2048);
      55  	  if (hs > end)
      56  	    return NULL;
      57  	}
      58  
      59        do
      60  	{
      61  	  hs += m1;
      62  	  tmp = shift[hash2 (hs)];
      63  	}
      64        while (tmp == 0 && hs <= end);
      65  
      66        hs -= tmp;
      67        if (tmp < m1)
      68  	continue;
      69  
      70        if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
      71  	{
      72  	  if (memcmp (hs, ne, m1) == 0)
      73  	    return (void *) hs;
      74  
      75  	  offset = (offset >= 8 ? offset : m1) - 8;
      76  	}
      77  
      78        hs += shift1;
      79      }
      80  }
      81  
      82  static int
      83  check_result (const char *s1, const char *s2,
      84  	      char *exp_result)
      85  {
      86    char *result = simple_strstr (s1, s2);
      87    if (result != exp_result)
      88      return -1;
      89  
      90    return 0;
      91  }
      92  
      93  void
      94  __attribute__ ((noclone, noinline))
      95  check1 (void)
      96  {
      97    const char s1[] =
      98      "F_BD_CE_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_C3_88_20_EF_BF_BD_EF_BF_BD_EF_BF_BD_C3_A7_20_EF_BF_BD";
      99    const char s2[] = "_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD_EF_BF_BD";
     100    char *exp_result;
     101  
     102    exp_result = simple_strstr (s1, s2);
     103    if (check_result (s1, s2, exp_result) != 0)
     104      abort ();
     105  }
     106  
     107  int
     108  main (void)
     109  {
     110    unsigned char *buf1, *buf2;
     111    size_t page_size = 2 * sysconf(_SC_PAGESIZE);
     112    buf1 = mmap (0, (1 + 1) * page_size, PROT_READ | PROT_WRITE,
     113  	       MAP_PRIVATE | MAP_ANON, -1, 0);
     114    if (buf1 == MAP_FAILED)
     115      return -1;
     116    if (mprotect (buf1 + 1 * page_size, page_size, PROT_NONE))
     117      return -1;
     118    buf2 = mmap (0, 2 * page_size, PROT_READ | PROT_WRITE,
     119  	       MAP_PRIVATE | MAP_ANON, -1, 0);
     120    if (buf2 == MAP_FAILED)
     121      return -1;
     122    if (mprotect (buf2 + page_size, page_size, PROT_NONE))
     123      return -1;
     124  
     125    memset (buf1, 0xa5, 1 * page_size);
     126    memset (buf2, 0x5a, page_size);
     127  
     128    check1 ();
     129    return 0;
     130  }