summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2022-02-28 14:35:39 -0500
committerTavian Barnes <tavianator@tavianator.com>2022-02-28 14:35:39 -0500
commit517a303e425b606cde3b70a1481ff557bba17462 (patch)
treecdb4100bab98bbd335aa192128aff949850f3ffe
parente14f04e52f792d12f3798b3c69bd0279ac7d3150 (diff)
downloadbfs-517a303e425b606cde3b70a1481ff557bba17462.tar.xz
parse: Check for globs with unescaped trailing backslashes
Both macOS and musl fail to fail on an unescaped backslash, so check for it ourselves. Link: https://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html Link: https://github.com/void-linux/void-packages/pull/35836 Link: https://www.openwall.com/lists/musl/2022/02/25/2 Link: https://www.austingroupbugs.net/view.php?id=806
-rw-r--r--parse.c25
-rwxr-xr-xtests.sh3
2 files changed, 23 insertions, 5 deletions
diff --git a/parse.c b/parse.c
index 826d325..3439f23 100644
--- a/parse.c
+++ b/parse.c
@@ -1686,11 +1686,14 @@ static struct expr *parse_fnmatch(const struct parser_state *state, struct expr
return NULL;
}
+ const char *arg = expr->argv[0];
+ const char *pattern = expr->sdata;
+
if (casefold) {
#ifdef FNM_CASEFOLD
expr->idata = FNM_CASEFOLD;
#else
- parse_error(state, "${blu}%s${rs} is missing platform support.\n", expr->argv[0]);
+ parse_error(state, "${blu}%s${rs} is missing platform support.\n", arg);
free_expr(expr);
return NULL;
#endif
@@ -1698,9 +1701,27 @@ static struct expr *parse_fnmatch(const struct parser_state *state, struct expr
expr->idata = 0;
}
+ // POSIX says, about fnmatch():
+ //
+ // If pattern ends with an unescaped <backslash>, fnmatch() shall
+ // return a non-zero value (indicating either no match or an error).
+ //
+ // But not all implementations obey this, so check for it ourselves.
+ size_t i, len = strlen(pattern);
+ for (i = 0; i < len; ++i) {
+ if (pattern[len - i - 1] != '\\') {
+ break;
+ }
+ }
+ if (i % 2 != 0) {
+ parse_warning(state, "${blu}%s${rs} ${bld}%s${rs}: Unescaped trailing backslash.\n\n", arg, pattern);
+ free_expr(expr);
+ return &expr_false;
+ }
+
expr->cost = 400.0;
- if (strchr(expr->sdata, '*')) {
+ if (strchr(pattern, '*')) {
expr->probability = 0.5;
} else {
expr->probability = 0.1;
diff --git a/tests.sh b/tests.sh
index 9003efd..995b7a6 100755
--- a/tests.sh
+++ b/tests.sh
@@ -1338,9 +1338,6 @@ function test_name_bracket() {
}
function test_name_backslash() {
- # fnmatch() is broken on macOS
- skip_if test "$UNAME" = "Darwin"
-
# An unescaped \ doesn't match
bfs_diff weirdnames -name '\'
}