csegmentation-faultpopt

Why does popt segfault when a string is too short?


Why would popt be segfaulting when the argDescrip string isn't long enough?

Take the following example:

#include <popt.h>

struct poptOption options[] = {
  POPT_AUTOHELP
  {
    .longName = "color",
    .shortName = '\0',
    .argInfo = POPT_ARG_STRING
               | POPT_ARGFLAG_OPTIONAL
               | POPT_ARGFLAG_SHOW_DEFAULT,
    .arg = (void*) "auto",
    .val = 1,
    .descrip = "Whether or not to use colored output",
    .argDescrip = "always|never|auto (checks if TTY)"
  },
  POPT_TABLEEND
};


int main(int argc, const char** argv) {
  // get popt context
  poptContext ctx = poptGetContext(
      "program",
      argc, argv,
      options,
      POPT_CONTEXT_POSIXMEHARDER);

  // parse
  poptGetNextOpt(ctx);

  return 0;
}

The above segfaults:

/tmp$ ./a.out --help
Usage: a.out [OPTION...]
[1]    47468 segmentation fault  ./a.out --help

Although changing .argDescrip to

.argDescrip = "always|never|auto (checks if TTY) "
              "........................................."

popt happily accepts it and displays the output:

/tmp$ ./a.out --help
Usage: a.out [OPTION...]
      --color[=always|never|auto (checks if TTY) .........................................]     Whether or not to use colored output

Help options:
  -?, --help                                                                                

Show this help message
    --usage
Display brief usage message

What gives? Am I missing something in the C spec? The popt man pages don't specify a required length. Is this a bug?


Solution

  • Your problem is something else. You have set the arg member to a constant string while you would have needed to set it to a pointer to such (the man page says, arg should be initialized with a pointer to char *). Your program dies while trying to dereference a pointer that isn't one.

    Try like this:

    char *garg = "auto";
    
    struct poptOption options[] = {
        POPT_AUTOHELP
        {
            .longName = "color",
            .shortName = '\0',
            .argInfo = POPT_ARG_STRING
                    | POPT_ARGFLAG_OPTIONAL
                    | POPT_ARGFLAG_SHOW_DEFAULT,
            .arg = &garg, 
            .val = 1,
            .descrip = "Whether or not to use colored output",
            .argDescrip = "always|never|auto (checks if TTY)"
        },
        POPT_TABLEEND
    };