File CVE-2025-67899.patch of Package uriparser.42543

commit 99f2aac8298c12b1cf8c14ad1e2ed53510cf0b14
Author: Adam Majer <amajer@suse.com>
Date:   Mon Feb 2 14:58:49 2026 +0100

    CVE-2025-67899

--- a/src/UriParse.c
+++ b/src/UriParse.c
@@ -157,16 +157,14 @@
 
 static const URI_CHAR * URI_FUNC(ParseAuthority)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
-static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParseHexZero)(const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
-static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseIpLit2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseOwnHost)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
-static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
@@ -177,7 +175,7 @@ static const URI_CHAR * URI_FUNC(ParsePathRootless)(URI_TYPE(ParserState) * stat
 static const URI_CHAR * URI_FUNC(ParsePchar)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParsePctEncoded)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
-static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
+static const URI_CHAR * URI_FUNC(ParsePort)(const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
 static const URI_CHAR * URI_FUNC(ParseSegmentNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast);
@@ -289,7 +287,7 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserSt
 	switch (*first) {
 	case _UT(':'):
 		{
-			const URI_CHAR * const afterPort = URI_FUNC(ParsePort)(state, first + 1, afterLast);
+			const URI_CHAR * const afterPort = URI_FUNC(ParsePort)(first + 1, afterLast);
 			if (afterPort == NULL) {
 				return NULL;
 			}
@@ -309,14 +307,16 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseAuthorityTwo)(URI_TYPE(ParserSt
  * [hexZero]->[HEXDIG][hexZero]
  * [hexZero]-><NULL>
  */
-static const URI_CHAR * URI_FUNC(ParseHexZero)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+static const URI_CHAR * URI_FUNC(ParseHexZero)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		return afterLast;
 	}
 
 	switch (*first) {
 	case URI_SET_HEXDIG:
-		return URI_FUNC(ParseHexZero)(state, first + 1, afterLast);
+		first += 1;
+		goto tail_call;
 
 	default:
 		return first;
@@ -374,75 +374,48 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseHierPart)(URI_TYPE(ParserState)
  * [ipFutLoop]-><:>[ipFutStopGo]
  */
 static const URI_CHAR * URI_FUNC(ParseIpFutLoop)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
-	if (first >= afterLast) {
-		URI_FUNC(StopSyntax)(state, first);
-		return NULL;
-	}
+	const URI_CHAR * const originalFirst = first;
+
+	while (first < afterLast) {
+		switch (*first) {
+		case _UT('!'):
+		case _UT('$'):
+		case _UT('&'):
+		case _UT('('):
+		case _UT(')'):
+		case _UT('-'):
+		case _UT('*'):
+		case _UT(','):
+		case _UT('.'):
+		case _UT(':'):
+		case _UT(';'):
+		case _UT('\''):
+		case _UT('_'):
+		case _UT('~'):
+		case _UT('+'):
+		case _UT('='):
+		case URI_SET_DIGIT:
+		case URI_SET_ALPHA:
+			first += 1;
+			break;
 
-	switch (*first) {
-	case _UT('!'):
-	case _UT('$'):
-	case _UT('&'):
-	case _UT('('):
-	case _UT(')'):
-	case _UT('-'):
-	case _UT('*'):
-	case _UT(','):
-	case _UT('.'):
-	case _UT(':'):
-	case _UT(';'):
-	case _UT('\''):
-	case _UT('_'):
-	case _UT('~'):
-	case _UT('+'):
-	case _UT('='):
-	case URI_SET_DIGIT:
-	case URI_SET_ALPHA:
-		return URI_FUNC(ParseIpFutStopGo)(state, first + 1, afterLast);
+		default:
+			goto done_looping;
+			break;
+		}
+	}
 
-	default:
+done_looping:
+	if (first == originalFirst) {
 		URI_FUNC(StopSyntax)(state, first);
 		return NULL;
 	}
+
+	return first;
 }
 
 
 
-/*
- * [ipFutStopGo]->[ipFutLoop]
- * [ipFutStopGo]-><NULL>
- */
-static const URI_CHAR * URI_FUNC(ParseIpFutStopGo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
-	if (first >= afterLast) {
-		return afterLast;
-	}
-
-	switch (*first) {
-	case _UT('!'):
-	case _UT('$'):
-	case _UT('&'):
-	case _UT('('):
-	case _UT(')'):
-	case _UT('-'):
-	case _UT('*'):
-	case _UT(','):
-	case _UT('.'):
-	case _UT(':'):
-	case _UT(';'):
-	case _UT('\''):
-	case _UT('_'):
-	case _UT('~'):
-	case _UT('+'):
-	case _UT('='):
-	case URI_SET_DIGIT:
-	case URI_SET_ALPHA:
-		return URI_FUNC(ParseIpFutLoop)(state, first, afterLast);
-
-	default:
-		return first;
-	}
-}
-
 
 
 /*
@@ -471,7 +444,7 @@ static const URI_CHAR * URI_FUNC(ParseIpFuture)(URI_TYPE(ParserState) * state, c
 			{
 				const URI_CHAR * afterIpFutLoop;
 				const URI_CHAR * const afterHexZero
-						= URI_FUNC(ParseHexZero)(state, first + 2, afterLast);
+						= URI_FUNC(ParseHexZero)(first + 2, afterLast);
 				if (afterHexZero == NULL) {
 					return NULL;
 				}
@@ -863,6 +836,7 @@ static const URI_CHAR * URI_FUNC(ParseIPv6address2)(URI_TYPE(ParserState) * stat
  * [mustBeSegmentNzNc]-><@>[mustBeSegmentNzNc]
  */
 static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		if (!URI_FUNC(PushPathSegment)(state, state->uri->scheme.first, first)) { /* SEGMENT BOTH */
 			URI_FUNC(StopMalloc)(state);
@@ -880,7 +854,8 @@ static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) *
 			if (afterPctEncoded == NULL) {
 				return NULL;
 			}
-			return URI_FUNC(ParseMustBeSegmentNzNc)(state, afterPctEncoded, afterLast);
+			first = afterPctEncoded;
+			goto tail_call;
 		}
 
 	case _UT('@'):
@@ -901,7 +876,8 @@ static const URI_CHAR * URI_FUNC(ParseMustBeSegmentNzNc)(URI_TYPE(ParserState) *
 	case _UT('~'):
 	case URI_SET_DIGIT:
 	case URI_SET_ALPHA:
-		return URI_FUNC(ParseMustBeSegmentNzNc)(state, first + 1, afterLast);
+		first += 1;
+		goto tail_call;
 
 	case _UT('/'):
 		{
@@ -992,6 +968,7 @@ static URI_INLINE UriBool URI_FUNC(OnExitOwnHost2)(URI_TYPE(ParserState) * state
  * [ownHost2]->[pctSubUnres][ownHost2]
  */
 static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		if (!URI_FUNC(OnExitOwnHost2)(state, first)) {
 			URI_FUNC(StopMalloc)(state);
@@ -1025,7 +1002,8 @@ static const URI_CHAR * URI_FUNC(ParseOwnHost2)(URI_TYPE(ParserState) * state, c
 			if (afterPctSubUnres == NULL) {
 				return NULL;
 			}
-			return URI_FUNC(ParseOwnHost2)(state, afterPctSubUnres, afterLast);
+			first = afterPctSubUnres;
+			goto tail_call;
 		}
 
 	default:
@@ -1060,50 +1038,6 @@ static URI_INLINE UriBool URI_FUNC(OnExitOwnHostUserInfo)(URI_TYPE(ParserState)
 
 
 
-/*
- * [ownHostUserInfo]->[ownHostUserInfoNz]
- * [ownHostUserInfo]-><NULL>
- */
-static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
-	if (first >= afterLast) {
-		if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first)) {
-			URI_FUNC(StopMalloc)(state);
-			return NULL;
-		}
-		return afterLast;
-	}
-
-	switch (*first) {
-	case _UT('!'):
-	case _UT('$'):
-	case _UT('%'):
-	case _UT('&'):
-	case _UT('('):
-	case _UT(')'):
-	case _UT('-'):
-	case _UT('*'):
-	case _UT(','):
-	case _UT('.'):
-	case _UT(':'):
-	case _UT(';'):
-	case _UT('@'):
-	case _UT('\''):
-	case _UT('_'):
-	case _UT('~'):
-	case _UT('+'):
-	case _UT('='):
-	case URI_SET_DIGIT:
-	case URI_SET_ALPHA:
-		return URI_FUNC(ParseOwnHostUserInfoNz)(state, first, afterLast);
-
-	default:
-		if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first)) {
-			URI_FUNC(StopMalloc)(state);
-			return NULL;
-		}
-		return first;
-	}
-}
 
 
 
@@ -1113,53 +1047,72 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseOwnHostUserInfo)(URI_TYPE(Parse
  * [ownHostUserInfoNz]-><@>[ownHost]
  */
 static const URI_CHAR * URI_FUNC(ParseOwnHostUserInfoNz)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
-	if (first >= afterLast) {
-		URI_FUNC(StopSyntax)(state, first);
-		return NULL;
-	}
-
-	switch (*first) {
-	case _UT('!'):
-	case _UT('$'):
-	case _UT('%'):
-	case _UT('&'):
-	case _UT('('):
-	case _UT(')'):
-	case _UT('-'):
-	case _UT('*'):
-	case _UT(','):
-	case _UT('.'):
-	case _UT(';'):
-	case _UT('\''):
-	case _UT('_'):
-	case _UT('~'):
-	case _UT('+'):
-	case _UT('='):
-	case URI_SET_DIGIT:
-	case URI_SET_ALPHA:
-		{
-			const URI_CHAR * const afterPctSubUnres
-					= URI_FUNC(ParsePctSubUnres)(state, first, afterLast);
-			if (afterPctSubUnres == NULL) {
-				return NULL;
+	const URI_CHAR * const originalFirst = first;
+
+	while (first < afterLast) {
+		switch (*first) {
+		case _UT('!'):
+		case _UT('$'):
+		case _UT('%'):
+		case _UT('&'):
+		case _UT('('):
+		case _UT(')'):
+		case _UT('-'):
+		case _UT('*'):
+		case _UT(','):
+		case _UT('.'):
+		case _UT(';'):
+		case _UT('\''):
+		case _UT('_'):
+		case _UT('~'):
+		case _UT('+'):
+		case _UT('='):
+		case URI_SET_DIGIT:
+		case URI_SET_ALPHA:
+			{
+				const URI_CHAR * const afterPctSubUnres
+						= URI_FUNC(ParsePctSubUnres)(state, first, afterLast);
+				if (afterPctSubUnres == NULL) {
+					return NULL;
+				}
+				first = afterPctSubUnres;
+				break;
 			}
-			return URI_FUNC(ParseOwnHostUserInfo)(state, afterPctSubUnres, afterLast);
+
+		default:
+			goto done_looping;
+			break;
 		}
+	}
 
-	case _UT(':'):
-		state->uri->hostText.afterLast = first; /* HOST END */
-		state->uri->portText.first = first + 1; /* PORT BEGIN */
-		return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast);
+done_looping:
+	if (first < afterLast) {
+		switch (*first) {
+		case _UT(':'):
+			state->uri->hostText.afterLast = first; /* HOST END */
+			state->uri->portText.first = first + 1; /* PORT BEGIN */
+			return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast);
 
-	case _UT('@'):
-		state->uri->userInfo.afterLast = first; /* USERINFO END */
-		state->uri->hostText.first = first + 1; /* HOST BEGIN */
-		return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast);
+		case _UT('@'):
+			state->uri->userInfo.afterLast = first; /* USERINFO END */
+			state->uri->hostText.first = first + 1; /* HOST BEGIN */
+			return URI_FUNC(ParseOwnHost)(state, first + 1, afterLast);
 
-	default:
+		default:
+			break;
+		}
+	}
+
+	if (first == originalFirst) {
 		URI_FUNC(StopSyntax)(state, first);
 		return NULL;
 	}
+
+	if (!URI_FUNC(OnExitOwnHostUserInfo)(state, first)) {
+		URI_FUNC(StopMalloc)(state);
+		return NULL;
+	}
+	return first;
 }
 
 
@@ -1199,6 +1152,7 @@ static URI_INLINE UriBool URI_FUNC(OnExitOwnPortUserInfo)(URI_TYPE(ParserState)
  * [ownPortUserInfo]-><NULL>
  */
 static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		if (!URI_FUNC(OnExitOwnPortUserInfo)(state, first)) {
 			URI_FUNC(StopMalloc)(state);
@@ -1234,7 +1188,8 @@ static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * s
 		return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast);
 
 	case URI_SET_DIGIT:
-		return URI_FUNC(ParseOwnPortUserInfo)(state, first + 1, afterLast);
+		first += 1;
+		goto tail_call;
 
 	case _UT('%'):
 		state->uri->portText.first = NULL; /* Not a port, reset */
@@ -1271,6 +1226,7 @@ static const URI_CHAR * URI_FUNC(ParseOwnPortUserInfo)(URI_TYPE(ParserState) * s
  * [ownUserInfo]-><@>[ownHost]
  */
 static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		URI_FUNC(StopSyntax)(state, first);
 		return NULL;
@@ -1301,11 +1257,13 @@ static const URI_CHAR * URI_FUNC(ParseOwnUserInfo)(URI_TYPE(ParserState) * state
 			if (afterPctSubUnres == NULL) {
 				return NULL;
 			}
-			return URI_FUNC(ParseOwnUserInfo)(state, afterPctSubUnres, afterLast);
+			first = afterPctSubUnres;
+			goto tail_call;
 		}
 
 	case _UT(':'):
-		return URI_FUNC(ParseOwnUserInfo)(state, first + 1, afterLast);
+		first += 1;
+		goto tail_call;
 
 	case _UT('@'):
 		/* SURE */
@@ -1366,6 +1324,7 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParsePartHelperTwo)(URI_TYPE(ParserS
  * [pathAbsEmpty]-><NULL>
  */
 static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		return afterLast;
 	}
@@ -1382,7 +1341,8 @@ static const URI_CHAR * URI_FUNC(ParsePathAbsEmpty)(URI_TYPE(ParserState) * stat
 				URI_FUNC(StopMalloc)(state);
 				return NULL;
 			}
-			return URI_FUNC(ParsePathAbsEmpty)(state, afterSegment, afterLast);
+			first = afterSegment;
+			goto tail_call;
 		}
 
 	default:
@@ -1605,14 +1565,16 @@ static const URI_CHAR * URI_FUNC(ParsePctSubUnres)(URI_TYPE(ParserState) * state
  * [port]->[DIGIT][port]
  * [port]-><NULL>
  */
-static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+static const URI_CHAR * URI_FUNC(ParsePort)(const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		return afterLast;
 	}
 
 	switch (*first) {
 	case URI_SET_DIGIT:
-		return URI_FUNC(ParsePort)(state, first + 1, afterLast);
+		first += 1;
+		goto tail_call;
 
 	default:
 		return first;
@@ -1628,6 +1590,7 @@ static const URI_CHAR * URI_FUNC(ParsePort)(URI_TYPE(ParserState) * state, const
  * [queryFrag]-><NULL>
  */
 static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		return afterLast;
 	}
@@ -1659,12 +1622,14 @@ static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state,
 			if (afterPchar == NULL) {
 				return NULL;
 			}
-			return URI_FUNC(ParseQueryFrag)(state, afterPchar, afterLast);
+			first = afterPchar;
+			goto tail_call;
 		}
 
 	case _UT('/'):
 	case _UT('?'):
-		return URI_FUNC(ParseQueryFrag)(state, first + 1, afterLast);
+		first += 1;
+		goto tail_call;
 
 	default:
 		return first;
@@ -1678,6 +1643,7 @@ static const URI_CHAR * URI_FUNC(ParseQueryFrag)(URI_TYPE(ParserState) * state,
  * [segment]-><NULL>
  */
 static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		return afterLast;
 	}
@@ -1709,7 +1675,8 @@ static const URI_CHAR * URI_FUNC(ParseSegment)(URI_TYPE(ParserState) * state, co
 			if (afterPchar == NULL) {
 				return NULL;
 			}
-			return URI_FUNC(ParseSegment)(state, afterPchar, afterLast);
+			first = afterPchar;
+			goto tail_call;
 		}
 
 	default:
@@ -1768,6 +1735,7 @@ static URI_INLINE UriBool URI_FUNC(OnExitSegmentNzNcOrScheme2)(URI_TYPE(ParserSt
  * [segmentNzNcOrScheme2]-><->[segmentNzNcOrScheme2]
  */
 static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		if (!URI_FUNC(OnExitSegmentNzNcOrScheme2)(state, first)) {
 			URI_FUNC(StopMalloc)(state);
@@ -1782,7 +1750,8 @@ static const URI_CHAR * URI_FUNC(ParseSegmentNzNcOrScheme2)(URI_TYPE(ParserState
 	case _UT('-'):
 	case URI_SET_ALPHA:
 	case URI_SET_DIGIT:
-		return URI_FUNC(ParseSegmentNzNcOrScheme2)(state, first + 1, afterLast);
+		first += 1;
+		goto tail_call;
 
 	case _UT('%'):
 		{
@@ -1996,11 +1965,8 @@ static URI_INLINE const URI_CHAR * URI_FUNC(ParseUriTailTwo)(URI_TYPE(ParserStat
 
 
 
-/*
- * [zeroMoreSlashSegs]-></>[segment][zeroMoreSlashSegs]
- * [zeroMoreSlashSegs]-><NULL>
- */
 static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) * state, const URI_CHAR * first, const URI_CHAR * afterLast) {
+tail_call:
 	if (first >= afterLast) {
 		return afterLast;
 	}
@@ -2017,7 +1983,8 @@ static const URI_CHAR * URI_FUNC(ParseZeroMoreSlashSegs)(URI_TYPE(ParserState) *
 				URI_FUNC(StopMalloc)(state);
 				return NULL;
 			}
-			return URI_FUNC(ParseZeroMoreSlashSegs)(state, afterSegment, afterLast);
+			first = afterSegment;
+			goto tail_call;
 		}
 
 	default:
diff --git a/test/test.cpp b/test/test.cpp
index 623e19e..b3da363 100644
--- a/test/test.cpp
+++ b/test/test.cpp
@@ -108,6 +108,7 @@ public:
 		TEST_ADD(UriSuite::testParseInvalid_Bug16)
 		TEST_ADD(UriSuite::testRangeComparison)
 		TEST_ADD(UriSuite::testEquals)
+		TEST_ADD(UriSuite::testNoStackOverflowIssue282)
 	}
 
 private:
@@ -1907,6 +1908,23 @@ Rule                                | Example | hostSet | absPath | emptySeg
 		testCompareRangeHelper("", NULL, 1, AVOID_NULL_RANGE);
 		testCompareRangeHelper("", NULL, 1, KEEP_NULL_RANGE);
 	}
+
+	void testNoStackOverflowIssue282() {
+		const size_t sizeBytes = 2 * 1024 * 1024;
+
+		char * const uriString = new char[sizeBytes];
+		TEST_ASSERT(uriString != NULL);
+		::memset(uriString, 'x', sizeBytes - 1);
+		uriString[sizeBytes - 1] = '\0';
+
+		UriUriA uri;
+		UriParserStateA state;
+		state.uri = &uri;
+		TEST_ASSERT(uriParseUriA(&state, uriString) == URI_SUCCESS);
+
+		uriFreeUriMembersA(&uri);
+		delete[] uriString;
+	}
 };
 
 
openSUSE Build Service is sponsored by