Robustify parsing of numbers from strings

* defs.h (string_to_uint): New prototype.
* util.c (string_to_uint): New function.
* strace.c (error_opt_arg): New function.
(process_opt_p_list): Use string_to_uint instead of atoi.
Terminate in case of invalid process id.
(init): Use string_to_uint instead of atoi.
Use error_opt_arg in case of invalid option argument.
* syscall.c (qual_syscall, qual_signal, qual_desc): Use string_to_uint
instead of atoi.
diff --git a/defs.h b/defs.h
index e46e230..3348400 100644
--- a/defs.h
+++ b/defs.h
@@ -489,6 +489,8 @@
 
 extern const char *xlookup(const struct xlat *, int);
 
+extern int string_to_uint(const char *str);
+
 #if HAVE_LONG_LONG
 /* _l refers to the lower numbered u_arg,
  * _h refers to the higher numbered u_arg
diff --git a/strace.c b/strace.c
index ac7e672..c211ac7 100644
--- a/strace.c
+++ b/strace.c
@@ -131,7 +131,7 @@
 static gid_t run_gid;
 
 unsigned int max_strlen = DEFAULT_STRLEN;
-static unsigned int acolumn = DEFAULT_ACOLUMN;
+static int acolumn = DEFAULT_ACOLUMN;
 static char *acolumn_spaces;
 
 static char *outfname = NULL;
@@ -315,6 +315,12 @@
 	error_msg_and_die("Out of memory");
 }
 
+static void
+error_opt_arg(int opt, const char *arg)
+{
+	error_msg_and_die("Invalid -%c argument: '%s'", opt, arg);
+}
+
 /* Glue for systems without a MMU that cannot provide fork() */
 #ifdef HAVE_FORK
 # define strace_vforked 0
@@ -825,14 +831,14 @@
 		char c = *delim;
 
 		*delim = '\0';
-		pid = atoi(opt); /* TODO: stricter parsing of the number? */
+		pid = string_to_uint(opt);
 		if (pid <= 0) {
-			error_msg("Invalid process id: '%s'", opt);
+			error_msg_and_die("Invalid process id: '%s'", opt);
 			*delim = c;
 			return;
 		}
 		if (pid == strace_tracer_pid) {
-			error_msg("I'm sorry, I can't let you do that, Dave.");
+			error_msg_and_die("I'm sorry, I can't let you do that, Dave.");
 			*delim = c;
 			return;
 		}
@@ -905,6 +911,7 @@
 
 					if (de->d_fileno == 0)
 						continue;
+					/* we trust /proc filesystem */
 					tid = atoi(de->d_name);
 					if (tid <= 0)
 						continue;
@@ -1445,7 +1452,7 @@
 init(int argc, char *argv[])
 {
 	struct tcb *tcp;
-	int c;
+	int c, i;
 	int optF = 0;
 	struct sigaction sa;
 
@@ -1547,9 +1554,9 @@
 			not_failing_only = 1;
 			break;
 		case 'a':
-			acolumn = atoi(optarg);
+			acolumn = string_to_uint(optarg);
 			if (acolumn < 0)
-				error_msg_and_die("Bad column width '%s'", optarg);
+				error_opt_arg(c, optarg);
 			break;
 		case 'e':
 			qualify(optarg);
@@ -1558,7 +1565,10 @@
 			outfname = strdup(optarg);
 			break;
 		case 'O':
-			set_overhead(atoi(optarg));
+			i = string_to_uint(optarg);
+			if (i < 0)
+				error_opt_arg(c, optarg);
+			set_overhead(i);
 			break;
 		case 'p':
 			process_opt_p_list(optarg);
@@ -1570,10 +1580,10 @@
 			}
 			break;
 		case 's':
-			max_strlen = atoi(optarg);
-			if (max_strlen < 0) {
-				error_msg_and_die("Invalid -%c argument: '%s'", c, optarg);
-			}
+			i = string_to_uint(optarg);
+			if (i < 0)
+				error_opt_arg(c, optarg);
+			max_strlen = i;
 			break;
 		case 'S':
 			set_sortby(optarg);
@@ -1586,10 +1596,9 @@
 				die_out_of_memory();
 			break;
 		case 'I':
-			opt_intr = atoi(optarg);
-			if (opt_intr <= 0 || opt_intr >= NUM_INTR_OPTS) {
-				error_msg_and_die("Invalid -%c argument: '%s'", c, optarg);
-			}
+			opt_intr = string_to_uint(optarg);
+			if (opt_intr <= 0 || opt_intr >= NUM_INTR_OPTS)
+				error_opt_arg(c, optarg);
 			break;
 		default:
 			usage(stderr, 1);
diff --git a/syscall.c b/syscall.c
index c4ac977..cf9cd08 100644
--- a/syscall.c
+++ b/syscall.c
@@ -338,7 +338,7 @@
 	int rc = -1;
 
 	if (*s >= '0' && *s <= '9') {
-		int i = atoi(s);
+		int i = string_to_uint(s);
 		if (i < 0 || i >= MAX_QUALS)
 			return -1;
 		qualify_one(i, bitflag, not, -1);
@@ -375,7 +375,7 @@
 	int i;
 
 	if (*s >= '0' && *s <= '9') {
-		int signo = atoi(s);
+		int signo = string_to_uint(s);
 		if (signo < 0 || signo >= MAX_QUALS)
 			return -1;
 		qualify_one(signo, bitflag, not, -1);
@@ -402,7 +402,7 @@
 qual_desc(const char *s, int bitflag, int not)
 {
 	if (*s >= '0' && *s <= '9') {
-		int desc = atoi(s);
+		int desc = string_to_uint(s);
 		if (desc < 0 || desc >= MAX_QUALS)
 			return -1;
 		qualify_one(desc, bitflag, not, -1);
diff --git a/util.c b/util.c
index e57f46a..ea3488d 100644
--- a/util.c
+++ b/util.c
@@ -80,6 +80,21 @@
 #endif
 
 int
+string_to_uint(const char *str)
+{
+	char *error;
+	long value;
+
+	if (!*str)
+		return -1;
+	errno = 0;
+	value = strtol(str, &error, 10);
+	if (errno || *error || value < 0 || (long)(int)value != value)
+		return -1;
+	return (int)value;
+}
+
+int
 tv_nz(struct timeval *a)
 {
 	return a->tv_sec || a->tv_usec;