zsh-workers
 help / color / mirror / code / Atom feed
* Infinite loop in dopadding() with doublewidth chars, probably since (mm)
@ 2010-09-28 22:51 Mikael Magnusson
  2010-10-02 18:41 ` Peter Stephenson
  0 siblings, 1 reply; 2+ messages in thread
From: Mikael Magnusson @ 2010-09-28 22:51 UTC (permalink / raw)
  To: zsh workers

Trying to pad a string to a width with a double-width character that
can't be done results in an infinite loop, where old versions just
left it one character too narrow. For example:
echo ${(ml:10::ま:):-hello}

dopadding() seems to consist mostly of special cases, but i ended up
around line 990,

 986 if ((m = f % lpremul)) {
here f is 5 "hello", lpremul is 2 "ま", so m is 1
 987     /*
 988      * Some fraction of the repeated string needed.
 989      */
 990     /* Need this much... */
 991     c = m;
 992     /* ...skipping this much first. */
 993     m = lpremul - m;
m is still 1 here
 994     MB_METACHARINIT();
 995     for (t = premul; m > 0; ) {
 996         t += MB_METACHARLENCONV(t, &cchar);
this advances t 3 bytes, pointing directly at the null after the ま
 997         m -= WCPADWIDTH(cchar, multi_width);
this subtracts 2 from m, leaving -1
 998     }
 999     /* Now the rest of the repeated string. */
1000     while (c > 0) {
c is still 1 here
1001         cl = MB_METACHARLENCONV(t, &cchar);
this is 0, remember t is ""
1002         while (cl--)
1003             *r++ = *t++;
1004         c -= WCPADWIDTH(cchar, multi_width);
which means c is decremented by 0 here
1005     }
1006 }

I didn't get much further than this. I didn't even dare look in how
many places some similar code exists in the function. :)

-- 
Mikael Magnusson


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Infinite loop in dopadding() with doublewidth chars, probably since (mm)
  2010-09-28 22:51 Infinite loop in dopadding() with doublewidth chars, probably since (mm) Mikael Magnusson
@ 2010-10-02 18:41 ` Peter Stephenson
  0 siblings, 0 replies; 2+ messages in thread
From: Peter Stephenson @ 2010-10-02 18:41 UTC (permalink / raw)
  To: zsh workers

On Wed, 29 Sep 2010 00:51:58 +0200
Mikael Magnusson <mikachu@gmail.com> wrote:
> Trying to pad a string to a width with a double-width character that
> can't be done results in an infinite loop, where old versions just
> left it one character too narrow. For example:
> echo ${(ml:10::ま:):-hello}

I suppose we just have to stop when there's nothing left.

Index: Src/subst.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/subst.c,v
retrieving revision 1.106
diff -p -u -r1.106 subst.c
--- Src/subst.c	11 Jun 2010 20:08:03 -0000	1.106
+++ Src/subst.c	2 Oct 2010 18:38:42 -0000
@@ -802,12 +802,17 @@ dopadding(char *str, int prenum, int pos
 		f = -f;
 		MB_METACHARINIT();
 		while (f > 0) {
-		    str += MB_METACHARLENCONV(str, &cchar);
+		    cl = MB_METACHARLENCONV(str, &cchar);
+		    if (!cl)
+			break;
+		    str += cl;
 		    f -= WCPADWIDTH(cchar, multi_width);
 		}
 		/* Now finish the first half. */
 		for (c = prenum; c > 0; ) {
 		    cl = MB_METACHARLENCONV(str, &cchar);
+		    if (!cl)
+			break;
 		    while (cl--)
 			*r++ = *str++;
 		    c -= WCPADWIDTH(cchar, multi_width);
@@ -823,7 +828,10 @@ dopadding(char *str, int prenum, int pos
 			f = lpreone - f;
 			/* So skip. */
 			for (t = preone; f > 0; ) {
-			    t += MB_METACHARLENCONV(t, &cchar);
+			    cl = MB_METACHARLENCONV(t, &cchar);
+			    if (!cl)
+				break;
+			    t += cl;
 			    f -= WCPADWIDTH(cchar, multi_width);
 			}
 			/* Then copy the entire remainder. */
@@ -841,7 +849,10 @@ dopadding(char *str, int prenum, int pos
 			    /* Skip this much. */
 			    m = lpremul - m;
 			    for (t = premul; m > 0; ) {
-				t += MB_METACHARLENCONV(t, &cchar);
+				cl = MB_METACHARLENCONV(t, &cchar);
+				if (!cl)
+				    break;
+				t += cl;
 				m -= WCPADWIDTH(cchar, multi_width);
 			    }
 			    /* Output the rest. */
@@ -853,6 +864,8 @@ dopadding(char *str, int prenum, int pos
 			    MB_METACHARINIT();
 			    for (c = lpremul, t = premul; c > 0; ) {
 				cl = MB_METACHARLENCONV(t, &cchar);
+				if (!cl)
+				    break;
 				while (cl--)
 				    *r++ = *t++;
 				c -= WCPADWIDTH(cchar, multi_width);
@@ -868,6 +881,8 @@ dopadding(char *str, int prenum, int pos
 		/* Output the first half width of the original string. */
 		for (c = ls2; c > 0; ) {
 		    cl = MB_METACHARLENCONV(str, &cchar);
+		    if (!cl)
+			break;
 		    c -= WCPADWIDTH(cchar, multi_width);
 		    while (cl--)
 			*r++ = *str++;
@@ -882,6 +897,8 @@ dopadding(char *str, int prenum, int pos
 		MB_METACHARINIT();
 		for (c = postnum; c > 0; ) {
 		    cl = MB_METACHARLENCONV(str, &cchar);
+		    if (!cl)
+			break;
 		    c -= WCPADWIDTH(cchar, multi_width);
 		    while (cl--)
 			*r++ = *str++;
@@ -895,6 +912,8 @@ dopadding(char *str, int prenum, int pos
 			/* Can't fit unrepeated string, truncate it */
 			for (c = f; c > 0; ) {
 			    cl = MB_METACHARLENCONV(postone, &cchar);
+			    if (!cl)
+				break;
 			    c -= WCPADWIDTH(cchar, multi_width);
 			    while (cl--)
 				*r++ = *postone++;
@@ -918,6 +937,8 @@ dopadding(char *str, int prenum, int pos
 			    MB_METACHARINIT();
 			    while (m > 0) {
 				cl = MB_METACHARLENCONV(postmul, &cchar);
+				if (!cl)
+				    break;
 				m -= WCPADWIDTH(cchar, multi_width);
 				while (cl--)
 				    *r++ = *postmul++;
@@ -941,12 +962,17 @@ dopadding(char *str, int prenum, int pos
 		f = -f;
 		MB_METACHARINIT();
 		while (f > 0) {
-		    str += MB_METACHARLENCONV(str, &cchar);
+		    cl = MB_METACHARLENCONV(str, &cchar);
+		    if (!cl)
+			break;
+		    str += cl;
 		    f -= WCPADWIDTH(cchar, multi_width);
 		}
 		/* Copy the rest of the original string */
 		for (c = prenum; c > 0; ) {
 		    cl = MB_METACHARLENCONV(str, &cchar);
+		    if (!cl)
+			break;
 		    while (cl--)
 			*r++ = *str++;
 		    c -= WCPADWIDTH(cchar, multi_width);
@@ -969,7 +995,10 @@ dopadding(char *str, int prenum, int pos
 			f = lpreone - f;
 			MB_METACHARINIT();
 			for (t = preone; f > 0; ) {
-			    t += MB_METACHARLENCONV(t, &cchar);
+			    cl = MB_METACHARLENCONV(t, &cchar);
+			    if (!cl)
+				break;
+			    t += cl;
 			    f -= WCPADWIDTH(cchar, multi_width);
 			}
 			/* Copy the rest of preone */
@@ -993,12 +1022,17 @@ dopadding(char *str, int prenum, int pos
 			    m = lpremul - m;
 			    MB_METACHARINIT();
 			    for (t = premul; m > 0; ) {
-				t += MB_METACHARLENCONV(t, &cchar);
+				cl = MB_METACHARLENCONV(t, &cchar);
+				if (!cl)
+				    break;
+				t += cl;
 				m -= WCPADWIDTH(cchar, multi_width);
 			    }
 			    /* Now the rest of the repeated string. */
 			    while (c > 0) {
 				cl = MB_METACHARLENCONV(t, &cchar);
+				if (!cl)
+				    break;
 				while (cl--)
 				    *r++ = *t++;
 				c -= WCPADWIDTH(cchar, multi_width);
@@ -1011,6 +1045,8 @@ dopadding(char *str, int prenum, int pos
 			    MB_METACHARINIT();
 			    for (c = lpremul, t = premul; c > 0; ) {
 				cl = MB_METACHARLENCONV(t, &cchar);
+				if (!cl)
+				    break;
 				while (cl--)
 				    *r++ = *t++;
 				c -= WCPADWIDTH(cchar, multi_width);
@@ -1049,6 +1085,8 @@ dopadding(char *str, int prenum, int pos
 	     */
 	    for (c = postnum; c > 0; ) {
 		cl = MB_METACHARLENCONV(str, &cchar);
+		if (!cl)
+		    break;
 		while (cl--)
 		    *r++ = *str++;
 		c -= WCPADWIDTH(cchar, multi_width);
@@ -1061,6 +1099,8 @@ dopadding(char *str, int prenum, int pos
 	     */
 	    for (c = ls; *str; ) {
 		cl = MB_METACHARLENCONV(str, &cchar);
+		if (!cl)
+		    break;
 		while (cl--)
 		    *r++ = *str++;
 		c -= WCPADWIDTH(cchar, multi_width);
@@ -1074,6 +1114,8 @@ dopadding(char *str, int prenum, int pos
 		     */
 		    for (c = f; c > 0; ) {
 			cl = MB_METACHARLENCONV(postone, &cchar);
+			if (!cl)
+			    break;
 			while (cl--)
 			    *r++ = *postone++;
 			c -= WCPADWIDTH(cchar, multi_width);
@@ -1085,6 +1127,8 @@ dopadding(char *str, int prenum, int pos
 		    /* Copy the entire unrepeated string */
 		    for (c = lpostone; *postone; ) {
 			cl = MB_METACHARLENCONV(postone, &cchar);
+			if (!cl)
+			    break;
 			while (cl--)
 			    *r++ = *postone++;
 			c -= WCPADWIDTH(cchar, multi_width);
@@ -1096,6 +1140,8 @@ dopadding(char *str, int prenum, int pos
 			MB_METACHARINIT();
 			for (c = lpostmul, t = postmul; *t; ) {
 			    cl = MB_METACHARLENCONV(t, &cchar);
+			    if (!cl)
+				break;
 			    while (cl--)
 				*r++ = *t++;
 			    c -= WCPADWIDTH(cchar, multi_width);
@@ -1109,6 +1155,8 @@ dopadding(char *str, int prenum, int pos
 			MB_METACHARINIT();
 			while (m > 0) {
 			    cl = MB_METACHARLENCONV(postmul, &cchar);
+			    if (!cl)
+				break;
 			    while (cl--)
 				*r++ = *postmul++;
 			    m -= WCPADWIDTH(cchar, multi_width);

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2010-10-02 19:43 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-09-28 22:51 Infinite loop in dopadding() with doublewidth chars, probably since (mm) Mikael Magnusson
2010-10-02 18:41 ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).