From 95584d3b3309ff4da4cc458254df383f5cff044b Mon Sep 17 00:00:00 2001 From: Liubov Dmitrieva Date: Sun, 23 Oct 2011 13:34:15 -0400 Subject: Fix signedness in wcscmp comparison --- string/test-strcmp.c | 89 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 75 insertions(+), 14 deletions(-) (limited to 'string') diff --git a/string/test-strcmp.c b/string/test-strcmp.c index b8d85dca79..0e43f85542 100644 --- a/string/test-strcmp.c +++ b/string/test-strcmp.c @@ -1,4 +1,4 @@ -/* Test and measure STRCMP functions. +/* Test and measure strcmp and wcscmp functions. Copyright (C) 1999, 2002, 2003, 2005, 2011 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Jakub Jelinek , 1999. @@ -23,7 +23,6 @@ #include "test-string.h" #ifdef WIDE -# include # include # define L(str) L##str @@ -34,12 +33,53 @@ # define SIMPLE_STRCMP simple_wcscmp # define STUPID_STRCMP stupid_wcscmp # define CHAR wchar_t -# define UCHAR uint32_t +# define UCHAR wchar_t # define CHARBYTES 4 # define CHARBYTESLOG 2 # define CHARALIGN __alignof__ (CHAR) # define MIDCHAR 0x7fffffff # define LARGECHAR 0xfffffffe +# define CHAR__MAX WCHAR_MAX +# define CHAR__MIN WCHAR_MIN + +/* Wcscmp uses signed semantics for comparison, not unsigned */ +/* Avoid using substraction since possible overflow */ + +int +simple_wcscmp (const wchar_t *s1, const wchar_t *s2) +{ + wchar_t c1, c2; + do + { + c1 = *s1++; + c2 = *s2++; + if (c2 == L'\0') + return c1 - c2; + } + while (c1 == c2); + + return c1 < c2 ? -1 : 1; +} + +int +stupid_wcscmp (const wchar_t *s1, const wchar_t *s2) +{ + size_t ns1 = wcslen (s1) + 1; + size_t ns2 = wcslen (s2) + 1; + size_t n = ns1 < ns2 ? ns1 : ns2; + int ret = 0; + + wchar_t c1, c2; + + while (n--) { + c1 = *s1++; + c2 = *s2++; + if ((ret = c1 < c2 ? -1 : c1 == c2 ? 0 : 1) != 0) + break; + } + return ret; +} + #else # define L(str) str # define STRCMP strcmp @@ -55,31 +95,35 @@ # define CHARALIGN 1 # define MIDCHAR 0x7f # define LARGECHAR 0xfe -#endif -typedef int (*proto_t) (const CHAR *, const CHAR *); +# define CHAR__MAX CHAR_MAX +# define CHAR__MIN CHAR_MIN +/* Strcmp uses unsigned semantics for comparison. */ int -SIMPLE_STRCMP (const CHAR *s1, const CHAR *s2) +simple_strcmp (const char *s1, const char *s2) { int ret; - while ((ret = *(UCHAR *) s1 - *(UCHAR *) s2++) == 0 && *s1++); + while ((ret = *(unsigned char *) s1 - *(unsigned char*) s2++) == 0 && *s1++); return ret; } int -STUPID_STRCMP (const CHAR *s1, const CHAR *s2) +stupid_strcmp (const char *s1, const char *s2) { - size_t ns1 = STRLEN (s1) + 1; - size_t ns2 = STRLEN (s2) + 1; + size_t ns1 = strlen (s1) + 1; + size_t ns2 = strlen (s2) + 1; size_t n = ns1 < ns2 ? ns1 : ns2; int ret = 0; while (n--) - if ((ret = *(UCHAR *) s1++ - *(UCHAR *) s2++) != 0) + if ((ret = *(unsigned char *) s1++ - *(unsigned char *) s2++) != 0) break; return ret; } +#endif + +typedef int (*proto_t) (const CHAR *, const CHAR *); IMPL (STUPID_STRCMP, 1) IMPL (SIMPLE_STRCMP, 1) @@ -276,14 +320,31 @@ check (void) STRCPY(s1, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs")); STRCPY(s2, L("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkLMNOPQRSTUV")); + /* Check correct working for negatives values */ + + s1[0] = 1; + s2[0] = 1; + s1[1] = 1; + s2[1] = 1; + s1[2] = -1; + s2[2] = 3; + s1[3] = 0; + s2[3] = -1; + + /* Check possible overflow bug, actual more for wcscmp */ + + s1[7] = CHAR__MIN; + s2[7] = CHAR__MAX; + size_t l1 = STRLEN (s1); size_t l2 = STRLEN (s2); + for (size_t i1 = 0; i1 < l1; i1++) for (size_t i2 = 0; i2 < l2; i2++) { - int exp_result = SIMPLE_STRCMP (s1 + i1, s2 + i2); - FOR_EACH_IMPL (impl, 0) - check_result (impl, s1 + i1, s2 + i2, exp_result); + int exp_result = SIMPLE_STRCMP (s1 + i1, s2 + i2); + FOR_EACH_IMPL (impl, 0) + check_result (impl, s1 + i1, s2 + i2, exp_result); } } -- cgit 1.4.1