1
0
mirror of https://git.code.sf.net/p/zint/code synced 2025-12-21 20:07:06 +00:00

frontend: workaround musl getopt_long_only() bug,

see - https://www.openwall.com/lists/musl/2025/12/19/1
This commit is contained in:
gitlost
2025-12-19 17:40:08 +00:00
parent 0ce46686b8
commit fe02f2dd17
2 changed files with 77 additions and 15 deletions

View File

@@ -2114,7 +2114,10 @@ int main(int argc, char **argv) {
cpy_str(my_symbol->bgcolour, ARRAY_SIZE(my_symbol->bgcolour), "000000"); cpy_str(my_symbol->bgcolour, ARRAY_SIZE(my_symbol->bgcolour), "000000");
break; break;
case '?': case '?': {
/* Workaround musl `optind` bug - see https://www.openwall.com/lists/musl/2025/12/19/1 */
const int idx = optind <= argc ? optind - 1 : argc - 1;
const char *const arg = argv[idx] ? argv[idx] : "?";
if (optopt) { if (optopt) {
for (i = 0; i < ARRAY_SIZE(long_options) && long_options[i].val != optopt; i++); for (i = 0; i < ARRAY_SIZE(long_options) && long_options[i].val != optopt; i++);
if (i == ARRAY_SIZE(long_options)) { /* Shouldn't happen */ if (i == ARRAY_SIZE(long_options)) { /* Shouldn't happen */
@@ -2122,15 +2125,15 @@ int main(int argc, char **argv) {
return do_exit(ZINT_ERROR_ENCODING_PROBLEM); return do_exit(ZINT_ERROR_ENCODING_PROBLEM);
} }
if (long_options[i].has_arg) { if (long_options[i].has_arg) {
fprintf(stderr, "Error 109: option '%s' requires an argument\n", argv[optind - 1]); fprintf(stderr, "Error 109: option '%s' requires an argument\n", arg);
} else { } else {
const char *eqs = strchr(argv[optind - 1], '='); const char *const eqs = strchr(arg, '=');
const int optlen = eqs ? (int) (eqs - argv[optind - 1]) : (int) strlen(argv[optind - 1]); const int optlen = eqs ? (int) (eqs - arg) : (int) strlen(arg);
fprintf(stderr, "Error 126: option '%.*s' does not take an argument\n", optlen, fprintf(stderr, "Error 126: option '%.*s' does not take an argument\n", optlen, arg);
argv[optind - 1]);
} }
} else { } else {
fprintf(stderr, "Error 101: unknown option '%s'\n", argv[optind - 1]); fprintf(stderr, "Error 101: unknown option '%s'\n", arg);
}
} }
return do_exit(ZINT_ERROR_INVALID_OPTION); return do_exit(ZINT_ERROR_INVALID_OPTION);
break; break;

View File

@@ -1390,6 +1390,64 @@ static void test_exit_status(const testCtx *const p_ctx) {
testFinish(); testFinish();
} }
static void test_bad_args(const testCtx *const p_ctx) {
int debug = p_ctx->debug;
struct item {
int b;
const char *data;
int input_mode;
const char *opt;
const char *opt_data;
const char *expected;
};
/* s/\/\*[ 0-9]*\*\//\=printf("\/\*%3d*\/", line(".") - line("'<")): */
struct item data[] = {
/* 0*/ { BARCODE_CODE128, NULL, -1, NULL, NULL, "Error 109: option '-d' requires an argument" },
/* 1*/ { BARCODE_CODE128, "1", -1, " -o", NULL, "Error 109: option '-o' requires an argument" },
/* 2*/ { BARCODE_CODE128, "1", -1, " --fast=", "1", "Error 126: option '--fast' does not take an argument" },
};
int data_size = ARRAY_SIZE(data);
int i;
int exit_status;
char cmd[4096];
char buf[8192];
testStart("test_bad_args");
for (i = 0; i < data_size; i++) {
if (testContinue(p_ctx, i)) continue;
strcpy(cmd, "zint");
*buf = '\0';
arg_int(cmd, "-b ", data[i].b);
arg_input_mode(cmd, data[i].input_mode);
if (data[i].data) {
arg_data(cmd, "-d ", data[i].data);
} else {
strcat(cmd, " -d");
}
if (data[i].opt) {
if (data[i].opt_data != NULL) {
arg_data(cmd, data[i].opt, data[i].opt_data);
} else {
strcat(cmd, data[i].opt);
}
}
strcat(cmd, " 2>&1");
assert_nonnull(exec(cmd, buf, sizeof(buf) - 1, debug, i, &exit_status), "i:%d exec(%s) NULL\n", i, cmd);
assert_zero(strcmp(buf, data[i].expected), "i:%d buf (%s) != expected (%s) (%s)\n", i, buf, data[i].expected, cmd);
}
testFinish();
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
testFunction funcs[] = { /* name, func */ testFunction funcs[] = { /* name, func */
@@ -1404,6 +1462,7 @@ int main(int argc, char *argv[]) {
{ "test_other_opts", test_other_opts }, { "test_other_opts", test_other_opts },
{ "test_combos", test_combos }, { "test_combos", test_combos },
{ "test_exit_status", test_exit_status }, { "test_exit_status", test_exit_status },
{ "test_bad_args", test_bad_args },
}; };
testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); testRun(argc, argv, funcs, ARRAY_SIZE(funcs));