libdraw, libframe, acme: fix, guard against inverted range in textsetselect

Credit to Roi Martin <jroi.martin@gmail.com> for noticing that
libdraw was being passed a negative string length and for finding the
sequence of keystrokes that make acme do it reproducibly.

Change-Id: If3f3d04a25c506175f740d3e887d5d83b5cd1bfe
Reviewed-on: https://plan9port-review.googlesource.com/1092
Reviewed-by: Russ Cox <rsc@swtch.com>
diff --git a/src/cmd/acme/text.c b/src/cmd/acme/text.c
index c537d27..7634d92 100644
--- a/src/cmd/acme/text.c
+++ b/src/cmd/acme/text.c
@@ -819,8 +819,12 @@
 		nr = runestrlen(rp);
 		break;	/* fall through to normal insertion case */
 	case 0x1B:
-		if(t->eq0 != ~0)
-			textsetselect(t, t->eq0, t->q0);
+		if(t->eq0 != ~0) {
+			if(t->eq0 <= t->q0)
+				textsetselect(t, t->eq0, t->q0);
+			else
+				textsetselect(t, t->q0, t->eq0);
+		}
 		if(t->ncache > 0)
 			typecommit(t);
 		t->iq1 = t->q0;
@@ -1173,7 +1177,7 @@
 textsetselect(Text *t, uint q0, uint q1)
 {
 	int p0, p1, ticked;
-
+	
 	/* t->fr.p0 and t->fr.p1 are always right; t->q0 and t->q1 may be off */
 	t->q0 = q0;
 	t->q1 = q1;
@@ -1198,6 +1202,8 @@
 			frtick(&t->fr, frptofchar(&t->fr, p0), ticked);
 		return;
 	}
+	if(p0 > p1)
+		sysfatal("acme: textsetselect p0=%d p1=%d q0=%ud q1=%ud t->org=%d nchars=%d", p0, p1, q0, q1, (int)t->org, (int)t->fr.nchars);
 	/* screen disagrees with desired selection */
 	if(t->fr.p1<=p0 || p1<=t->fr.p0 || p0==p1 || t->fr.p1==t->fr.p0){
 		/* no overlap or too easy to bother trying */
diff --git a/src/libdraw/string.c b/src/libdraw/string.c
index 4e876c1..392a7e8 100644
--- a/src/libdraw/string.c
+++ b/src/libdraw/string.c
@@ -67,6 +67,9 @@
 	Font *def;
 	Subfont *sf;
 
+	if(len < 0)
+		sysfatal("libdraw: _string len=%d", len);
+
 	if(s == nil){
 		s = "";
 		sptr = nil;
diff --git a/src/libframe/frdraw.c b/src/libframe/frdraw.c
index 2a3a95e..05a45fe 100644
--- a/src/libframe/frdraw.c
+++ b/src/libframe/frdraw.c
@@ -62,6 +62,9 @@
 	Point qt;
 	uint p;
 	char *ptr;
+	
+	if(p0 > p1)
+		sysfatal("libframe: frdrawsel0 p0=%lud > p1=%lud", p0, p1);
 
 	p = 0;
 	b = f->box;