about summary refs log tree commit diff
path: root/Src/pattern.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2010-01-21 11:11:05 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2010-01-21 11:11:05 +0000
commitf0287c6e17c00b61a0640514f32461aeeefd4600 (patch)
treeac9dc5b88dbe36c44b55477b988215c4d6b32893 /Src/pattern.c
parentf02778f83c9a1dfaae895a52d3a49417a8f340ea (diff)
downloadzsh-f0287c6e17c00b61a0640514f32461aeeefd4600.tar.gz
zsh-f0287c6e17c00b61a0640514f32461aeeefd4600.tar.xz
zsh-f0287c6e17c00b61a0640514f32461aeeefd4600.zip
users/14723: invalid converted characters should never match valid ones
Diffstat (limited to 'Src/pattern.c')
-rw-r--r--Src/pattern.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/Src/pattern.c b/Src/pattern.c
index 8ac79546d..53ada0f8d 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -1795,9 +1795,9 @@ charnext(char *x, char *y)
 
 
 /* Get a character and increment */
-#define CHARREFINC(x, y)	charrefinc(&(x), (y))
+#define CHARREFINC(x, y, z)	charrefinc(&(x), (y), (z))
 static wchar_t
-charrefinc(char **x, char *y)
+charrefinc(char **x, char *y, int *z)
 {
     wchar_t wc;
     size_t ret;
@@ -1808,7 +1808,8 @@ charrefinc(char **x, char *y)
     ret = mbrtowc(&wc, *x, y-*x, &shiftstate);
 
     if (ret == MB_INVALID || ret == MB_INCOMPLETE) {
-	/* Error.  Treat as single byte. */
+	/* Error.  Treat as single byte, but flag. */
+	*z = 1;
 	/* Reset the shift state for next time. */
 	memset(&shiftstate, 0, sizeof(shiftstate));
 	return (wchar_t) STOUC(*(*x)++);
@@ -1865,7 +1866,7 @@ charsub(char *x, char *y)
 /* Increment a pointer past the current character. */
 #define CHARINC(x, y)	((x)++)
 /* Get a character and increment */
-#define CHARREFINC(x, y)	(STOUC(*(x)++))
+#define CHARREFINC(x, y, z)	(STOUC(*(x)++))
 /* Counter the number of characters between two pointers, smaller first */
 #define CHARSUB(x,y)	((y) - (x))
 
@@ -2419,9 +2420,21 @@ patmatch(Upat prog)
 	    while (chrop < chrend && patinput < patinend) {
 		char *savpatinput = patinput;
 		char *savchrop = chrop;
-		patint_t chin = CHARREFINC(patinput, patinend);
-		patint_t chpa = CHARREFINC(chrop, chrend);
-		if (!CHARMATCH(chin, chpa)) {
+		int badin = 0, badpa = 0;
+		/*
+		 * Care with character matching:
+		 * We do need to convert the character to wide
+		 * representation if possible, because we may need
+		 * to do case transformation.  However, we should
+		 * be careful in case one, but not the other, wasn't
+		 * representable in the current locale---in that
+		 * case they don't match even if the returned
+		 * values (one properly converted, one raw) are
+		 * the same.
+		 */
+		patint_t chin = CHARREFINC(patinput, patinend, &badin);
+		patint_t chpa = CHARREFINC(chrop, chrend, &badpa);
+		if (!CHARMATCH(chin, chpa) || badin != badpa) {
 		    fail = 1;
 		    patinput = savpatinput;
 		    chrop = savchrop;