MEDIUM: tools: improve time format error detection

As reported in GH issue #109 and in discourse issue
https://discourse.haproxy.org/t/haproxy-returns-408-or-504-error-when-timeout-client-value-is-every-25d
the time parser doesn't error on overflows nor underflows. This is a
recurring problem which additionally has the bad taste of taking a long
time before hitting the user.

This patch makes parse_time_err() return special error codes for overflows
and underflows, and adds the control in the call places to report suitable
errors depending on the requested unit. In practice, underflows are almost
never returned as the parsing function takes care of rounding values up,
so this might possibly happen on 64-bit overflows returning exactly zero
after rounding though. It is not really possible to cut the patch into
pieces as it changes the function's API, hence all callers.

Tests were run on about every relevant part (cookie maxlife/maxidle,
server inter, stats timeout, timeout*, cli's set timeout command,
tcp-request/response inspect-delay).
diff --git a/src/arg.c b/src/arg.c
index b0fe945..2719b53 100644
--- a/src/arg.c
+++ b/src/arg.c
@@ -222,8 +222,11 @@
 				goto empty_err;
 
 			ptr_err = parse_time_err(word, &uint, TIME_UNIT_MS);
-			if (ptr_err)
+			if (ptr_err) {
+				if (ptr_err == PARSE_TIME_OVER || ptr_err == PARSE_TIME_UNDER)
+					ptr_err = word;
 				goto parse_err;
+			}
 			arg->data.sint = uint;
 			arg->type = ARGT_SINT;
 			break;
diff --git a/src/cfgparse-global.c b/src/cfgparse-global.c
index 8355a8f..4ecaff1 100644
--- a/src/cfgparse-global.c
+++ b/src/cfgparse-global.c
@@ -263,9 +263,21 @@
 		}
 
 		res = parse_time_err(args[1], &idle, TIME_UNIT_MS);
-		if (res) {
+		if (res == PARSE_TIME_OVER) {
+			ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 65535 ms.\n",
+			         file, linenum, args[1], args[0]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		else if (res == PARSE_TIME_UNDER) {
+			ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
+			         file, linenum, args[1], args[0]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		else if (res) {
 			ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
-			      file, linenum, *res, args[0]);
+			         file, linenum, *res, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
@@ -942,15 +954,21 @@
 		}
 
 		err = parse_time_err(args[1], &val, TIME_UNIT_MS);
-		if (err) {
-			ha_alert("parsing [%s:%d]: unsupported character '%c' in '%s' (wants an integer delay).\n", file, linenum, *err, args[0]);
+		if (err == PARSE_TIME_OVER) {
+			ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
+			         file, linenum, args[1], args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
 		}
-		global.max_spread_checks = val;
-		if (global.max_spread_checks < 0) {
-			ha_alert("parsing [%s:%d]: '%s' needs a positive delay in milliseconds.\n",file, linenum, args[0]);
+		else if (err == PARSE_TIME_UNDER) {
+			ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
+			         file, linenum, args[1], args[0]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+		}
+		else if (err) {
+			ha_alert("parsing [%s:%d]: unsupported character '%c' in '%s' (wants an integer delay).\n", file, linenum, *err, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
 		}
+		global.max_spread_checks = val;
 	}
 	else if (strcmp(args[0], "cpu-map") == 0) {
 		/* map a process list to a CPU set */
diff --git a/src/cfgparse-listen.c b/src/cfgparse-listen.c
index 7ffc0e0..d659779 100644
--- a/src/cfgparse-listen.c
+++ b/src/cfgparse-listen.c
@@ -1067,7 +1067,19 @@
 				}
 
 				res = parse_time_err(args[cur_arg + 1], &maxidle, TIME_UNIT_S);
-				if (res) {
+				if (res == PARSE_TIME_OVER) {
+					ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 s (~68 years).\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg]);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (res == PARSE_TIME_UNDER) {
+					ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 s.\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg]);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (res) {
 					ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
 						 file, linenum, *res, args[cur_arg]);
 					err_code |= ERR_ALERT | ERR_FATAL;
@@ -1087,8 +1099,21 @@
 					goto out;
 				}
 
+
 				res = parse_time_err(args[cur_arg + 1], &maxlife, TIME_UNIT_S);
-				if (res) {
+				if (res == PARSE_TIME_OVER) {
+					ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 s (~68 years).\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg]);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (res == PARSE_TIME_UNDER) {
+					ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 s.\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg]);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (res) {
 					ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
 						 file, linenum, *res, args[cur_arg]);
 					err_code |= ERR_ALERT | ERR_FATAL;
@@ -1932,8 +1957,20 @@
 			unsigned interval;
 
 			err = parse_time_err(args[2], &interval, TIME_UNIT_S);
-			if (err) {
-				ha_alert("parsing [%s:%d] : unexpected character '%c' in stats refresh interval.\n",
+			if (err == PARSE_TIME_OVER) {
+				ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to stats refresh interval, maximum value is 2147483647 s (~68 years).\n",
+					 file, linenum, args[2]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			else if (err == PARSE_TIME_UNDER) {
+				ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to stats refresh interval, minimum non-null value is 1 s.\n",
+					 file, linenum, args[2]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			else if (err) {
+				ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to stats refresh interval.\n",
 					 file, linenum, *err);
 				err_code |= ERR_ALERT | ERR_FATAL;
 				goto out;
@@ -3374,7 +3411,19 @@
 			goto out;
 		}
 		err = parse_time_err(args[1], &val, TIME_UNIT_MS);
-		if (err) {
+		if (err == PARSE_TIME_OVER) {
+			ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to grace time, maximum value is 2147483647 ms (~24.8 days).\n",
+			         file, linenum, args[1]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		else if (err == PARSE_TIME_UNDER) {
+			ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to grace time, minimum non-null value is 1 ms.\n",
+			         file, linenum, args[1]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		else if (err) {
 			ha_alert("parsing [%s:%d] : unexpected character '%c' in grace time.\n",
 				 file, linenum, *err);
 			err_code |= ERR_ALERT | ERR_FATAL;
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 98adadf..1101470 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1203,7 +1203,19 @@
 			goto out;
 		}
 		res = parse_time_err(args[2], &time, TIME_UNIT_MS);
-		if (res) {
+		if (res == PARSE_TIME_OVER) {
+			ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
+			         file, linenum, args[1], args[0]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		else if (res == PARSE_TIME_UNDER) {
+			ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
+			         file, linenum, args[1], args[0]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		else if (res) {
 			ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
 				 file, linenum, *res, args[0]);
 			err_code |= ERR_ALERT | ERR_FATAL;
@@ -1283,7 +1295,19 @@
 				goto out;
 			}
 			res = parse_time_err(args[2], &tout, TIME_UNIT_MS);
-			if (res) {
+			if (res == PARSE_TIME_OVER) {
+				ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s %s>, maximum value is 2147483647 ms (~24.8 days).\n",
+					 file, linenum, args[2], args[0], args[1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			else if (res == PARSE_TIME_UNDER) {
+				ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s %s>, minimum non-null value is 1 ms.\n",
+					 file, linenum, args[2], args[0], args[1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			else if (res) {
 				ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n",
 					 file, linenum, *res, args[0], args[1]);
 				err_code |= ERR_ALERT | ERR_FATAL;
@@ -1459,14 +1483,21 @@
 				goto out;
 			}
 			res = parse_time_err(args[2], &timeout_mail, TIME_UNIT_MS);
-			if (res) {
-				ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s>.\n",
-					 file, linenum, *res, args[0]);
+			if (res == PARSE_TIME_OVER) {
+				ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s %s>, maximum value is 2147483647 ms (~24.8 days).\n",
+					 file, linenum, args[2], args[0], args[1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			else if (res == PARSE_TIME_UNDER) {
+				ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s %s>, minimum non-null value is 1 ms.\n",
+					 file, linenum, args[2], args[0], args[1]);
 				err_code |= ERR_ALERT | ERR_FATAL;
 				goto out;
 			}
-			if (timeout_mail <= 0) {
-				ha_alert("parsing [%s:%d] : '%s %s' expects a positive <time> argument.\n", file, linenum, args[0], args[1]);
+			else if (res) {
+				ha_alert("parsing [%s:%d]: unexpected character '%c' in argument to <%s %s>.\n",
+					 file, linenum, *res, args[0], args[1]);
 				err_code |= ERR_ALERT | ERR_FATAL;
 				goto out;
 			}
diff --git a/src/cli.c b/src/cli.c
index 9949a88..25743d9 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -309,7 +309,17 @@
 		unsigned timeout;
 		const char *res = parse_time_err(args[2], &timeout, TIME_UNIT_MS);
 
-		if (res) {
+		if (res == PARSE_TIME_OVER) {
+			memprintf(err, "timer overflow in argument '%s' to '%s %s' (maximum value is 2147483647 ms or ~24.8 days)",
+				 args[2], args[0], args[1]);
+			return -1;
+		}
+		else if (res == PARSE_TIME_UNDER) {
+			memprintf(err, "timer underflow in argument '%s' to '%s %s' (minimum non-null value is 1 ms)",
+				 args[2], args[0], args[1]);
+			return -1;
+		}
+		else if (res) {
 			memprintf(err, "'%s %s' : unexpected character '%c'", args[0], args[1], *res);
 			return -1;
 		}
diff --git a/src/flt_spoe.c b/src/flt_spoe.c
index 711ac80..f20b264 100644
--- a/src/flt_spoe.c
+++ b/src/flt_spoe.c
@@ -3482,7 +3482,19 @@
 			goto out;
 		}
 		res = parse_time_err(args[2], &timeout, TIME_UNIT_MS);
-		if (res) {
+		if (res == PARSE_TIME_OVER) {
+			ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s %s>, maximum value is 2147483647 ms (~24.8 days).\n",
+				 file, linenum, args[2], args[0], args[1]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		else if (res == PARSE_TIME_UNDER) {
+			ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s %s>, minimum non-null value is 1 ms.\n",
+				 file, linenum, args[2], args[0], args[1]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+		else if (res) {
 			ha_alert("parsing [%s:%d] : unexpected character '%c' in 'timeout %s'.\n",
 				 file, linenum, *res, args[1]);
 			err_code |= ERR_ALERT | ERR_FATAL;
diff --git a/src/hlua.c b/src/hlua.c
index ef79632..28abd08 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -8073,7 +8073,17 @@
 	const char *error;
 
 	error = parse_time_err(args[1], timeout, TIME_UNIT_MS);
-	if (error && *error != '\0') {
+	if (error == PARSE_TIME_OVER) {
+		memprintf(err, "timer overflow in argument <%s> to <%s> (maximum value is 2147483647 ms or ~24.8 days)",
+			  args[1], args[0]);
+		return -1;
+	}
+	else if (error == PARSE_TIME_UNDER) {
+		memprintf(err, "timer underflow in argument <%s> to <%s> (minimum non-null value is 1 ms)",
+			  args[1], args[0]);
+		return -1;
+	}
+	else if (error) {
 		memprintf(err, "%s: invalid timeout", args[0]);
 		return -1;
 	}
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 51d10a5..64ffb83 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1816,7 +1816,17 @@
 	}
 
 	ptr = parse_time_err(args[cur_arg + 1], &timeout, TIME_UNIT_MS);
-	if (ptr) {
+	if (ptr == PARSE_TIME_OVER) {
+		memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
+			  args[cur_arg+1], args[cur_arg]);
+		return ERR_ALERT | ERR_FATAL;
+	}
+	else if (ptr == PARSE_TIME_UNDER) {
+		memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
+			  args[cur_arg+1], args[cur_arg]);
+		return ERR_ALERT | ERR_FATAL;
+	}
+	else if (ptr) {
 		memprintf(err, "'%s' : expects a positive delay in milliseconds", args[cur_arg]);
 		return ERR_ALERT | ERR_FATAL;
 	}
@@ -1891,7 +1901,17 @@
 	}
 
 	ptr = parse_time_err(args[*cur_arg + 1], &timeout, TIME_UNIT_MS);
-	if (ptr) {
+	if (ptr == PARSE_TIME_OVER) {
+		memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
+			  args[*cur_arg+1], args[*cur_arg]);
+		return ERR_ALERT | ERR_FATAL;
+	}
+	else if (ptr == PARSE_TIME_UNDER) {
+		memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
+			  args[*cur_arg+1], args[*cur_arg]);
+		return ERR_ALERT | ERR_FATAL;
+	}
+	else if (ptr) {
 		memprintf(err, "'%s' : expects a positive delay in milliseconds", args[*cur_arg]);
 		return ERR_ALERT | ERR_FATAL;
 	}
diff --git a/src/proxy.c b/src/proxy.c
index 575a8ef..78babd5 100644
--- a/src/proxy.c
+++ b/src/proxy.c
@@ -275,7 +275,17 @@
 	}
 
 	res = parse_time_err(args[1], &timeout, TIME_UNIT_MS);
-	if (res) {
+	if (res == PARSE_TIME_OVER) {
+		memprintf(err, "timer overflow in argument '%s' to 'timeout %s' (maximum value is 2147483647 ms or ~24.8 days)",
+			  args[1], name);
+		return -1;
+	}
+	else if (res == PARSE_TIME_UNDER) {
+		memprintf(err, "timer underflow in argument '%s' to 'timeout %s' (minimum non-null value is 1 ms)",
+			  args[1], name);
+		return -1;
+	}
+	else if (res) {
 		memprintf(err, "unexpected character '%c' in 'timeout %s'", *res, name);
 		return -1;
 	}
@@ -1056,7 +1066,17 @@
 		return -1;
 	}
 	res = parse_time_err(args[1], &global.hard_stop_after, TIME_UNIT_MS);
-	if (res) {
+	if (res == PARSE_TIME_OVER) {
+		memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
+			  args[1], args[0]);
+		return -1;
+	}
+	else if (res == PARSE_TIME_UNDER) {
+		memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
+			  args[1], args[0]);
+		return -1;
+	}
+	else if (res) {
 		memprintf(err, "unexpected character '%c' in argument to <%s>.\n", *res, args[0]);
 		return -1;
 	}
diff --git a/src/server.c b/src/server.c
index 14e1a93..0cbba78 100644
--- a/src/server.c
+++ b/src/server.c
@@ -404,7 +404,17 @@
 		return ERR_ALERT | ERR_FATAL;
 	}
 	res = parse_time_err(arg, &time, TIME_UNIT_MS);
-	if (res) {
+	if (res == PARSE_TIME_OVER) {
+		memprintf(err, "timer overflow in argument '%s' to '%s' (maximum value is 2147483647 ms or ~24.8 days)",
+			  args[*cur_arg+1], args[*cur_arg]);
+		return ERR_ALERT | ERR_FATAL;
+	}
+	else if (res == PARSE_TIME_UNDER) {
+		memprintf(err, "timer underflow in argument '%s' to '%s' (minimum non-null value is 1 ms)",
+			  args[*cur_arg+1], args[*cur_arg]);
+		return ERR_ALERT | ERR_FATAL;
+	}
+	else if (res) {
 		memprintf(err, "unexpected character '%c' in argument to <%s>.\n",
 		    *res, args[*cur_arg]);
 		return ERR_ALERT | ERR_FATAL;
@@ -2305,7 +2315,20 @@
 		while (*args[cur_arg]) {
 			if (!strcmp(args[cur_arg], "agent-inter")) {
 				const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
-				if (err) {
+
+				if (err == PARSE_TIME_OVER) {
+					ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s> of server %s, maximum value is 2147483647 ms (~24.8 days).\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err == PARSE_TIME_UNDER) {
+					ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s> of server %s, minimum non-null value is 1 ms.\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err) {
 					ha_alert("parsing [%s:%d] : unexpected character '%c' in 'agent-inter' argument of server %s.\n",
 					      file, linenum, *err, newsrv->id);
 					err_code |= ERR_ALERT | ERR_FATAL;
@@ -2530,7 +2553,20 @@
 			}
 			else if (!strcmp(args[cur_arg], "inter")) {
 				const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
-				if (err) {
+
+				if (err == PARSE_TIME_OVER) {
+					ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s> of server %s, maximum value is 2147483647 ms (~24.8 days).\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err == PARSE_TIME_UNDER) {
+					ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s> of server %s, minimum non-null value is 1 ms.\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err) {
 					ha_alert("parsing [%s:%d] : unexpected character '%c' in 'inter' argument of server %s.\n",
 					      file, linenum, *err, newsrv->id);
 					err_code |= ERR_ALERT | ERR_FATAL;
@@ -2547,7 +2583,20 @@
 			}
 			else if (!strcmp(args[cur_arg], "fastinter")) {
 				const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
-				if (err) {
+
+				if (err == PARSE_TIME_OVER) {
+					ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s> of server %s, maximum value is 2147483647 ms (~24.8 days).\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err == PARSE_TIME_UNDER) {
+					ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s> of server %s, minimum non-null value is 1 ms.\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err) {
 					ha_alert("parsing [%s:%d]: unexpected character '%c' in 'fastinter' argument of server %s.\n",
 					      file, linenum, *err, newsrv->id);
 					err_code |= ERR_ALERT | ERR_FATAL;
@@ -2564,7 +2613,20 @@
 			}
 			else if (!strcmp(args[cur_arg], "downinter")) {
 				const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
-				if (err) {
+
+				if (err == PARSE_TIME_OVER) {
+					ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s> of server %s, maximum value is 2147483647 ms (~24.8 days).\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err == PARSE_TIME_UNDER) {
+					ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s> of server %s, minimum non-null value is 1 ms.\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err) {
 					ha_alert("parsing [%s:%d]: unexpected character '%c' in 'downinter' argument of server %s.\n",
 					      file, linenum, *err, newsrv->id);
 					err_code |= ERR_ALERT | ERR_FATAL;
@@ -2611,7 +2673,20 @@
 			else if (!strcmp(args[cur_arg], "slowstart")) {
 				/* slowstart is stored in seconds */
 				const char *err = parse_time_err(args[cur_arg + 1], &val, TIME_UNIT_MS);
-				if (err) {
+
+				if (err == PARSE_TIME_OVER) {
+					ha_alert("parsing [%s:%d]: timer overflow in argument <%s> to <%s> of server %s, maximum value is 2147483647 ms (~24.8 days).\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err == PARSE_TIME_UNDER) {
+					ha_alert("parsing [%s:%d]: timer underflow in argument <%s> to <%s> of server %s, minimum non-null value is 1 ms.\n",
+						 file, linenum, args[cur_arg+1], args[cur_arg], newsrv->id);
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+				else if (err) {
 					ha_alert("parsing [%s:%d] : unexpected character '%c' in 'slowstart' argument of server %s.\n",
 					      file, linenum, *err, newsrv->id);
 					err_code |= ERR_ALERT | ERR_FATAL;
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 5cc005b..b6364fa 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -9065,7 +9065,17 @@
 	}
 
 	res = parse_time_err(args[1], &global_ssl.life_time, TIME_UNIT_S);
-	if (res) {
+	if (res == PARSE_TIME_OVER) {
+		memprintf(err, "timer overflow in argument '%s' to <%s> (maximum value is 2147483647 s or ~68 years).",
+			  args[1], args[0]);
+		return -1;
+	}
+	else if (res == PARSE_TIME_UNDER) {
+		memprintf(err, "timer underflow in argument '%s' to <%s> (minimum non-null value is 1 s).",
+			  args[1], args[0]);
+		return -1;
+	}
+	else if (res) {
 		memprintf(err, "unexpected character '%c' in argument to <%s>.", *res, args[0]);
 		return -1;
 	}
diff --git a/src/standard.c b/src/standard.c
index a67948b..3651f5e 100644
--- a/src/standard.c
+++ b/src/standard.c
@@ -2032,12 +2032,15 @@
  * The value is returned in <ret> if everything is fine, and a NULL is returned
  * by the function. In case of error, a pointer to the error is returned and
  * <ret> is left untouched. Values are automatically rounded up when needed.
+ * Values resulting in values larger than or equal to 2^31 after conversion are
+ * reported as an overflow as value PARSE_TIME_OVER. Non-null values resulting
+ * in an underflow are reported as an underflow as value PARSE_TIME_UNDER.
  */
 const char *parse_time_err(const char *text, unsigned *ret, unsigned unit_flags)
 {
-	unsigned imult, idiv;
-	unsigned omult, odiv;
-	unsigned value;
+	unsigned long long imult, idiv;
+	unsigned long long omult, odiv;
+	unsigned long long value, result;
 
 	omult = odiv = 1;
 
@@ -2100,8 +2103,12 @@
 	if (imult % odiv == 0) { imult /= odiv; odiv = 1; }
 	if (odiv % imult == 0) { odiv /= imult; imult = 1; }
 
-	value = (value * (imult * omult) + (idiv * odiv - 1)) / (idiv * odiv);
-	*ret = value;
+	result = (value * (imult * omult) + (idiv * odiv - 1)) / (idiv * odiv);
+	if (result >= 0x80000000)
+		return PARSE_TIME_OVER;
+	if (!result && value)
+		return PARSE_TIME_UNDER;
+	*ret = result;
 	return NULL;
 }
 
diff --git a/src/stick_table.c b/src/stick_table.c
index a555e64..4b04f18 100644
--- a/src/stick_table.c
+++ b/src/stick_table.c
@@ -769,15 +769,21 @@
 				goto out;
 			}
 			err = parse_time_err(args[idx], &val, TIME_UNIT_MS);
-			if (err) {
-				ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
-					 file, linenum, args[0], *err, args[idx-1]);
+			if (err == PARSE_TIME_OVER) {
+				ha_alert("parsing [%s:%d]: %s: timer overflow in argument <%s> to <%s>, maximum value is 2147483647 ms (~24.8 days).\n",
+					 file, linenum, args[0], args[idx], args[idx-1]);
 				err_code |= ERR_ALERT | ERR_FATAL;
 				goto out;
 			}
-			if (val > INT_MAX) {
-				ha_alert("parsing [%s:%d] : Expire value [%u]ms exceeds maxmimum value of 24.85 days.\n",
-					 file, linenum, val);
+			else if (err == PARSE_TIME_UNDER) {
+				ha_alert("parsing [%s:%d]: %s: timer underflow in argument <%s> to <%s>, minimum non-null value is 1 ms.\n",
+					 file, linenum, args[0], args[idx], args[idx-1]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			else if (err) {
+				ha_alert("parsing [%s:%d] : %s: unexpected character '%c' in argument of '%s'.\n",
+					 file, linenum, args[0], *err, args[idx-1]);
 				err_code |= ERR_ALERT | ERR_FATAL;
 				goto out;
 			}
diff --git a/src/tcp_rules.c b/src/tcp_rules.c
index a70c4c0..72b11ae 100644
--- a/src/tcp_rules.c
+++ b/src/tcp_rules.c
@@ -922,7 +922,12 @@
 			memprintf(err,
 			          "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
 			          args[0], args[1], proxy_type_str(curpx), curpx->id);
-			if (ptr)
+
+			if (ptr == PARSE_TIME_OVER)
+				memprintf(err, "%s (timer overflow in '%s', maximum value is 2147483647 ms or ~24.8 days)", *err, args[2]);
+			else if (ptr == PARSE_TIME_UNDER)
+				memprintf(err, "%s (timer underflow in '%s', minimum non-null value is 1 ms)", *err, args[2]);
+			else if (ptr)
 				memprintf(err, "%s (unexpected character '%c')", *err, *ptr);
 			return -1;
 		}
@@ -1031,7 +1036,12 @@
 			memprintf(err,
 			          "'%s %s' expects a positive delay in milliseconds, in %s '%s'",
 			          args[0], args[1], proxy_type_str(curpx), curpx->id);
-			if (ptr)
+
+			if (ptr == PARSE_TIME_OVER)
+				memprintf(err, "%s (timer overflow in '%s', maximum value is 2147483647 ms or ~24.8 days)", *err, args[2]);
+			else if (ptr == PARSE_TIME_UNDER)
+				memprintf(err, "%s (timer underflow in '%s', minimum non-null value is 1 ms)", *err, args[2]);
+			else if (ptr)
 				memprintf(err, "%s (unexpected character '%c')", *err, *ptr);
 			return -1;
 		}