From: Chen-Tse Tsai <ctse.tsai@gmail.com>
Date: Wed, 18 May 2016 09:53:12 -0500
Subject: Improve option parsing

Detect errors when parsing numeric arguments, check for the right number of
arguments, and use optarg(3) if possible.

Bug-Debian: http://bugs.debian.org/716362, 716363
Forwarded: yes

--- a/svm-predict.c
+++ b/svm-predict.c
@@ -3,7 +3,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <math.h>
+#include <limits.h>
 #include "svm.h"
+#define INF HUGE_VAL
 
 int print_null(const char *s,...) {return 0;}
 
@@ -167,6 +170,20 @@
 	exit(1);
 }
 
+static long strtol_or_exit(const char *str) {
+	errno = 0;
+	char *endptr;
+	long val = strtol(str, &endptr, 10);
+
+	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) {
+		perror("error converting %s to int:");
+		exit_with_help();
+	} else if (*endptr != '\0') {
+		exit_with_help();
+	}
+	return val;
+}
+
 int main(int argc, char **argv)
 {
 	FILE *input, *output;
@@ -179,7 +196,7 @@
 		switch(argv[i-1][1])
 		{
 			case 'b':
-				predict_probability = atoi(argv[i]);
+				predict_probability = strtol_or_exit(argv[i]);
 				break;
 			case 'q':
 				info = &print_null;
--- a/svm-scale.c
+++ b/svm-scale.c
@@ -3,6 +3,10 @@
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
+#include <math.h>
+#include <limits.h>
+#include <errno.h>
+#define INF HUGE_VAL
 
 void exit_with_help()
 {
@@ -18,6 +22,20 @@
 	exit(1);
 }
 
+static float strtof_or_exit(const char *str) {
+	errno = 0;
+	char *endptr;
+	float val = strtof(str, &endptr);
+
+	if ((errno == ERANGE && (val == HUGE_VALF || val == HUGE_VALL)) || (errno != 0 && val == 0.0)) {
+		perror("error converting %s to float:");
+		exit_with_help();
+	} else if (*endptr != '\0') {
+		exit_with_help();
+	}
+	return val;
+}
+
 char *line = NULL;
 int max_line_len = 1024;
 double lower=-1.0,upper=1.0,y_lower,y_upper;
@@ -52,12 +70,12 @@
 		++i;
 		switch(argv[i-1][1])
 		{
-			case 'l': lower = atof(argv[i]); break;
-			case 'u': upper = atof(argv[i]); break;
+			case 'l': lower = strtof_or_exit(argv[i]); break;
+			case 'u': upper = strtof_or_exit(argv[i]); break;
 			case 'y':
-				y_lower = atof(argv[i]);
+				y_lower = strtof_or_exit(argv[i]);
 				++i;
-				y_upper = atof(argv[i]);
+				y_upper = strtof_or_exit(argv[i]);
 				y_scaling = 1;
 				break;
 			case 's': save_filename = argv[i]; break;
--- a/svm-train.c
+++ b/svm-train.c
@@ -3,8 +3,11 @@
 #include <string.h>
 #include <ctype.h>
 #include <errno.h>
+#include <limits.h>
 #include "svm.h"
+#include <math.h>
 #define Malloc(type,n) (type *)malloc((n)*sizeof(type))
+#define INF HUGE_VAL
 
 void print_null(const char *s) {}
 
@@ -48,6 +51,34 @@
 	exit(1);
 }
 
+static long strtol_or_exit(const char *str) {
+	errno = 0;
+	char *endptr;
+	long val = strtol(str, &endptr, 10);
+
+	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN)) || (errno != 0 && val == 0)) {
+		perror("error converting %s to int:");
+		exit_with_help();
+	} else if (*endptr != '\0') {
+		exit_with_help();
+	}
+	return val;
+}
+
+static float strtof_or_exit(const char *str) {
+	errno = 0;
+	char *endptr;
+	float val = strtof(str, &endptr);
+
+	if ((errno == ERANGE && (val == HUGE_VALF || val == HUGE_VALL)) || (errno != 0 && val == 0.0)) {
+		perror("error converting %s to float:");
+		exit_with_help();
+	} else if (*endptr != '\0') {
+		exit_with_help();
+	}
+	return val;
+}
+
 void parse_command_line(int argc, char **argv, char *input_file_name, char *model_file_name);
 void read_problem(const char *filename);
 void do_cross_validation();
@@ -190,40 +221,40 @@
 		switch(argv[i-1][1])
 		{
 			case 's':
-				param.svm_type = atoi(argv[i]);
+				param.svm_type = strtol_or_exit(argv[i]);
 				break;
 			case 't':
-				param.kernel_type = atoi(argv[i]);
+				param.kernel_type = strtol_or_exit(argv[i]);
 				break;
 			case 'd':
-				param.degree = atoi(argv[i]);
+				param.degree = strtol_or_exit(argv[i]);
 				break;
 			case 'g':
-				param.gamma = atof(argv[i]);
+				param.gamma = strtof_or_exit(argv[i]);
 				break;
 			case 'r':
-				param.coef0 = atof(argv[i]);
+				param.coef0 = strtof_or_exit(argv[i]);
 				break;
 			case 'n':
-				param.nu = atof(argv[i]);
+				param.nu = strtof_or_exit(argv[i]);
 				break;
 			case 'm':
-				param.cache_size = atof(argv[i]);
+				param.cache_size = strtof_or_exit(argv[i]);
 				break;
 			case 'c':
-				param.C = atof(argv[i]);
+				param.C = strtof_or_exit(argv[i]);
 				break;
 			case 'e':
-				param.eps = atof(argv[i]);
+				param.eps = strtof_or_exit(argv[i]);
 				break;
 			case 'p':
-				param.p = atof(argv[i]);
+				param.p = strtof_or_exit(argv[i]);
 				break;
 			case 'h':
-				param.shrinking = atoi(argv[i]);
+				param.shrinking = strtol_or_exit(argv[i]);
 				break;
 			case 'b':
-				param.probability = atoi(argv[i]);
+				param.probability = strtol_or_exit(argv[i]);
 				break;
 			case 'q':
 				print_func = &print_null;
@@ -231,7 +262,7 @@
 				break;
 			case 'v':
 				cross_validation = 1;
-				nr_fold = atoi(argv[i]);
+				nr_fold = strtol_or_exit(argv[i]);
 				if(nr_fold < 2)
 				{
 					fprintf(stderr,"n-fold cross validation: n must >= 2\n");
@@ -242,8 +273,8 @@
 				++param.nr_weight;
 				param.weight_label = (int *)realloc(param.weight_label,sizeof(int)*param.nr_weight);
 				param.weight = (double *)realloc(param.weight,sizeof(double)*param.nr_weight);
-				param.weight_label[param.nr_weight-1] = atoi(&argv[i-1][2]);
-				param.weight[param.nr_weight-1] = atof(argv[i]);
+				param.weight_label[param.nr_weight-1] = strtol_or_exit(&argv[i-1][2]);
+				param.weight[param.nr_weight-1] = strtof_or_exit(argv[i]);
 				break;
 			default:
 				fprintf(stderr,"Unknown option: -%c\n", argv[i-1][1]);
