GNU getopt not populating optarg

846 views Asked by At

I'm trying to use the GNU getopt function parse some command line arguments in my C program. Say I make the following call:

./my_program -E 16 -t path/to/file

My current expectation is that if I have the following code:

long arg;
int e_val;
char *t_str;
while ((arg = getopt(argc, argv, "E:t:")) != -1) {
    switch(arg) {
        case 'E':
            e_val = *optarg; // e_val = 16
            break;
        case 't':
            t_str = optarg;
            break;
    }
}

then e_val will equal 16 and t_str will point to path/to/file. However, I can't seem to figure out how to access the actual value for these arguments. By the time I get to assigning e_val in case 'E', optarg is still a null pointer:

Starting program: /stack/overflow/example -E 16 -t stackoverflow
Breakpoint 1, get_arguments (argc=5, argv=0x7fffffffe318) at stack_overflow.c:233
233       while ((arg = getopt(argc, argv, "E:t:")) != -1)
(gdb) n
235         switch (arg)
(gdb)
254             e_val = *optarg;
(gdb) p optarg
$6 = 0x0
(gdb) x/1xw optarg
0x0:    Cannot access memory at address 0x0
(gdb) p /x arg
$7 = 0x45 // ASCII for 'E'

Why is optarg not getting set? And if optarg isn't the value I'm supposed to be using to get the 16 following E, then what should I be using?

As a final note, I briefly stepped through getopt with gdb and it looks like it isn't setting the extern optarg variable for some reason.

Backtrace:

#0  _getopt_internal (argc=<value optimized out>, argv=<value optimized out>, optstring=<value optimized out>,
    longopts=<value optimized out>, longind=<value optimized out>, long_only=<value optimized out>, posixly_correct=0)
    at getopt.c:1135
#1  0x00007ffff7894138 in getopt (argc=<value optimized out>, argv=<value optimized out>, optstring=<value optimized out>)
    at getopt.c:1145
#2  0x0000000000400cd6 in get_arguments (argc=5, argv=0x7fffffffe318) at stackoverflow.c:233
#3  0x0000000000400875 in main (argc=5, argv=0x7fffffffe318) at stackoverflow.c:82

Code being executed:

(gdb) l
1130
1131      result = _getopt_internal_r (argc, argv, optstring, longopts,
1132                                   longind, long_only, &getopt_data,
1133                                   posixly_correct);
1134
1135      optind = getopt_data.optind;
1136      optarg = getopt_data.optarg;
1137      optopt = getopt_data.optopt;
1138
1139      return result;

optarg not getting set:

(gdb) n
1136      optarg = getopt_data.optarg;
(gdb)
1135      optind = getopt_data.optind;
(gdb) p optarg
$10 = 0x0
(gdb) p getopt_data.optarg
$11 = 0x7fffffffe60d "16"

Note that optarg not being set here is not due to compiler optimization. I can step all the way through back to my function and it stays null.

1

There are 1 answers

1
Jonathan Leffler On BEST ANSWER

This isn't truly an answer, but it is too big to be a comment.

This code compiles cleanly under stringent compilation options:

#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    long arg;
    int e_val = -1;
    char *t_str = "pygmalion";
    while ((arg = getopt(argc, argv, "E:t:")) != -1)
    {
        switch (arg)
        {
        case 'E':
            e_val = atoi(optarg); // e_val = 16
            break;
        case 't':
            t_str = optarg;
            break;
        }
    }

    printf("e_val = %d\n", e_val);
    printf("t_str = %s\n", t_str);
    return 0;
}

Compile and run:

$ gcc -g -O3 -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Wold-style-declaration -Werror go.c -o go
$ ./go -E 16 -t path/to/file
e_val = 16
t_str = path/to/file
$ ./go -E 16 
e_val = 16
t_str = pygmalion
$ ./go -t pygmalion
e_val = -1
t_str = pygmalion
$ ./go 
e_val = -1
t_str = pygmalion
$

Testing on an Ubuntu 14.04 LTS derivative with GCC 5.1.0. So, on the face of it, the code is approximately correct. That in turn suggests that the problem is in the surrounding code. Is there any chance that something you're linking with is also defining optarg?

What do you get if you take the code I've just shown and run it? If it works but your much bigger program doesn't, then there's something in your bigger program that is causing the trouble, somehow.