From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp2 ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms0.migadu.com with LMTPS id wIQYL9Ap7mAkeQAAgWs5BA (envelope-from ) for ; Wed, 14 Jul 2021 02:03:28 +0200 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp2 with LMTPS id wCPYKtAp7mDWWgAAB5/wlQ (envelope-from ) for ; Wed, 14 Jul 2021 00:03:28 +0000 Received: from mail.notmuchmail.org (nmbug.tethera.net [144.217.243.247]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id 57B658689 for ; Wed, 14 Jul 2021 02:03:28 +0200 (CEST) Received: from nmbug.tethera.net (localhost [127.0.0.1]) by mail.notmuchmail.org (Postfix) with ESMTP id 5896C290E9; Tue, 13 Jul 2021 20:03:05 -0400 (EDT) Received: from fethera.tethera.net (fethera.tethera.net [IPv6:2607:5300:60:c5::1]) by mail.notmuchmail.org (Postfix) with ESMTP id D407A290D2 for ; Tue, 13 Jul 2021 20:02:47 -0400 (EDT) Received: by fethera.tethera.net (Postfix, from userid 1001) id CC02B5FD21; Tue, 13 Jul 2021 20:02:47 -0400 (EDT) Received: (nullmailer pid 804667 invoked by uid 1000); Wed, 14 Jul 2021 00:02:42 -0000 From: David Bremner To: notmuch@notmuchmail.org Cc: David Bremner Subject: [PATCH 09/11] lib/parse-sexp: add error handling to internal API Date: Tue, 13 Jul 2021 21:02:37 -0300 Message-Id: <20210714000239.804384-10-david@tethera.net> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20210714000239.804384-1-david@tethera.net> References: <20210714000239.804384-1-david@tethera.net> MIME-Version: 1.0 Message-ID-Hash: KTM5WANOXUMDD6CIGVHSR4O7VGZRFM6W X-Message-ID-Hash: KTM5WANOXUMDD6CIGVHSR4O7VGZRFM6W X-MailFrom: bremner@tethera.net X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-notmuch.notmuchmail.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; suspicious-header X-Mailman-Version: 3.2.1 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Help: List-Post: List-Subscribe: List-Unsubscribe: Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Migadu-Flow: FLOW_IN ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1626221008; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=QOqiNutiTb+CHrsIQZFiCZLkc5DC/uqiPBNbY3qKSmA=; b=NS2I3Va1U1HOWrvOcx2z1G7MbixcTsi20dJ9hf10HSDRoOAlDv5q06WYVEaLuD/CQ1Ejrh 8O3eEeMBCh5mTceg8vFxhNB8wlkM/S5pgSA/v6T0cecoR4Fpou2m5ThwfoknMEXiQL0kwk BbEEkL1fmTi30kVYtNMRtqPo80i/iwpX8IQfe+K0Y+cd53vB/Zl6zmXS3snXaDxjSZFaSb hGMiuT9Pe/CHkyqgdGEki+fgVpDZmfISWWm293wzDr37K0wO1NTnkpuhQh6sTvYpMDgpx2 +5KGKbv6JOfsoScXkp2zD7cexP0HgFcxaPijFsiEhU0thgLh7OiCzUk9k2ww5Q== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1626221008; a=rsa-sha256; cv=none; b=qj5TB4scjlJiH3a6WzHqWCkw9g2m0d6t1uNVQV1bv0pgE2jF9tTRHsuyUhBEzPpq5aqpbh W+aODjpoom6n8Pcy0xMRhr30AMYbVpyBrpxW8LKWP0ZQWzwYwS5n4gaePTRnRX6pH/fRCH ceMkrTB4zZbwDOOt95BTDNishdCFM2mtCJWu2ldIQEs2xfq6O693Fwrai8+ADQzSLUydcG PUFtPcUABnrK+6KrgVx6KitbUNPOPFsrj2YmwLx+A/J7x5Fofl480TwNgQ94GZdM7df3oG 2ZlQQz2EgX8M9fqYsJTg/oUtsSBJFKE9ABZy06VAPLhrBtmrzXlVpAcaOK+g9w== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=none; dmarc=none; spf=pass (aspmx1.migadu.com: domain of notmuch-bounces@notmuchmail.org designates 144.217.243.247 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Migadu-Spam-Score: -1.08 Authentication-Results: aspmx1.migadu.com; dkim=none; dmarc=none; spf=pass (aspmx1.migadu.com: domain of notmuch-bounces@notmuchmail.org designates 144.217.243.247 as permitted sender) smtp.mailfrom=notmuch-bounces@notmuchmail.org X-Migadu-Queue-Id: 57B658689 X-Spam-Score: -1.08 X-Migadu-Scanner: scn0.migadu.com X-TUID: uxHLeEqAEdhH The 'notmuch' argument is currently only used for logging in one place, but this will most likely change in the future. Furthermore, it will be needed for e.g. stored queries. --- lib/parse-sexp.cc | 75 +++++++++++++++++++++++++-------------- lib/query.cc | 5 +-- test/T081-sexpr-search.sh | 12 ++++++- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/lib/parse-sexp.cc b/lib/parse-sexp.cc index 81bf5cee..4a9e1aeb 100644 --- a/lib/parse-sexp.cc +++ b/lib/parse-sexp.cc @@ -40,40 +40,55 @@ static _sexp_field_t fields[] = { } }; -static Xapian::Query _sexp_to_xapian_query (sexp_t *sx); +static notmuch_status_t _sexp_to_xapian_query (notmuch_database_t *notmuch, sexp_t *sx, Xapian::Query &output); -static Xapian::Query -_sexp_combine_query (Xapian::Query::op operation, +static notmuch_status_t +_sexp_combine_query (notmuch_database_t *notmuch, + Xapian::Query::op operation, Xapian::Query left, - sexp_t *sx) + sexp_t *sx, + Xapian::Query &output) { + Xapian::Query subquery; + + notmuch_status_t status; /* if we run out elements, return accumulator */ - if (! sx) - return left; + if (! sx) { + output = left; + return NOTMUCH_STATUS_SUCCESS; + } - return _sexp_combine_query (operation, - Xapian::Query (operation, - left, - _sexp_to_xapian_query (sx)), - sx->next); + status = _sexp_to_xapian_query (notmuch, sx, subquery); + if (status) + return status; + + return _sexp_combine_query (notmuch, + operation, + Xapian::Query (operation, left, subquery), + sx->next, output); } -Xapian::Query -_notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *querystr) +notmuch_status_t +_notmuch_sexp_string_to_xapian_query (notmuch_database_t *notmuch, const char *querystr, + Xapian::Query &output) { sexp_t *sx = NULL; char *buf = talloc_strdup (notmuch, querystr); sx = parse_sexp (buf, strlen (querystr)); - return _sexp_to_xapian_query (sx); + if (!sx) + return NOTMUCH_STATUS_ILLEGAL_ARGUMENT; + + return _sexp_to_xapian_query (notmuch, sx, output); } -static Xapian::Query +static notmuch_status_t _sexp_combine_field (const char *prefix, Xapian::Query::op operation, - sexp_t *sx) + sexp_t *sx, + Xapian::Query &output) { std::vector terms; @@ -107,15 +122,16 @@ _sexp_combine_field (const char *prefix, terms.push_back (pref_str + cur->val); } } - return Xapian::Query (operation, terms.begin (), terms.end ()); + output = Xapian::Query (operation, terms.begin (), terms.end ()); + return NOTMUCH_STATUS_SUCCESS; } /* Here we expect the s-expression to be a proper list, with first * element defining and operation, or as a special case the empty * list */ -static Xapian::Query -_sexp_to_xapian_query (sexp_t *sx) +static notmuch_status_t +_sexp_to_xapian_query (notmuch_database_t *notmuch, sexp_t *sx, Xapian::Query &output) { const _sexp_op_t *op; @@ -124,18 +140,25 @@ _sexp_to_xapian_query (sexp_t *sx) assert (sx->ty == SEXP_LIST); /* Empty list */ - if (! sx->list) - return Xapian::Query::MatchAll; + if (! sx->list) { + output = Xapian::Query::MatchAll; + return NOTMUCH_STATUS_SUCCESS; + } for (op = operations; op && op->name; op++) { - if (strcasecmp (op->name, hd_sexp (sx)->val) == 0) - return _sexp_combine_query (op->xapian_op, op->initial, sx->list->next); + if (strcasecmp (op->name, hd_sexp (sx)->val) == 0) { + return _sexp_combine_query (notmuch, op->xapian_op, op->initial, sx->list->next, output); + } + } for (const _sexp_field_t *field = fields; field && field->name; field++) { - if (strcasecmp (field->name, hd_sexp (sx)->val) == 0) - return _sexp_combine_field (_find_prefix (field->name), field->xapian_op, sx->list->next); + if (strcasecmp (field->name, hd_sexp (sx)->val) == 0) { + return _sexp_combine_field (_find_prefix (field->name), field->xapian_op, sx->list->next, + output); + } } - INTERNAL_ERROR ("unimplemented prefix %s\n", sx->list->val); + _notmuch_database_log_append (notmuch, "unimplemented prefix %s\n", sx->list->val); + return NOTMUCH_STATUS_ILLEGAL_ARGUMENT; } diff --git a/lib/query.cc b/lib/query.cc index 6e89af60..4b42620e 100644 --- a/lib/query.cc +++ b/lib/query.cc @@ -191,10 +191,7 @@ _notmuch_query_ensure_parsed_xapian (notmuch_query_t *query) static notmuch_status_t _notmuch_query_ensure_parsed_sexpr (notmuch_query_t *query) { - - query->xapian_query = _notmuch_sexp_string_to_xapian_query (query->notmuch, query->query_string); - - return NOTMUCH_STATUS_SUCCESS; + return _notmuch_sexp_string_to_xapian_query (query->notmuch, query->query_string, query->xapian_query); } static notmuch_status_t diff --git a/test/T081-sexpr-search.sh b/test/T081-sexpr-search.sh index 9ee9de7b..b8229ebe 100755 --- a/test/T081-sexpr-search.sh +++ b/test/T081-sexpr-search.sh @@ -178,5 +178,15 @@ test_begin_subtest "Search by 'to' (name and address)" output=$(notmuch search --query-syntax=sexp '(to "Search By To Name ")' | notmuch_search_sanitize) test_expect_equal "$output" "thread:XXX 2000-01-01 [1/1] Notmuch Test Suite; search by to (name) (inbox unread)" - +test_begin_subtest "Unbalanced parens" +# A code 1 indicates the error was handled (a crash will return e.g. 139). +test_expect_code 1 "notmuch search --query-syntax=sexp '('" + +test_begin_subtest "unknown_prefix" +notmuch search --query-syntax=sexp '(foo)' >OUTPUT 2>&1 +cat < EXPECTED +notmuch search: Illegal argument for function +unimplemented prefix foo +EOF +test_expect_equal_file EXPECTED OUTPUT test_done -- 2.30.2