From 1e0159219d2172f6b68d8625d54f592d5b46bc04 Mon Sep 17 00:00:00 2001 From: Dan Willemsen Date: Mon, 12 Feb 2018 18:16:35 -0800 Subject: Fail find parsing for \* Android hit a few cases where we were searching for *.pyc or verifiedboot*, and escaping the * as \*. In most cases the entire argument was just quoted instead. Kati understands and handles the quotes just fine, but it didn't realize that \* was special, so it was searching for files that started with a literal '\'. We have no good way of freeing allocated memory in the find parser, so just support stripping a leading \ (\*.pyc works, along with '\('), and fall back to the system find if another \ is found in a token. --- find.cc | 24 +++++++++++++++++------- find_test.cc | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 7 deletions(-) diff --git a/find.cc b/find.cc index 1bf0b9e..a31adce 100644 --- a/find.cc +++ b/find.cc @@ -449,6 +449,16 @@ class FindCommandParser { return false; *tok = tok->substr(1, tok->size() - 2); return true; + } else { + // Support stripping off a leading backslash + if (c == '\\') { + *tok = tok->substr(1); + } + // But if there are any others, we can't support it, as unescaping would + // require allocation + if (tok->find("\\") != string::npos) { + return false; + } } return true; @@ -473,18 +483,18 @@ class FindCommandParser { } FindCond* ParseFact(StringPiece tok) { - if (tok == "-not" || tok == "\\!") { + if (tok == "-not" || tok == "!") { if (!GetNextToken(&tok) || tok.empty()) return NULL; unique_ptr c(ParseFact(tok)); if (!c.get()) return NULL; return new NotCond(c.release()); - } else if (tok == "\\(") { + } else if (tok == "(") { if (!GetNextToken(&tok) || tok.empty()) return NULL; unique_ptr c(ParseExpr(tok)); - if (!GetNextToken(&tok) || tok != "\\)") { + if (!GetNextToken(&tok) || tok != ")") { return NULL; } return c.release(); @@ -530,7 +540,7 @@ class FindCommandParser { if (!GetNextToken(&tok) || tok.empty()) return NULL; } else { - if (tok != "-not" && tok != "\\!" && tok != "\\(" && tok != "-name" && + if (tok != "-not" && tok != "!" && tok != "(" && tok != "-name" && tok != "-type") { UngetToken(tok); return c.release(); @@ -567,8 +577,8 @@ class FindCommandParser { // ::= { } // ::= {[] } - // ::= | '\(' '\)' | - // ::= '-not' | '\!' + // ::= | '(' ')' | + // ::= '-not' | '!' // ::= '-and' | '-a' // ::= '-or' | '-o' // ::= | | @@ -609,7 +619,7 @@ class FindCommandParser { return false; } fc_->depth = d; - } else if (tok[0] == '-' || tok == "\\(") { + } else if (tok[0] == '-' || tok == "(" || tok == "!") { if (fc_->print_cond.get()) return false; FindCond* c = ParseFindCond(tok); diff --git a/find_test.cc b/find_test.cc index 10f865c..d7d44bd 100644 --- a/find_test.cc +++ b/find_test.cc @@ -107,6 +107,17 @@ void CompareFind(const string& cmd) { } } +void ExpectParseFailure(const string& cmd) { + Run(cmd); + + FindCommand fc; + if (fc.Parse(cmd)) { + fprintf(stderr, "Expected parse failure for `%s`\n", cmd.c_str()); + fprintf(stderr, "------------------------------------------\n"); + unit_test_failed = true; + } +} + int FindUnitTests() { Run("rm -rf out/find"); Run("mkdir -p out/find"); @@ -149,5 +160,11 @@ int FindUnitTests() { CompareFind("find .//top"); + CompareFind("find top -type f -name 'a*' -o -name \\*b"); + CompareFind("find top \\! -name 'a*'"); + CompareFind("find top \\( -name 'a*' \\)"); + + ExpectParseFailure("find top -name a\\*"); + return unit_test_failed ? 1 : 0; } -- cgit v1.2.3