Giter Club home page Giter Club logo

optparse's Issues

Segmentation fault

Hello, while writing tests for a program that uses optparse, I stumbled on this segfault situation. I tried to summarize/reproduce it in this little program that crashes as soon as it is executed.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define OPTPARSE_IMPLEMENTATION
#define OPTPARSE_API static
#include "optparse.h"

int fake_main(int argc, char **argv)
{
    struct optparse_long longopts[] = {
        {"amend", 'a', OPTPARSE_NONE},
        {"brief", 'b', OPTPARSE_NONE},
        {"color", 'c', OPTPARSE_REQUIRED},
        {"delay", 'd', OPTPARSE_OPTIONAL},
        {0}
    };

    bool amend = false;
    bool brief = false;
    const char *color = "white";
    int delay = 0;

    char *arg;
    int option;
    struct optparse options;

    optparse_init(&options, argv);
    while ((option = optparse_long(&options, longopts, NULL)) != -1) {
        switch (option) {
        case 'a':
            amend = true;
            break;
        case 'b':
            brief = true;
            break;
        case 'c':
            color = options.optarg;
            break;
        case 'd':
            delay = options.optarg ? atoi(options.optarg) : 1;
            break;
        case '?':
            fprintf(stderr, "%s: %s\n", argv[0], options.errmsg);
            exit(EXIT_FAILURE);
        }
    }

    printf("chosen color %s and delay %d\n", color, delay);

    /* Print remaining arguments. */
    while ((arg = optparse_arg(&options)))
        printf("%s\n", arg);

    return 0;
}

int main(int argc, char *argv[])
{
    fake_main(4, (char *[]){"fakeprg", "--color", "red", "-d", "4"});
    return 0;
}

When run, this program segfaults. Using gdb, I can track this back to optparse_is_dashdash(const char *arg). I don't actually understand 100% of optparse's code, but I thought that the line:

return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';

may indeed segfault if arg is not that long, or am I just missing or forgetting something with the code above ?

non-character shortname breaks optparse_from_long

If someone wants to have a longopt without a corresponding shortopt, it can be simpler to use values above 255 (maximum unsigned char), instead of using longindex. e.g.

struct optparse_long long_options[] = {
    { "opt1", 256, OPTPARSE_NONE },
    { "opt2", 'o', OPTPARSE_NONE }

However, in optparse_from_long(), it is only checked that shortname exists, not that it is a valid character, so regardless of validity it is added to the shortopt string, which causes shortopts used after the invalid character (like using -o for the example above) to be considered invalid.
I think the solution here would be to make sure that shortname doesn't just exist, but falls within a valid range (probably below 128).

Subcommands?

Various bits of the documentation mention how this can be used to handle subcommands and options.

Are there any examples of this? I'm not sure how to approach such a usage.

Credit

I'm glad this library exists, and I'm about to use it in a project.

I wonder if you'd be alright with adding your name, or a link to this Github repo somewhere in the credit file? In case someone ever asks me where a piece of code is from, it's nice to be able to point back to its author.

problematic recursion in optparse() and optparse_long()

The use of recursion in these functions (particularly in the way it is used, which prevents tail-call optimization), leads to increasing stack usage for every non-option argument, and eventually stack overflow. The recursion should probably be removed to avoid this (setting a variable within the functions to indicate that the function has restarted, along with a goto to the beginning and some other refactoring, might be a solution).

optparse_long skips argv null --> optind off by one --> overflow

While playing around with optparse I found an potential bug.

Problem
Using optparse_long and after that optparse_arg in a while-loop with arguments ./a.out --colorprints all char **envp values, thus overflows.
(If the system supports envp of course)
If first copying char **argv it segfaults of course.

Possible Solution

diff --git a/optparse.h b/optparse.h
index bf61fad..9d534d8 100644
--- a/optparse.h
+++ b/optparse.h
@@ -387,9 +387,11 @@ optparse_long(struct optparse *options,
             } if (arg != 0) {
                 options->optarg = arg;
             } else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
-                options->optarg = options->argv[options->optind++];
+                options->optarg = options->argv[options->optind];
                 if (options->optarg == 0)
                     return optparse_error(options, OPTPARSE_MSG_MISSING, name);
+               else
+                   options->optind++;
             }
             return options->optopt;
         }

Example
Nearly completely taken from the README.md

#define OPTPARSE_IMPLEMENTATION
#define OPTPARSE_API static
#include "optparse.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void try_optparse_long(char **argv)
{
    char *arg;
    int opt, longindex;
    struct optparse options;
    struct optparse_long longopts[] = {
        {"amend", 'a', OPTPARSE_NONE},
        {"brief", 'b', OPTPARSE_NONE},
        {"color", 'c', OPTPARSE_REQUIRED},
        {"delay", 'd', OPTPARSE_REQUIRED},
        {0, 0, 0}
    };

    optparse_init(&options, argv);
    while ((opt = optparse_long(&options, longopts, &longindex)) != -1) {
        if (opt == '?')
            printf("%s: %s\n", argv[0], options.errmsg);
        printf("%c (%d, %d) = '%s'\n",
               opt, options.optind, longindex, options.optarg);
    }
    printf("optind = %d\n", options.optind);
    while ((arg = optparse_arg(&options)))
       printf("argument: %s\n", arg);
}

int main(int argc, char **argv)
{
    size_t size = (argc + 1) * sizeof(*argv);
    char **argv_copy = malloc(size);

    memcpy(argv_copy, argv, size);

    try_optparse_long(argv);
    try_optparse_long(argv_copy);
    return 0;
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.