I am trying to compare options that can be entered on the command line for my program. for option f a user can enter c or b.
int main(int argc, char** argv){
char *i;
char *o;
char *f;
int c;
while ((c = getopt (argc, argv, "i:o:f")) != -1)
switch (c)
{
case 'i':
i = optarg;
break;
case 'o':
o = optarg;
break;
case 'f':
f = optarg;
break;
}
if(strcmp(f, "b") == 0){
//execute code
}
}
When I run this I get the following error:
Program received signal SIGSEGV, Segmentation fault.
__strcmp_avx2 () at ../sysdeps/x86_64/multiarch/strcmp-avx2.S:115
115 ../sysdeps/x86_64/multiarch/strcmp-avx2.S: No such file or directory.
Edit: I'm using Linux and running
gcc -g program.c program
gdb --args ./program -f b
CodePudding user response:
There are two issues here. One, getopt()
needs to know that the f
option takes an argument by adding the colon, like this:
getopt(argc, argv, "i:o:f:")
Second, f
is being passed to strcmp()
with no checking that f
has a valid value. Because getopt()
wasn't expecting an argument for the f
option, optarg
will be NULL
, so strcmp()
is likely the cause of the SIGSEGV
.
It would be a good idea to initialize i
, o
, and f
to NULL
then check their values after calling getopt()
to see if they point to a valid argument string before using them.
CodePudding user response:
- If your program is called with
-f
it will crash asstrcmp()
expects two strings and the first argument isNULL
which is not a string. The is due to a missing guard on the call tostrcmp()
. - If your program requires
-f
to have an argument then theoptstring
should bei:o:f:
(missing the:
afterf
). This meansoptarg
isn'tNULL
when processing thef
option. - If your program is called without
-f
then the variablef
remains uninitialized and the call tostrcmp()
is undefined behavior. It happens to crash withf == NULL
for me. getopt()
returns?
for invalid options, I would say it's bad form to not handle that either explicitly or with a default.- Finally, I suggest using a
for(;;)
to avoid the assignment that is also an expression. It's sufficiently error prune that gcc insist on wrapping the assignment in parenthesis. This minimizes the scope of the variablec
, and it's cleaner to handle all return values fromgetopt()
in the same switch. If you are allergic togoto
use a flag instead.
#define _POSIX_C_SOURCE 2
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char** argv) {
char *f = NULL;
char *i = NULL;
char *o = NULL;
for(;;) {
int c = getopt(argc, argv, "i:o:f:");
switch (c) {
case -1:
goto done;
case '?':
// getopt generates error message
break;
case 'f':
f = optarg;
break;
case 'i':
i = optarg;
break;
case 'o':
o = optarg;
break;
}
}
done:
printf("%sb\n", f && !strcmp(f, "b") ? "" : "not ");
return 0;
}
and here is sample executions:
./a.out
not b
./a.out -f
./a.out: option requires an argument -- 'f'
not b
./a.out -f a
not b
./a.out -f b
b