Hello, we use atoi for user argument processing in same place which return zero for both invalid input and input value zero. In most case its ok because we error out with appropriate error message for input zero but in same place where we accept zero as valued input it case a problem by preceding for invalid input as input value zero. The attached patch change those place to strtol which can handle invalid input
regards Surafel
diff --git a/contrib/pg_standby/pg_standby.c b/contrib/pg_standby/pg_standby.c index 23f706b21d..2bcacbfbb5 100644 --- a/contrib/pg_standby/pg_standby.c +++ b/contrib/pg_standby/pg_standby.c @@ -27,6 +27,7 @@ #include <dirent.h> #include <sys/stat.h> #include <fcntl.h> +#include <limits.h> #include <signal.h> #include <sys/time.h> @@ -638,6 +639,14 @@ sigquit_handler(int sig) int main(int argc, char **argv) { + char *keepfilesendptr; + char *maxretriesendptr; + char *sleeptimeendptr; + char *maxwaittimeendptr; + long numkeepfiles; + long nummaxretries; + long numsleeptime; + long nummaxwaittime; int c; progname = get_progname(argv[0]); @@ -688,12 +697,17 @@ main(int argc, char **argv) debug = true; break; case 'k': /* keepfiles */ - keepfiles = atoi(optarg); - if (keepfiles < 0) + errno = 0; + numkeepfiles = strtol(optarg, &keepfilesendptr, 10); + + if (keepfilesendptr == optarg || *keepfilesendptr != '\0' || + numkeepfiles < 0 || numkeepfiles > INT_MAX || + errno == ERANGE) { - fprintf(stderr, "%s: -k keepfiles must be >= 0\n", progname); + fprintf(stderr, "%s: -k keepfiles must be in range %d..%d\n", progname, 0, INT_MAX); exit(2); } + keepfiles = (int) numkeepfiles; break; case 'l': /* Use link */ @@ -707,31 +721,46 @@ main(int argc, char **argv) #endif break; case 'r': /* Retries */ - maxretries = atoi(optarg); - if (maxretries < 0) + errno = 0; + nummaxretries = strtol(optarg, &maxretriesendptr, 10); + + if (maxretriesendptr == optarg || *maxretriesendptr != '\0' || + nummaxretries < 0 || nummaxretries > INT_MAX || + errno == ERANGE) { - fprintf(stderr, "%s: -r maxretries must be >= 0\n", progname); + fprintf(stderr, "%s: -r maxretries must be in range %d..%d\n", progname, 0, INT_MAX); exit(2); } + maxretries = (int) nummaxretries; break; case 's': /* Sleep time */ - sleeptime = atoi(optarg); - if (sleeptime <= 0 || sleeptime > 60) + errno = 0; + numsleeptime = strtol(optarg, &sleeptimeendptr, 10); + + if (sleeptimeendptr == optarg || *sleeptimeendptr != '\0' || + numsleeptime <= 0 || numsleeptime > 60 || + errno == ERANGE) { - fprintf(stderr, "%s: -s sleeptime incorrectly set\n", progname); + fprintf(stderr, "%s: -s sleeptime must be in range %d..%d\n", progname, 1, 59); exit(2); } + sleeptime = (int) numsleeptime; break; case 't': /* Trigger file */ triggerPath = pg_strdup(optarg); break; case 'w': /* Max wait time */ - maxwaittime = atoi(optarg); - if (maxwaittime < 0) + errno = 0; + nummaxwaittime = strtol(optarg, &maxwaittimeendptr, 10); + + if (maxwaittimeendptr == optarg || *maxwaittimeendptr != '\0' || + nummaxwaittime < 0 || nummaxwaittime > INT_MAX || + errno == ERANGE) { - fprintf(stderr, "%s: -w maxwaittime incorrectly set\n", progname); + fprintf(stderr, "%s: -w maxwaittime must be in range %d..%d\n", progname, 0, INT_MAX); exit(2); } + maxwaittime = (int) nummaxwaittime; break; default: fprintf(stderr, "Try \"%s --help\" for more information.\n", progname); diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c index 63f554307c..16d44c8617 100644 --- a/src/bin/pg_basebackup/pg_basebackup.c +++ b/src/bin/pg_basebackup/pg_basebackup.c @@ -2193,6 +2193,10 @@ main(int argc, char **argv) {"no-verify-checksums", no_argument, NULL, 3}, {NULL, 0, NULL, 0} }; + char *compressEndptr; + char *timeoutEndptr; + long compressNumber; + long timeoutNumber; int c; int option_index; @@ -2305,12 +2309,18 @@ main(int argc, char **argv) #endif break; case 'Z': - compresslevel = atoi(optarg); - if (compresslevel < 0 || compresslevel > 9) + errno = 0; + compressNumber = strtol(optarg, &compressEndptr, 10); + + if (compressEndptr == optarg || *compressEndptr != '\0' || + compressNumber < 0 || compressNumber > 9 || + errno == ERANGE) { - pg_log_error("invalid compression level \"%s\"\n", optarg); + pg_log_error("compression level must be in range %d..%d \"%s\"\n", + 0, 9, optarg); exit(1); } + compresslevel = (int) compressNumber; break; case 'c': if (pg_strcasecmp(optarg, "fast") == 0) @@ -2343,12 +2353,18 @@ main(int argc, char **argv) dbgetpassword = 1; break; case 's': - standby_message_timeout = atoi(optarg) * 1000; - if (standby_message_timeout < 0) + errno = 0; + timeoutNumber = strtol(optarg, &timeoutEndptr, 10); + + if (timeoutEndptr == optarg || *timeoutEndptr != '\0' || + timeoutNumber < 0 || timeoutNumber > INT_MAX || + errno == ERANGE) { - pg_log_error("invalid status interval \"%s\"", optarg); + pg_log_error("status interval must be in range %d..%d \"%s\"\n", + 0, INT_MAX, optarg); exit(1); } + standby_message_timeout = (int) timeoutNumber * 1000; break; case 'v': verbose++; diff --git a/src/bin/pg_basebackup/pg_receivewal.c b/src/bin/pg_basebackup/pg_receivewal.c index f39c1339d7..9b27621419 100644 --- a/src/bin/pg_basebackup/pg_receivewal.c +++ b/src/bin/pg_basebackup/pg_receivewal.c @@ -15,6 +15,7 @@ #include "postgres_fe.h" #include <dirent.h> +#include <limits.h> #include <signal.h> #include <sys/stat.h> #include <unistd.h> @@ -492,10 +493,15 @@ main(int argc, char **argv) {"no-sync", no_argument, NULL, 5}, {NULL, 0, NULL, 0} }; - + long compressNumber; + long timeoutNumber; + long portNumber; int c; int option_index; + char *compressEndptr; char *db_name; + char *timeoutEndptr; + char *portEndptr; uint32 hi, lo; @@ -533,9 +539,15 @@ main(int argc, char **argv) dbhost = pg_strdup(optarg); break; case 'p': - if (atoi(optarg) <= 0) + errno = 0; + portNumber = strtol(optarg, &portEndptr, 10); + + if (portEndptr == optarg || *portEndptr != '\0' || + portNumber <= 0 || portNumber > INT_MAX || + errno == ERANGE) { - pg_log_error("invalid port number \"%s\"", optarg); + pg_log_error("port number must be in range %d..%d \"%s\"\n", + 1, INT_MAX, optarg); exit(1); } dbport = pg_strdup(optarg); @@ -550,12 +562,18 @@ main(int argc, char **argv) dbgetpassword = 1; break; case 's': - standby_message_timeout = atoi(optarg) * 1000; - if (standby_message_timeout < 0) + errno = 0; + timeoutNumber = strtol(optarg, &timeoutEndptr, 10); + + if (timeoutEndptr == optarg || *timeoutEndptr != '\0' || + timeoutNumber < 0 || timeoutNumber > INT_MAX || + errno == ERANGE) { - pg_log_error("invalid status interval \"%s\"", optarg); + pg_log_error("status interval must be in range %d..%d \"%s\"\n", + 0, INT_MAX, optarg); exit(1); } + standby_message_timeout = (int) timeoutNumber * 1000; break; case 'S': replication_slot = pg_strdup(optarg); @@ -575,12 +593,18 @@ main(int argc, char **argv) verbose++; break; case 'Z': - compresslevel = atoi(optarg); - if (compresslevel < 0 || compresslevel > 9) + errno = 0; + compressNumber = strtol(optarg, &compressEndptr, 10); + + if (compressEndptr == optarg || *compressEndptr != '\0' || + compressNumber < 0 || compressNumber > 9 || + errno == ERANGE) { - pg_log_error("invalid compression level \"%s\"", optarg); + pg_log_error("compression level must be in range %d..%d \"%s\"\n", + 0, 9, optarg); exit(1); } + compresslevel = (int) compressNumber; break; /* action */ case 1: diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index dfb6c19f5a..396ca32dc2 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -12,6 +12,7 @@ #include "postgres_fe.h" #include <fcntl.h> +#include <limits.h> #include <signal.h> #include <time.h> #include <sys/stat.h> @@ -2266,6 +2267,8 @@ main(int argc, char **argv) }; char *env_wait; + char *seconds_endptr; + long seconds; int option_index; int c; pgpid_t killproc = 0; @@ -2395,7 +2398,18 @@ main(int argc, char **argv) #endif break; case 't': - wait_seconds = atoi(optarg); + errno = 0; + seconds = strtol(optarg, &seconds_endptr, 10); + + if (seconds_endptr == optarg || *seconds_endptr != '\0' || + seconds <= 0 || seconds > INT_MAX || + errno == ERANGE) + { + write_stderr(_("timeout must be in range %d..%d\n"), + 1, INT_MAX); + exit(1); + } + wait_seconds = (int) seconds; wait_seconds_arg = true; break; case 'U': diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 8909a45d61..b7858b48d2 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -311,14 +311,20 @@ main(int argc, char **argv) DumpableObject *boundaryObjs; int i; int optindex; + char *compressEndptr; + char *digitsEndptr; char *endptr; + char *workersEndptr; RestoreOptions *ropt; Archive *fout; /* the script file */ bool g_verbose = false; const char *dumpencoding = NULL; const char *dumpsnapshot = NULL; char *use_role = NULL; + long compressNumber; + long floatDigits; long rowsPerInsert; + long workersNumber; int numWorkers = 1; trivalue prompt_password = TRI_DEFAULT; int compressLevel = -1; @@ -473,7 +479,18 @@ main(int argc, char **argv) break; case 'j': /* number of dump jobs */ - numWorkers = atoi(optarg); + errno = 0; + workersNumber = strtol(optarg, &workersEndptr, 10); + + if (workersEndptr == optarg || *workersEndptr != '\0' || + workersNumber <= 0 || workersNumber > INT_MAX || + errno == ERANGE) + { + pg_log_error("jobs must be in range %d..%d", + 1, INT_MAX); + exit_nicely(1); + } + numWorkers = (int) workersNumber; break; case 'n': /* include schema(s) */ @@ -536,12 +553,17 @@ main(int argc, char **argv) break; case 'Z': /* Compression Level */ - compressLevel = atoi(optarg); - if (compressLevel < 0 || compressLevel > 9) + errno = 0; + compressNumber = strtol(optarg, &compressEndptr, 10); + + if (compressEndptr == optarg || *compressEndptr != '\0' || + compressNumber < 0 || compressNumber > 9 || + errno == ERANGE) { pg_log_error("compression level must be in range 0..9"); exit_nicely(1); } + compressLevel = (int) compressNumber; break; case 0: @@ -573,13 +595,18 @@ main(int argc, char **argv) break; case 8: - have_extra_float_digits = true; - extra_float_digits = atoi(optarg); - if (extra_float_digits < -15 || extra_float_digits > 3) + errno = 0; + floatDigits = strtol(optarg, &digitsEndptr, 10); + + if (digitsEndptr == optarg || *digitsEndptr != '\0' || + floatDigits < -15 || floatDigits > 3 || + errno == ERANGE) { pg_log_error("extra_float_digits must be in range -15..3"); exit_nicely(1); } + have_extra_float_digits = true; + extra_float_digits = (int) floatDigits; break; case 9: /* inserts */ diff --git a/src/bin/pg_dump/pg_restore.c b/src/bin/pg_dump/pg_restore.c index f9b1ae6809..018f120e1e 100644 --- a/src/bin/pg_dump/pg_restore.c +++ b/src/bin/pg_dump/pg_restore.c @@ -60,9 +60,11 @@ int main(int argc, char **argv) { RestoreOptions *opts; + long workersNumber; int c; int exit_code; int numWorkers = 1; + char *workersEndptr; Archive *AH; char *inputFileSpec; static int disable_triggers = 0; @@ -185,7 +187,18 @@ main(int argc, char **argv) break; case 'j': /* number of restore jobs */ - numWorkers = atoi(optarg); + errno = 0; + workersNumber = strtol(optarg, &workersEndptr, 10); + + if (workersEndptr == optarg || *workersEndptr != '\0' || + workersNumber <= 0 || workersNumber > INT_MAX || + errno == ERANGE) + { + pg_log_error("jobs must be in range %d..%d", + 1, INT_MAX); + exit_nicely(1); + } + numWorkers = (int) workersNumber; break; case 'l': /* Dump the TOC summary */ diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c index 73f395f2a3..67075dc482 100644 --- a/src/bin/pg_upgrade/option.c +++ b/src/bin/pg_upgrade/option.c @@ -9,6 +9,7 @@ #include "postgres_fe.h" +#include <limits.h> #include <time.h> #ifdef WIN32 #include <io.h> @@ -59,11 +60,17 @@ parseCommandLine(int argc, char *argv[]) {NULL, 0, NULL, 0} }; + long workersNumber; + long newPortNumber; + long oldNumber; int option; /* Command line option */ int optindex = 0; /* used by getopt_long */ int os_user_effective_id; FILE *fp; char **filename; + char *newPortEndptr; + char *oldPortEndptr; + char *workersEndptr; time_t run_time = time(NULL); user_opts.transfer_mode = TRANSFER_MODE_COPY; @@ -127,7 +134,18 @@ parseCommandLine(int argc, char *argv[]) break; case 'j': - user_opts.jobs = atoi(optarg); + errno = 0; + workersNumber = strtol(optarg, &workersEndptr, 10); + + if (workersEndptr == optarg || *workersEndptr != '\0' || + workersNumber <= 0 || workersNumber > INT_MAX || + errno == ERANGE) + { + pg_fatal("jobs must be in range %d..%d", + 0, INT_MAX); + exit(1); + } + user_opts.jobs = (int) workersNumber; break; case 'k': @@ -166,19 +184,31 @@ parseCommandLine(int argc, char *argv[]) * supported on all old/new versions (added in PG 9.2). */ case 'p': - if ((old_cluster.port = atoi(optarg)) <= 0) + errno = 0; + oldNumber = strtol(optarg, &oldPortEndptr, 10); + + if (oldPortEndptr == optarg || *oldPortEndptr != '\0' || + oldNumber <= 0 || oldNumber > INT_MAX || + errno == ERANGE) { pg_fatal("invalid old port number\n"); exit(1); } + old_cluster.port = (int) oldNumber; break; case 'P': - if ((new_cluster.port = atoi(optarg)) <= 0) + errno = 0; + newPortNumber = strtol(optarg, &newPortEndptr, 10); + + if (newPortEndptr == optarg || *newPortEndptr != '\0' || + newPortNumber <= 0 || newPortNumber > INT_MAX || + errno == ERANGE) { pg_fatal("invalid new port number\n"); exit(1); } + new_cluster.port = (int) newPortNumber; break; case 'r':