skeeto / optparse Goto Github PK
View Code? Open in Web Editor NEWPortable, reentrant, getopt-like option parser
License: The Unlicense
Portable, reentrant, getopt-like option parser
License: The Unlicense
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 ?
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).
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.
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.
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).
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 --color
prints 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;
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.