postgres.git / summary / log / commit / refs

commit    61aa17b92eab017d64419c19fa466d72a509d016
Author:   Nathan Bossart <nathan@postgresql.org>
Date:     Fri Sep 11 19:37:51 2026 +0000

    Fix optional-argument handling in in-tree getopt_long().
    
    If a long option that accepts an optional argument is given without
    one, optind is advanced twice, and the following argument is
    skipped.  For example, "pg_waldump --stats --limit 5" skips --limit
    and interprets "5" as a non-option, so the command complains that
    it cannot location WAL file "5".  The same path also returns BADARG
    when optstring starts with a colon, even though nothing is missing.
    To fix, handle optional arguments before the missing-argument code,
    which then only needs to deal with required arguments.
    
    This is a bug fix and could be back-patched, but since this issue
    went unnoticed for 23 years, I'm not going to bother.
    
    Author: Sehrope Sarkuni <sehrope@jackdb.com>
    Reviewed-by: solai v <solai.cdac@gmail.com>
    Discussion: https://postgr.es/m/CAH7T-arxDuVCSkorO%3Dk7%2BM-_JV0JFzMpN_EtKMyD2K0RDqZ2OA%40mail.gmail.com


src/bin/pg_waldump/t/001_basic.pl | 3 +-- src/port/getopt_long.c | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/bin/pg_waldump/t/001_basic.pl b/src/bin/pg_waldump/t/001_basic.pl index 8beac19eaff..7b33efc6299 100644 --- a/src/bin/pg_waldump/t/001_basic.pl +++ b/src/bin/pg_waldump/t/001_basic.pl @@ -340,11 +340,10 @@ sub test_pg_waldump my ($stdout, $stderr); my $result = IPC::Run::run [ - 'pg_waldump', + 'pg_waldump', @opts, '--start' => $startlsn, '--end' => $endlsn, '--path' => $path, - @opts ], '>' => \$stdout, '2>' => \$stderr; diff --git a/src/port/getopt_long.c b/src/port/getopt_long.c index 2e869fed58b..0a9a50189f1 100644 --- a/src/port/getopt_long.c +++ b/src/port/getopt_long.c @@ -137,8 +137,9 @@ retry: { if (place[namelen] == '=') optarg = place + namelen + 1; - else if (optind < argc - 1 && - has_arg == required_argument) + else if (has_arg == optional_argument) + optarg = NULL; + else if (optind < argc - 1) { optind++; optarg = argv[optind]; @@ -152,16 +153,14 @@ retry: return BADARG; } - if (opterr && has_arg == required_argument) + if (opterr) fprintf(stderr, "%s: option requires an argument -- %s\n", argv[0], place); place = EMSG; - if (has_arg == required_argument) - return BADCH; - optarg = NULL; + return BADCH; } } else