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
-fit will crash asstrcmp()expects two strings and the first argument isNULLwhich is not a string. The is due to a missing guard on the call tostrcmp(). - If your program requires
-fto have an argument then theoptstringshould bei:o:f:(missing the:afterf). This meansoptargisn'tNULLwhen processing thefoption. - If your program is called without
-fthen the variablefremains uninitialized and the call tostrcmp()is undefined behavior. It happens to crash withf == NULLfor 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 togotouse 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
