bd3afb
diff -ru mercurial-2.6.2/mercurial/mpatch.c mercurial-2.6.2_patched/mercurial/mpatch.c
bd3afb
--- mercurial-2.6.2/mercurial/mpatch.c	2013-06-02 00:10:16.000000000 +0200
bd3afb
+++ mercurial-2.6.2_patched/mercurial/mpatch.c	2019-05-07 16:51:13.631774481 +0200
bd3afb
@@ -74,6 +74,35 @@
bd3afb
 	return a->tail - a->head;
bd3afb
 }
bd3afb
 
bd3afb
+/* add helper to add src and *dest iff it won't overflow */
bd3afb
+static inline int safeadd(int src, int *dest)
bd3afb
+{
bd3afb
+	if ((src > 0) == (*dest > 0)) {
bd3afb
+		if (*dest > 0) {
bd3afb
+			if (src > (INT_MAX - *dest)) {
bd3afb
+				return 0;
bd3afb
+			}
bd3afb
+		} else {
bd3afb
+			if (src < (INT_MIN - *dest)) {
bd3afb
+				return 0;
bd3afb
+			}
bd3afb
+		}
bd3afb
+	}
bd3afb
+	*dest += src;
bd3afb
+	return 1;
bd3afb
+}
bd3afb
+
bd3afb
+/* subtract src from dest and store result in dest */
bd3afb
+static inline int safesub(int src, int *dest)
bd3afb
+{
bd3afb
+	if (((src > 0) && (*dest < INT_MIN + src)) ||
bd3afb
+	    ((src < 0) && (*dest > INT_MAX + src))) {
bd3afb
+		return 0;
bd3afb
+	}
bd3afb
+	*dest -= src;
bd3afb
+	return 1;
bd3afb
+}
bd3afb
+
bd3afb
 /* move hunks in source that are less cut to dest, compensating
bd3afb
    for changes in offset. the last hunk may be split if necessary.
bd3afb
 */
bd3afb
@@ -83,18 +112,37 @@
bd3afb
 	int postend, c, l;
bd3afb
 
bd3afb
 	while (s != src->tail) {
bd3afb
-		if (s->start + offset >= cut)
bd3afb
+		int soffset = s->start;
bd3afb
+		if (!safeadd(offset, &soffset))
bd3afb
+			break; /* add would overflow, oh well */
bd3afb
+		if (soffset >= cut)
bd3afb
 			break; /* we've gone far enough */
bd3afb
 
bd3afb
-		postend = offset + s->start + s->len;
bd3afb
+		postend = offset;
bd3afb
+		if (!safeadd(s->start, &postend) ||
bd3afb
+		    !safeadd(s->len, &postend)) {
bd3afb
+			break;
bd3afb
+		}
bd3afb
 		if (postend <= cut) {
bd3afb
 			/* save this hunk */
bd3afb
-			offset += s->start + s->len - s->end;
bd3afb
+			int tmp = s->start;
bd3afb
+			if (!safesub(s->end, &tmp)) {
bd3afb
+				break;
bd3afb
+			}
bd3afb
+			if (!safeadd(s->len, &tmp)) {
bd3afb
+				break;
bd3afb
+			}
bd3afb
+			if (!safeadd(tmp, &offset)) {
bd3afb
+				break; /* add would overflow, oh well */
bd3afb
+			}
bd3afb
 			*d++ = *s++;
bd3afb
 		}
bd3afb
 		else {
bd3afb
 			/* break up this hunk */
bd3afb
-			c = cut - offset;
bd3afb
+			c = cut;
bd3afb
+			if (!safesub(offset, &c)) {
bd3afb
+				break;
bd3afb
+			}
bd3afb
 			if (s->end < c)
bd3afb
 				c = s->end;
bd3afb
 			l = cut - offset - s->start;
bd3afb
@@ -128,16 +176,40 @@
bd3afb
 	int postend, c, l;
bd3afb
 
bd3afb
 	while (s != src->tail) {
bd3afb
-		if (s->start + offset >= cut)
bd3afb
+		int cmpcut = s->start;
bd3afb
+		if (!safeadd(offset, &cmpcut)) {
bd3afb
+			break;
bd3afb
+		}
bd3afb
+		if (cmpcut >= cut)
bd3afb
 			break;
bd3afb
 
bd3afb
-		postend = offset + s->start + s->len;
bd3afb
+		postend = offset;
bd3afb
+		if (!safeadd(s->start, &postend)) {
bd3afb
+			break;
bd3afb
+		}
bd3afb
+		if (!safeadd(s->len, &postend)) {
bd3afb
+			break;
bd3afb
+		}
bd3afb
 		if (postend <= cut) {
bd3afb
-			offset += s->start + s->len - s->end;
bd3afb
+			/* do the subtraction first to avoid UB integer overflow
bd3afb
+			 */
bd3afb
+			int tmp = s->start;
bd3afb
+			if (!safesub(s->end, &tmp)) {
bd3afb
+				break;
bd3afb
+			}
bd3afb
+			if (!safeadd(s->len, &tmp)) {
bd3afb
+				break;
bd3afb
+			}
bd3afb
+			if (!safeadd(tmp, &offset)) {
bd3afb
+				break;
bd3afb
+			}
bd3afb
 			s++;
bd3afb
 		}
bd3afb
 		else {
bd3afb
-			c = cut - offset;
bd3afb
+			c = cut;
bd3afb
+			if (!safesub(offset, &c)) {
bd3afb
+				break;
bd3afb
+			}
bd3afb
 			if (s->end < c)
bd3afb
 				c = s->end;
bd3afb
 			l = cut - offset - s->start;
bd3afb
@@ -179,8 +251,18 @@
bd3afb
 
bd3afb
 			/* insert new hunk */
bd3afb
 			ct = c->tail;
bd3afb
-			ct->start = bh->start - offset;
bd3afb
-			ct->end = bh->end - post;
bd3afb
+			ct->start = bh->start;
bd3afb
+			ct->end = bh->end;
bd3afb
+			if (!safesub(offset, &(ct->start)) ||
bd3afb
+			    !safesub(post, &(ct->end))) {
bd3afb
+				/* It was already possible to exit
bd3afb
+				 * this function with a return value
bd3afb
+				 * of NULL before the safesub()s were
bd3afb
+				 * added, so this should be fine. */
bd3afb
+				lfree(c);
bd3afb
+				c = NULL;
bd3afb
+				goto done;
bd3afb
+			}
bd3afb
 			ct->len = bh->len;
bd3afb
 			ct->data = bh->data;
bd3afb
 			c->tail++;
bd3afb
@@ -191,7 +273,7 @@
bd3afb
 		memcpy(c->tail, a->head, sizeof(struct frag) * lsize(a));
bd3afb
 		c->tail += lsize(a);
bd3afb
 	}
bd3afb
-
bd3afb
+done:
bd3afb
 	lfree(a);
bd3afb
 	lfree(b);
bd3afb
 	return c;
bd3afb
@@ -215,13 +297,17 @@
bd3afb
 		lt->start = getbe32(bin);
bd3afb
 		lt->end = getbe32(bin + 4);
bd3afb
 		lt->len = getbe32(bin + 8);
bd3afb
-		if (lt->start > lt->end)
bd3afb
-			break; /* sanity check */
bd3afb
-		bin = data + lt->len;
bd3afb
-		if (bin < data)
bd3afb
+		if (lt->start < 0 || lt->start > lt->end || lt->len < 0)
bd3afb
+ 			break; /* sanity check */
bd3afb
+		bin = data;
bd3afb
+		if (!safeadd(lt->len, &bin)) {
bd3afb
 			break; /* big data + big (bogus) len can wrap around */
bd3afb
+		}
bd3afb
 		lt->data = data;
bd3afb
-		data = bin + 12;
bd3afb
+		data = bin;
bd3afb
+		if (!safeadd(12, &data)) {
bd3afb
+			break;
bd3afb
+		}
bd3afb
 		lt++;
bd3afb
 	}
bd3afb
 
bd3afb
@@ -266,7 +352,8 @@
bd3afb
 	char *p = buf;
bd3afb
 
bd3afb
 	while (f != l->tail) {
bd3afb
-		if (f->start < last || f->end > len) {
bd3afb
+		if (f->start < last || f->start > len || f->end > len ||
bd3afb
+            last < 0) {
bd3afb
 			if (!PyErr_Occurred())
bd3afb
 				PyErr_SetString(mpatch_Error,
bd3afb
 				                "invalid patch");
bd3afb
@@ -279,6 +366,12 @@
bd3afb
 		p += f->len;
bd3afb
 		f++;
bd3afb
 	}
bd3afb
+	if (last < 0) {
bd3afb
+		if (!PyErr_Occurred())
bd3afb
+			PyErr_SetString(mpatch_Error,
bd3afb
+			                "invalid patch");
bd3afb
+		return 0;
bd3afb
+	}
bd3afb
 	memcpy(p, orig + last, len - last);
bd3afb
 	return 1;
bd3afb
 }