From 2fd954a3b7abfe80cf702d58e5f5a43da44c5521 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 9 Mar 2020 12:16:09 +0100 Subject: [PATCH] Fix potential NPE in FuzzyTermsEnum (#53231) Under certain circumstances SpanMultiTermQueryWrapper uses SpanBooleanQueryRewriteWithMaxClause as its rewrite method, which in turn tries to get a TermsEnum from the wrapped MultiTermQuery currently using a `null` AttributeSource. While queries TermsQuery or subclasses of AutomatonQuery ignore this argument, FuzzyQuery uses it to create a FuzzyTermsEnum which triggers an NPE when the AttributeSource is not provided. This PR fixes this by supplying an empty AttributeSource instead of a `null` value. Closes #52894 --- .../SpanBooleanQueryRewriteWithMaxClause.java | 6 ++++-- .../search/query/SearchQueryIT.java | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/common/lucene/search/SpanBooleanQueryRewriteWithMaxClause.java b/server/src/main/java/org/elasticsearch/common/lucene/search/SpanBooleanQueryRewriteWithMaxClause.java index e78770ed2a8..a8a44ecb6e9 100644 --- a/server/src/main/java/org/elasticsearch/common/lucene/search/SpanBooleanQueryRewriteWithMaxClause.java +++ b/server/src/main/java/org/elasticsearch/common/lucene/search/SpanBooleanQueryRewriteWithMaxClause.java @@ -33,6 +33,7 @@ import org.apache.lucene.search.spans.SpanMultiTermQueryWrapper; import org.apache.lucene.search.spans.SpanOrQuery; import org.apache.lucene.search.spans.SpanQuery; import org.apache.lucene.search.spans.SpanTermQuery; +import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.BytesRef; import java.io.IOException; @@ -92,11 +93,12 @@ public class SpanBooleanQueryRewriteWithMaxClause extends SpanMultiTermQueryWrap continue; } - final TermsEnum termsEnum = getTermsEnum(query, terms, null); + final TermsEnum termsEnum = getTermsEnum(query, terms, new AttributeSource()); assert termsEnum != null; - if (termsEnum == TermsEnum.EMPTY) + if (termsEnum == TermsEnum.EMPTY) { continue; + } BytesRef bytes; while ((bytes = termsEnum.next()) != null) { diff --git a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java index a152cfbb1e9..88873ead39c 100644 --- a/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java +++ b/server/src/test/java/org/elasticsearch/search/query/SearchQueryIT.java @@ -19,7 +19,10 @@ package org.elasticsearch.search.query; +import org.apache.lucene.index.IndexReader; +import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.join.ScoreMode; +import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.English; import org.elasticsearch.action.index.IndexRequestBuilder; import org.elasticsearch.action.search.SearchPhaseExecutionException; @@ -28,6 +31,7 @@ import org.elasticsearch.action.search.SearchType; import org.elasticsearch.bootstrap.JavaVersion; import org.elasticsearch.common.Strings; import org.elasticsearch.common.document.DocumentField; +import org.elasticsearch.common.lucene.search.SpanBooleanQueryRewriteWithMaxClause; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -1892,4 +1896,20 @@ public class SearchQueryIT extends ESIntegTestCase { } } + + /** + * Test correct handling {@link SpanBooleanQueryRewriteWithMaxClause#rewrite(IndexReader, MultiTermQuery)}. That rewrite method is e.g. + * set for fuzzy queries with "constant_score" rewrite nested inside a `span_multi` query and would cause NPEs due to an unset + * {@link AttributeSource}. + */ + public void testIssueFuzzyInsideSpanMulti() { + createIndex("test"); + client().prepareIndex("test", "_doc", "1").setSource("field", "foobarbaz").get(); + ensureGreen(); + refresh(); + + BoolQueryBuilder query = boolQuery().filter(spanMultiTermQueryBuilder(fuzzyQuery("field", "foobarbiz").rewrite("constant_score"))); + SearchResponse response = client().prepareSearch("test").setQuery(query).get(); + assertHitCount(response, 1); + } }