]> sourceware.org Git - glibc.git/commitdiff
Use correct signedness in wcsncmp
authorStefan Liebler <stli@linux.vnet.ibm.com>
Mon, 13 Apr 2015 19:23:10 +0000 (21:23 +0200)
committerAndreas Krebbel <krebbel@linux.vnet.ibm.com>
Mon, 13 Apr 2015 19:25:04 +0000 (21:25 +0200)
[BZ #18206]
* wcsmbs/wcsncmp.c (wcsncmp): Compare as wchar_t, not wint_t.
  Use signed comparision instead of substraction to avoid
  overflow bug.
* localedata/tests-mbwc/tst_wcsncmp.c (tst_wcsncmp):
  Take the sign of ret.
* localedata/tests-mbwc/dat_wcsncmp.c (tst_wcsncmp_loc):
  Do not expect precise return values. Only the sign matters.
* wcsmbs/Makefile (strop-tests): Add wcsncmp.
* wcsmbs/test-wcsncmp.c: New File.
* string/test-strncmp.c: Add wcsncmp support.

ChangeLog
NEWS
localedata/tests-mbwc/dat_wcsncmp.c
localedata/tests-mbwc/tst_wcsncmp.c
string/test-strncmp.c
wcsmbs/Makefile
wcsmbs/test-wcsncmp.c [new file with mode: 0644]
wcsmbs/wcsncmp.c

index 60c1bd6835e5a4628697bc6f27b562b9b8f5afd9..489495b735a8a1bb444750e58cd9cc721a7d6bcb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2015-04-13  Stefan Liebler  <stli@linux.vnet.ibm.com>
+
+       [BZ #18206]
+       * wcsmbs/wcsncmp.c (wcsncmp): Compare as wchar_t, not wint_t.
+         Use signed comparision instead of substraction to avoid
+         overflow bug.
+       * localedata/tests-mbwc/tst_wcsncmp.c (tst_wcsncmp):
+         Take the sign of ret.
+       * localedata/tests-mbwc/dat_wcsncmp.c (tst_wcsncmp_loc):
+         Do not expect precise return values. Only the sign matters.
+       * wcsmbs/Makefile (strop-tests): Add wcsncmp.
+       * wcsmbs/test-wcsncmp.c: New File.
+       * string/test-strncmp.c: Add wcsncmp support.
+
 2015-04-13  Stefan Liebler  <stli@linux.vnet.ibm.com>
 
        [BZ #6792]
diff --git a/NEWS b/NEWS
index fb614bed25ae83d4c2e11c872f3cdecdf85db098..2bbd6a3f8bd93419d976f92186a189c978c3c4e9 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -16,7 +16,7 @@ Version 2.22
   17969, 17978, 17987, 17991, 17996, 17998, 17999, 18019, 18020, 18029,
   18030, 18032, 18036, 18038, 18039, 18042, 18043, 18046, 18047, 18068,
   18080, 18093, 18100, 18104, 18110, 18111, 18128, 18138, 18185, 18197,
-  18210, 18211, 18247.
+  18206, 18210, 18211, 18247.
 
 * A powerpc and powerpc64 optimization for TLS, similar to TLS descriptors
   for LD and GD on x86 and x86-64, has been implemented.  You will need
index 167ce48a7f9ee2cf7b37612d24ba28f421291ab0..f468a8b358f58f09474d249293d988de2d79c913 100644 (file)
@@ -33,7 +33,7 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
       },
       { /*input.*/ { { 0x00D1,0x00D2,0x00D3,0x0000 },
                     { 0x0000,0x00D2,0x00D3,0x0000 }, 3 },  /* #06 */
-       /*expect*/ { 0,1,0x00D1,                        },
+       /*expect*/ { 0,1,1,                     },
       },
       { /*input.*/ { { 0x00D1,0x00D2,0x00D3,0x0000 },
                     { 0x00D1,0x00D2,0x00D9,0x0000 }, 2 },  /* #07 */
@@ -41,11 +41,11 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
       },
       { /*input.*/ { { 0x00D1,0x00D2,0x00D3,0x0000 },
                     { 0x00D1,0x00D2,0x00D9,0x0000 }, 3 },  /* #08 */
-       /*expect*/ { 0,1,-0x0006,                       },
+       /*expect*/ { 0,1,-1,                    },
       },
       { /*input.*/ { { 0x00D1,0x00D2,0x00D3,0x0000 },
                     { 0x00D1,0x00D2,0x0000        }, 4 },  /* #09 */
-       /*expect*/ { 0,1,0x00D3,                        },
+       /*expect*/ { 0,1,1,                     },
       },
       { .is_last = 1 }
     }
@@ -75,7 +75,7 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
       },
       { /*input.*/ { { 0x0041,0x0042,0x0043,0x0000 },
                     { 0x0000,0x0042,0x0043,0x0000 }, 3 },  /* #06 */
-       /*expect*/ { 0,1,0x0041,                        },
+       /*expect*/ { 0,1,1,                     },
       },
       { /*input.*/ { { 0x0041,0x0042,0x0043,0x0000 },
                     { 0x0041,0x0042,0x0049,0x0000 }, 2 },  /* #07 */
@@ -83,11 +83,11 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
       },
       { /*input.*/ { { 0x0041,0x0042,0x0043,0x0000 },
                     { 0x0041,0x0042,0x0049,0x0000 }, 3 },  /* #08 */
-       /*expect*/ { 0,1,-0x0006,                       },
+       /*expect*/ { 0,1,-1,                    },
       },
       { /*input.*/ { { 0x0041,0x0042,0x0043,0x0000 },
                     { 0x0041,0x0042,0x0000        }, 4 },  /* #09 */
-       /*expect*/ { 0,1,0x0043,                        },
+       /*expect*/ { 0,1,1,                     },
       },
       { .is_last = 1 }
     }
@@ -117,7 +117,7 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
       },
       { /*input.*/ { { 0x3041,0x3042,0x3043,0x0000 },
                     { 0x0000,0x3042,0x3043,0x0000 }, 3 },  /* #06 */
-       /*expect*/ { 0,1,0x3041,                        },
+       /*expect*/ { 0,1,1,                     },
       },
       { /*input.*/ { { 0x3041,0x3042,0x3043,0x0000 },
                     { 0x3041,0x3042,0x3049,0x0000 }, 2 },  /* #07 */
@@ -125,11 +125,11 @@ TST_WCSNCMP tst_wcsncmp_loc [] = {
       },
       { /*input.*/ { { 0x3041,0x3042,0x3043,0x0000 },
                     { 0x3041,0x3042,0x3049,0x0000 }, 3 },  /* #08 */
-       /*expect*/ { 0,1,-0x0006,                       },
+       /*expect*/ { 0,1,-1,                    },
       },
       { /*input.*/ { { 0x3041,0x3042,0x3043,0x0000 },
                     { 0x3041,0x3042,0x0000        }, 4 },  /* #09 */
-       /*expect*/ { 0,1,0x3043,                        },
+       /*expect*/ { 0,1,1,                     },
       },
       { .is_last = 1 }
     }
index d046ecd13374cdbd52af09502df8e0c83339d5b5..f93ca49e47408742cad692974c10afbc034d0d95 100644 (file)
@@ -24,6 +24,7 @@ tst_wcsncmp (FILE * fp, int debug_flg)
       ws2 = TST_INPUT (wcsncmp).ws2;
       n = TST_INPUT (wcsncmp).n;
       ret = wcsncmp (ws1, ws2, n);
+      ret = (ret > 0 ? 1 : ret < 0 ? -1 : 0);
 
       if (debug_flg)
        {
index aaf4b4aac79461aa205a75997d76c651819b47b3..fb57a9bdc5b5f9d40e1b60a8c9d9a72139e9e541 100644 (file)
@@ -1,4 +1,4 @@
-/* Test and measure strncmp functions.
+/* Test strncmp and wcsncmp functions.
    Copyright (C) 1999-2015 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Jakub Jelinek <jakub@redhat.com>, 1999.
    <http://www.gnu.org/licenses/>.  */
 
 #define TEST_MAIN
-#define TEST_NAME "strncmp"
+#ifdef WIDE
+# define TEST_NAME "wcsncmp"
+#else
+# define TEST_NAME "strncmp"
+#endif
 #include "test-string.h"
 
-typedef int (*proto_t) (const char *, const char *, size_t);
-int simple_strncmp (const char *, const char *, size_t);
-int stupid_strncmp (const char *, const char *, size_t);
+#ifdef WIDE
+# include <wchar.h>
+
+# define L(str) L##str
+# define STRNCMP wcsncmp
+# define STRCPY wcscpy
+# define STRDUP wcsdup
+# define MEMCPY wmemcpy
+# define SIMPLE_STRNCMP simple_wcsncmp
+# define STUPID_STRNCMP stupid_wcsncmp
+# define CHAR wchar_t
+# define UCHAR wchar_t
+# define CHARBYTES 4
+# define CHAR__MAX WCHAR_MAX
+# define CHAR__MIN WCHAR_MIN
+
+/* Wcsncmp uses signed semantics for comparison, not unsigned.
+   Avoid using substraction since possible overflow */
+int
+simple_wcsncmp (const CHAR *s1, const CHAR *s2, size_t n)
+{
+  wchar_t c1, c2;
+
+  while (n--)
+    {
+      c1 = *s1++;
+      c2 = *s2++;
+      if (c1 == L('\0') || c1 != c2)
+       return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
+    }
+  return 0;
+}
 
-IMPL (stupid_strncmp, 0)
-IMPL (simple_strncmp, 0)
-IMPL (strncmp, 1)
+int
+stupid_wcsncmp (const CHAR *s1, const CHAR *s2, size_t n)
+{
+  wchar_t c1, c2;
+  size_t ns1 = wcsnlen (s1, n) + 1, ns2 = wcsnlen (s2, n) + 1;
+
+  n = ns1 < n ? ns1 : n;
+  n = ns2 < n ? ns2 : n;
+
+  while (n--)
+    {
+      c1 = *s1++;
+      c2 = *s2++;
+      if (c1 != c2)
+       return c1 > c2 ? 1 : -1;
+    }
+  return 0;
+}
 
+#else
+# define L(str) str
+# define STRNCMP strncmp
+# define STRCPY strcpy
+# define STRDUP strdup
+# define MEMCPY memcpy
+# define SIMPLE_STRNCMP simple_strncmp
+# define STUPID_STRNCMP stupid_strncmp
+# define CHAR char
+# define UCHAR unsigned char
+# define CHARBYTES 1
+# define CHAR__MAX CHAR_MAX
+# define CHAR__MIN CHAR_MIN
+
+/* Strncmp uses unsigned semantics for comparison. */
 int
 simple_strncmp (const char *s1, const char *s2, size_t n)
 {
@@ -51,8 +114,17 @@ stupid_strncmp (const char *s1, const char *s2, size_t n)
   return ret;
 }
 
+#endif
+
+typedef int (*proto_t) (const CHAR *, const CHAR *, size_t);
+
+IMPL (STUPID_STRNCMP, 0)
+IMPL (SIMPLE_STRNCMP, 0)
+IMPL (STRNCMP, 1)
+
+
 static int
-check_result (impl_t *impl, const char *s1, const char *s2, size_t n,
+check_result (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t n,
             int exp_result)
 {
   int result = CALL (impl, s1, s2, n);
@@ -70,7 +142,7 @@ check_result (impl_t *impl, const char *s1, const char *s2, size_t n,
 }
 
 static void
-do_one_test (impl_t *impl, const char *s1, const char *s2, size_t n,
+do_one_test (impl_t *impl, const CHAR *s1, const CHAR *s2, size_t n,
             int exp_result)
 {
   if (check_result (impl, s1, s2, n, exp_result) < 0)
@@ -82,12 +154,12 @@ do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
         int exp_result)
 {
   size_t i, align_n;
-  char *s1, *s2;
+  CHAR *s1, *s2;
 
   if (n == 0)
     {
-      s1 = (char*)(buf1 + page_size);
-      s2 = (char*)(buf2 + page_size);
+      s1 = (CHAR *) (buf1 + page_size);
+      s2 = (CHAR *) (buf2 + page_size);
 
       FOR_EACH_IMPL (impl, 0)
        do_one_test (impl, s1, s2, n, 0);
@@ -97,16 +169,16 @@ do_test_limit (size_t align1, size_t align2, size_t len, size_t n, int max_char,
 
   align1 &= 15;
   align2 &= 15;
-  align_n = (page_size - n) & 15;
+  align_n = (page_size - n * CHARBYTES) & 15;
 
-  s1 = (char*)(buf1 + page_size - n);
-  s2 = (char*)(buf2 + page_size - n);
+  s1 = (CHAR *) (buf1 + page_size - n * CHARBYTES);
+  s2 = (CHAR *) (buf2 + page_size - n * CHARBYTES);
 
   if (align1 < align_n)
-    s1 -= (align_n - align1);
+    s1 = (CHAR *) ((char *) s1 - (align_n - align1));
 
   if (align2 < align_n)
-    s2 -= (align_n - align2);
+    s2 = (CHAR *) ((char *) s2 - (align_n - align2));
 
   for (i = 0; i < n; i++)
     s1[i] = s2[i] = 1 + 23 * i % max_char;
@@ -130,24 +202,24 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
         int exp_result)
 {
   size_t i;
-  char *s1, *s2;
+  CHAR *s1, *s2;
 
   if (n == 0)
     return;
 
-  align1 &= 7;
-  if (align1 + n + 1 >= page_size)
+  align1 &= 63;
+  if (align1 + (n + 1) * CHARBYTES >= page_size)
     return;
 
-  align2 &= 7;
-  if (align2 + n + 1 >= page_size)
+  align2 &= 63;
+  if (align2 + (n + 1) * CHARBYTES >= page_size)
     return;
 
-  s1 = (char*)(buf1 + align1);
-  s2 = (char*)(buf2 + align2);
+  s1 = (CHAR *) (buf1 + align1);
+  s2 = (CHAR *) (buf2 + align2);
 
   for (i = 0; i < n; i++)
-    s1[i] = s2[i] = 1 + 23 * i % max_char;
+    s1[i] = s2[i] = 1 + (23 << ((CHARBYTES - 1) * 8)) * i % max_char;
 
   s1[n] = 24 + exp_result;
   s2[n] = 23;
@@ -161,19 +233,20 @@ do_test (size_t align1, size_t align2, size_t len, size_t n, int max_char,
     s2[n - 1] -= exp_result;
 
   FOR_EACH_IMPL (impl, 0)
-    do_one_test (impl, (char*)s1, (char*)s2, n, exp_result);
+    do_one_test (impl, s1, s2, n, exp_result);
 }
 
 static void
-do_page_test (size_t offset1, size_t offset2, char *s2)
+do_page_test (size_t offset1, size_t offset2, CHAR *s2)
 {
-  char *s1;
+  CHAR *s1;
   int exp_result;
 
-  if (offset1 >= page_size || offset2 >= page_size)
+  if (offset1 * CHARBYTES  >= page_size || offset2 * CHARBYTES >= page_size)
     return;
 
-  s1 = (char *) (buf1 + offset1);
+  s1 = (CHAR *) buf1;
+  s1 += offset1;
   s2 += offset2;
 
   exp_result= *s1;
@@ -191,8 +264,8 @@ do_random_tests (void)
   size_t i, j, n, align1, align2, pos, len1, len2, size;
   int result;
   long r;
-  unsigned char *p1 = buf1 + page_size - 512;
-  unsigned char *p2 = buf2 + page_size - 512;
+  UCHAR *p1 = (UCHAR *) (buf1 + page_size - 512 * CHARBYTES);
+  UCHAR *p2 = (UCHAR *) (buf2 + page_size - 512 * CHARBYTES);
 
   for (n = 0; n < ITERATIONS; n++)
     {
@@ -240,7 +313,7 @@ do_random_tests (void)
        }
 
       result = 0;
-      memcpy (p2 + align2, p1 + align1, pos);
+      MEMCPY (p2 + align2, p1 + align1, pos);
       if (pos < len1)
        {
          if (p2[align2 + pos] == p1[align1 + pos])
@@ -263,7 +336,7 @@ do_random_tests (void)
 
       FOR_EACH_IMPL (impl, 1)
        {
-         r = CALL (impl, (char*)(p1 + align1), (char*)(p2 + align2), size);
+         r = CALL (impl, (CHAR *) (p1 + align1), (CHAR *) (p2 + align2), size);
          /* Test whether on 64-bit architectures where ABI requires
             callee to promote has the promotion been done.  */
          asm ("" : "=g" (r) : "0" (r));
@@ -282,19 +355,26 @@ do_random_tests (void)
 static void
 check1 (void)
 {
-  char *s1 = (char *)(buf1 + 0xb2c);
-  char *s2 = (char *)(buf1 + 0xfd8);
-  size_t i;
+  CHAR *s1 = (CHAR *) (buf1 + 0xb2c);
+  CHAR *s2 = (CHAR *) (buf1 + 0xfd8);
+  size_t i, offset;
   int exp_result;
 
-  strcpy(s1, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs");
-  strcpy(s2, "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV");
+  STRCPY(s1, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs"));
+  STRCPY(s2, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV"));
+
+  /* Check possible overflow bug for wcsncmp */
+  s1[4] = CHAR__MAX;
+  s2[4] = CHAR__MIN;
 
-  for (i = 0; i < 80; i++)
+  for (offset = 0; offset < 6; offset++)
     {
-      exp_result = simple_strncmp (s1, s2, i);
-      FOR_EACH_IMPL (impl, 0)
-        check_result (impl, s1, s2, i, exp_result);
+      for (i = 0; i < 80; i++)
+       {
+         exp_result = SIMPLE_STRNCMP (s1 + offset, s2 + offset, i);
+         FOR_EACH_IMPL (impl, 0)
+           check_result (impl, s1 + offset, s2 + offset, i, exp_result);
+       }
     }
 }
 
@@ -302,17 +382,17 @@ static void
 check2 (void)
 {
   size_t i;
-  char *s1, *s2;
+  CHAR *s1, *s2;
 
-  s1 = (char *) buf1;
-  for (i = 0; i < page_size - 1; i++)
+  s1 = (CHAR *) buf1;
+  for (i = 0; i < (page_size / CHARBYTES) - 1; i++)
     s1[i] = 23;
   s1[i] = 0;
 
-  s2 = strdup (s1);
+  s2 = STRDUP (s1);
 
   for (i = 0; i < 64; ++i)
-    do_page_test (3990 + i, 2635, s2);
+    do_page_test ((3988 / CHARBYTES) + i, (2636 / CHARBYTES), s2);
 
   free (s2);
 }
index 69f78922a2e635afe92c0c0bc5ffbbe7aca25d08..44a4494403f201c97be595fcc75ec2197832569f 100644 (file)
@@ -42,7 +42,7 @@ routines := wcscat wcschr wcscmp wcscpy wcscspn wcsdup wcslen wcsncat \
            isoc99_swscanf isoc99_vswscanf \
            mbrtoc16 c16rtomb
 
-strop-tests :=  wcscmp wmemcmp wcslen wcschr wcsrchr wcscpy
+strop-tests :=  wcscmp wcsncmp wmemcmp wcslen wcschr wcsrchr wcscpy
 tests := tst-wcstof wcsmbs-tst1 tst-wcsnlen tst-btowc tst-mbrtowc \
         tst-wcrtomb tst-wcpncpy tst-mbsrtowcs tst-wchar-h tst-mbrtowc2 \
         tst-c16c32-1 wcsatcliff $(addprefix test-,$(strop-tests))
diff --git a/wcsmbs/test-wcsncmp.c b/wcsmbs/test-wcsncmp.c
new file mode 100644 (file)
index 0000000..07757d8
--- /dev/null
@@ -0,0 +1,2 @@
+#define WIDE 1
+#include "../string/test-strncmp.c"
index 59e003b85787971e3e137880a06962f873e4212a..e083ad81749fe2c160872a079e21b3b9e8ecd8bd 100644 (file)
@@ -29,42 +29,42 @@ wcsncmp (s1, s2, n)
      const wchar_t *s2;
      size_t n;
 {
-  wint_t c1 = L'\0';
-  wint_t c2 = L'\0';
+  wchar_t c1 = L'\0';
+  wchar_t c2 = L'\0';
 
   if (n >= 4)
     {
       size_t n4 = n >> 2;
       do
        {
-         c1 = (wint_t) *s1++;
-         c2 = (wint_t) *s2++;
+         c1 = *s1++;
+         c2 = *s2++;
          if (c1 == L'\0' || c1 != c2)
-           return c1 - c2;
-         c1 = (wint_t) *s1++;
-         c2 = (wint_t) *s2++;
+           return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
+         c1 = *s1++;
+         c2 = *s2++;
          if (c1 == L'\0' || c1 != c2)
-           return c1 - c2;
-         c1 = (wint_t) *s1++;
-         c2 = (wint_t) *s2++;
+           return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
+         c1 = *s1++;
+         c2 = *s2++;
          if (c1 == L'\0' || c1 != c2)
-           return c1 - c2;
-         c1 = (wint_t) *s1++;
-         c2 = (wint_t) *s2++;
+           return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
+         c1 = *s1++;
+         c2 = *s2++;
          if (c1 == L'\0' || c1 != c2)
-           return c1 - c2;
+           return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
        } while (--n4 > 0);
       n &= 3;
     }
 
   while (n > 0)
     {
-      c1 = (wint_t) *s1++;
-      c2 = (wint_t) *s2++;
+      c1 = *s1++;
+      c2 = *s2++;
       if (c1 == L'\0' || c1 != c2)
-       return c1 - c2;
+       return c1 > c2 ? 1 : (c1 < c2 ? -1 : 0);
       n--;
     }
 
-  return c1 - c2;
+  return 0;
 }
This page took 0.138537 seconds and 5 git commands to generate.