Skip to content

Commit 4b199dd

Browse files
NETWORKING: Fix Netty Leaks by upgrading to 4.1.28 (#32511)
* Upgrade to `4.1.28` since the problem reported in #32487 is a bug in Netty itself (see netty/netty#7337) * Fixed other leaks in test code that now showed up due to fixes improvements in leak reporting in the newer version * Needed to extend permissions for netty common package because it now sets a classloader at runtime after changes in netty/netty@63bae09 * Adjusted forbidden APIs check accordingly * Closes #32487
1 parent cc6d6ca commit 4b199dd

File tree

40 files changed

+137
-76
lines changed

40 files changed

+137
-76
lines changed

modules/transport-netty4/build.gradle

+8-9
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ compileTestJava.options.compilerArgs << "-Xlint:-cast,-deprecation,-rawtypes,-tr
3434

3535
dependencies {
3636
// network stack
37-
compile "io.netty:netty-buffer:4.1.16.Final"
38-
compile "io.netty:netty-codec:4.1.16.Final"
39-
compile "io.netty:netty-codec-http:4.1.16.Final"
40-
compile "io.netty:netty-common:4.1.16.Final"
41-
compile "io.netty:netty-handler:4.1.16.Final"
42-
compile "io.netty:netty-resolver:4.1.16.Final"
43-
compile "io.netty:netty-transport:4.1.16.Final"
37+
compile "io.netty:netty-buffer:4.1.28.Final"
38+
compile "io.netty:netty-codec:4.1.28.Final"
39+
compile "io.netty:netty-codec-http:4.1.28.Final"
40+
compile "io.netty:netty-common:4.1.28.Final"
41+
compile "io.netty:netty-handler:4.1.28.Final"
42+
compile "io.netty:netty-resolver:4.1.28.Final"
43+
compile "io.netty:netty-transport:4.1.28.Final"
4444
}
4545

4646
dependencyLicenses {
@@ -134,7 +134,6 @@ thirdPartyAudit.excludes = [
134134
'net.jpountz.xxhash.StreamingXXHash32',
135135
'net.jpountz.xxhash.XXHashFactory',
136136
'io.netty.internal.tcnative.CertificateRequestedCallback',
137-
'io.netty.internal.tcnative.CertificateRequestedCallback$KeyMaterial',
138137
'io.netty.internal.tcnative.CertificateVerifier',
139138
'io.netty.internal.tcnative.SessionTicketKey',
140139
'io.netty.internal.tcnative.SniHostNameMatcher',
@@ -161,6 +160,6 @@ thirdPartyAudit.excludes = [
161160

162161
'org.conscrypt.AllocatedBuffer',
163162
'org.conscrypt.BufferAllocator',
164-
'org.conscrypt.Conscrypt$Engines',
163+
'org.conscrypt.Conscrypt',
165164
'org.conscrypt.HandshakeListener'
166165
]

modules/transport-netty4/licenses/netty-buffer-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
d6c2d13492778009d33f60e05ed90bcb535d1fd1

modules/transport-netty4/licenses/netty-codec-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a38361d893900947524f8a9da980555950e73d6a

modules/transport-netty4/licenses/netty-codec-http-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
897100c1022c780b0a436b9349e507e8fa9800dc

modules/transport-netty4/licenses/netty-common-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
df69ce8bb9b544a71e7bbee290253cf7c93e6bad

modules/transport-netty4/licenses/netty-handler-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a035784682da0126bc25f10713dac732b5082a6d

modules/transport-netty4/licenses/netty-resolver-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
f33557dcb31fa20da075ac05e4808115e32ef9b7

modules/transport-netty4/licenses/netty-transport-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
d2ef28f49d726737f0ffe84bf66529b3bf6e0c0d

modules/transport-netty4/src/main/plugin-metadata/plugin-security.policy

+3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ grant codeBase "${codebase.netty-common}" {
2323

2424
// netty makes and accepts socket connections
2525
permission java.net.SocketPermission "*", "accept,connect";
26+
27+
// Netty sets custom classloader for some of its internal threads
28+
permission java.lang.RuntimePermission "*", "setContextClassLoader";
2629
};
2730

2831
grant codeBase "${codebase.netty-transport}" {

modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4BadRequestTests.java

+12-7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.http.netty4;
2121

2222
import io.netty.handler.codec.http.FullHttpResponse;
23+
import io.netty.util.ReferenceCounted;
2324
import org.elasticsearch.ElasticsearchException;
2425
import org.elasticsearch.common.network.NetworkService;
2526
import org.elasticsearch.common.settings.Settings;
@@ -92,15 +93,19 @@ public void dispatchBadRequest(RestRequest request, RestChannel channel, ThreadC
9293
try (Netty4HttpClient nettyHttpClient = new Netty4HttpClient()) {
9394
final Collection<FullHttpResponse> responses =
9495
nettyHttpClient.get(transportAddress.address(), "/_cluster/settings?pretty=%");
95-
assertThat(responses, hasSize(1));
96-
assertThat(responses.iterator().next().status().code(), equalTo(400));
97-
final Collection<String> responseBodies = Netty4HttpClient.returnHttpResponseBodies(responses);
98-
assertThat(responseBodies, hasSize(1));
99-
assertThat(responseBodies.iterator().next(), containsString("\"type\":\"bad_parameter_exception\""));
100-
assertThat(
96+
try {
97+
assertThat(responses, hasSize(1));
98+
assertThat(responses.iterator().next().status().code(), equalTo(400));
99+
final Collection<String> responseBodies = Netty4HttpClient.returnHttpResponseBodies(responses);
100+
assertThat(responseBodies, hasSize(1));
101+
assertThat(responseBodies.iterator().next(), containsString("\"type\":\"bad_parameter_exception\""));
102+
assertThat(
101103
responseBodies.iterator().next(),
102104
containsString(
103-
"\"reason\":\"java.lang.IllegalArgumentException: unterminated escape sequence at end of string: %\""));
105+
"\"reason\":\"java.lang.IllegalArgumentException: unterminated escape sequence at end of string: %\""));
106+
} finally {
107+
responses.forEach(ReferenceCounted::release);
108+
}
104109
}
105110
}
106111
}

modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpRequestSizeLimitIT.java

+21-8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.http.netty4;
2121

2222
import io.netty.handler.codec.http.FullHttpResponse;
23+
import io.netty.util.ReferenceCounted;
2324
import org.elasticsearch.ESNetty4IntegTestCase;
2425
import org.elasticsearch.common.collect.Tuple;
2526
import org.elasticsearch.common.settings.Settings;
@@ -88,12 +89,20 @@ public void testLimitsInFlightRequests() throws Exception {
8889

8990
try (Netty4HttpClient nettyHttpClient = new Netty4HttpClient()) {
9091
Collection<FullHttpResponse> singleResponse = nettyHttpClient.post(transportAddress.address(), requests[0]);
91-
assertThat(singleResponse, hasSize(1));
92-
assertAtLeastOnceExpectedStatus(singleResponse, HttpResponseStatus.OK);
93-
94-
Collection<FullHttpResponse> multipleResponses = nettyHttpClient.post(transportAddress.address(), requests);
95-
assertThat(multipleResponses, hasSize(requests.length));
96-
assertAtLeastOnceExpectedStatus(multipleResponses, HttpResponseStatus.SERVICE_UNAVAILABLE);
92+
try {
93+
assertThat(singleResponse, hasSize(1));
94+
assertAtLeastOnceExpectedStatus(singleResponse, HttpResponseStatus.OK);
95+
96+
Collection<FullHttpResponse> multipleResponses = nettyHttpClient.post(transportAddress.address(), requests);
97+
try {
98+
assertThat(multipleResponses, hasSize(requests.length));
99+
assertAtLeastOnceExpectedStatus(multipleResponses, HttpResponseStatus.SERVICE_UNAVAILABLE);
100+
} finally {
101+
multipleResponses.forEach(ReferenceCounted::release);
102+
}
103+
} finally {
104+
singleResponse.forEach(ReferenceCounted::release);
105+
}
97106
}
98107
}
99108

@@ -113,8 +122,12 @@ public void testDoesNotLimitExcludedRequests() throws Exception {
113122

114123
try (Netty4HttpClient nettyHttpClient = new Netty4HttpClient()) {
115124
Collection<FullHttpResponse> responses = nettyHttpClient.put(transportAddress.address(), requestUris);
116-
assertThat(responses, hasSize(requestUris.length));
117-
assertAllInExpectedStatus(responses, HttpResponseStatus.OK);
125+
try {
126+
assertThat(responses, hasSize(requestUris.length));
127+
assertAllInExpectedStatus(responses, HttpResponseStatus.OK);
128+
} finally {
129+
responses.forEach(ReferenceCounted::release);
130+
}
118131
}
119132
}
120133

modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpServerPipeliningTests.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import io.netty.handler.codec.http.FullHttpRequest;
3030
import io.netty.handler.codec.http.FullHttpResponse;
3131
import io.netty.handler.codec.http.HttpHeaderNames;
32+
import io.netty.util.ReferenceCounted;
3233
import org.elasticsearch.common.bytes.BytesArray;
3334
import org.elasticsearch.common.network.NetworkService;
3435
import org.elasticsearch.common.settings.Settings;
@@ -98,8 +99,12 @@ public void testThatHttpPipeliningWorks() throws Exception {
9899

99100
try (Netty4HttpClient nettyHttpClient = new Netty4HttpClient()) {
100101
Collection<FullHttpResponse> responses = nettyHttpClient.get(transportAddress.address(), requests.toArray(new String[]{}));
101-
Collection<String> responseBodies = Netty4HttpClient.returnHttpResponseBodies(responses);
102-
assertThat(responseBodies, contains(requests.toArray()));
102+
try {
103+
Collection<String> responseBodies = Netty4HttpClient.returnHttpResponseBodies(responses);
104+
assertThat(responseBodies, contains(requests.toArray()));
105+
} finally {
106+
responses.forEach(ReferenceCounted::release);
107+
}
103108
}
104109
}
105110
}

modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4HttpServerTransportTests.java

+23-10
Original file line numberDiff line numberDiff line change
@@ -207,14 +207,23 @@ public void dispatchBadRequest(RestRequest request, RestChannel channel, ThreadC
207207
HttpUtil.setContentLength(request, contentLength);
208208

209209
final FullHttpResponse response = client.post(remoteAddress.address(), request);
210-
assertThat(response.status(), equalTo(expectedStatus));
211-
if (expectedStatus.equals(HttpResponseStatus.CONTINUE)) {
212-
final FullHttpRequest continuationRequest =
213-
new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/", Unpooled.EMPTY_BUFFER);
214-
final FullHttpResponse continuationResponse = client.post(remoteAddress.address(), continuationRequest);
215-
216-
assertThat(continuationResponse.status(), is(HttpResponseStatus.OK));
217-
assertThat(new String(ByteBufUtil.getBytes(continuationResponse.content()), StandardCharsets.UTF_8), is("done"));
210+
try {
211+
assertThat(response.status(), equalTo(expectedStatus));
212+
if (expectedStatus.equals(HttpResponseStatus.CONTINUE)) {
213+
final FullHttpRequest continuationRequest =
214+
new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, "/", Unpooled.EMPTY_BUFFER);
215+
final FullHttpResponse continuationResponse = client.post(remoteAddress.address(), continuationRequest);
216+
try {
217+
assertThat(continuationResponse.status(), is(HttpResponseStatus.OK));
218+
assertThat(
219+
new String(ByteBufUtil.getBytes(continuationResponse.content()), StandardCharsets.UTF_8), is("done")
220+
);
221+
} finally {
222+
continuationResponse.release();
223+
}
224+
}
225+
} finally {
226+
response.release();
218227
}
219228
}
220229
}
@@ -280,10 +289,14 @@ public void dispatchBadRequest(final RestRequest request,
280289
final FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, url);
281290

282291
final FullHttpResponse response = client.post(remoteAddress.address(), request);
283-
assertThat(response.status(), equalTo(HttpResponseStatus.BAD_REQUEST));
284-
assertThat(
292+
try {
293+
assertThat(response.status(), equalTo(HttpResponseStatus.BAD_REQUEST));
294+
assertThat(
285295
new String(response.content().array(), Charset.forName("UTF-8")),
286296
containsString("you sent a bad request and you should feel bad"));
297+
} finally {
298+
response.release();
299+
}
287300
}
288301
}
289302

modules/transport-netty4/src/test/java/org/elasticsearch/http/netty4/Netty4PipeliningIT.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
package org.elasticsearch.http.netty4;
2121

2222
import io.netty.handler.codec.http.FullHttpResponse;
23+
import io.netty.util.ReferenceCounted;
2324
import org.elasticsearch.ESNetty4IntegTestCase;
2425
import org.elasticsearch.common.transport.TransportAddress;
2526
import org.elasticsearch.http.HttpServerTransport;
@@ -45,14 +46,18 @@ public void testThatNettyHttpServerSupportsPipelining() throws Exception {
4546

4647
HttpServerTransport httpServerTransport = internalCluster().getInstance(HttpServerTransport.class);
4748
TransportAddress[] boundAddresses = httpServerTransport.boundAddress().boundAddresses();
48-
TransportAddress transportAddress = (TransportAddress) randomFrom(boundAddresses);
49+
TransportAddress transportAddress = randomFrom(boundAddresses);
4950

5051
try (Netty4HttpClient nettyHttpClient = new Netty4HttpClient()) {
5152
Collection<FullHttpResponse> responses = nettyHttpClient.get(transportAddress.address(), requests);
52-
assertThat(responses, hasSize(5));
53+
try {
54+
assertThat(responses, hasSize(5));
5355

54-
Collection<String> opaqueIds = Netty4HttpClient.returnOpaqueIds(responses);
55-
assertOpaqueIdsInOrder(opaqueIds);
56+
Collection<String> opaqueIds = Netty4HttpClient.returnOpaqueIds(responses);
57+
assertOpaqueIdsInOrder(opaqueIds);
58+
} finally {
59+
responses.forEach(ReferenceCounted::release);
60+
}
5661
}
5762
}
5863

plugins/transport-nio/build.gradle

+8-9
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ dependencies {
2929
compile "org.elasticsearch:elasticsearch-nio:${version}"
3030

3131
// network stack
32-
compile "io.netty:netty-buffer:4.1.16.Final"
33-
compile "io.netty:netty-codec:4.1.16.Final"
34-
compile "io.netty:netty-codec-http:4.1.16.Final"
35-
compile "io.netty:netty-common:4.1.16.Final"
36-
compile "io.netty:netty-handler:4.1.16.Final"
37-
compile "io.netty:netty-resolver:4.1.16.Final"
38-
compile "io.netty:netty-transport:4.1.16.Final"
32+
compile "io.netty:netty-buffer:4.1.28.Final"
33+
compile "io.netty:netty-codec:4.1.28.Final"
34+
compile "io.netty:netty-codec-http:4.1.28.Final"
35+
compile "io.netty:netty-common:4.1.28.Final"
36+
compile "io.netty:netty-handler:4.1.28.Final"
37+
compile "io.netty:netty-resolver:4.1.28.Final"
38+
compile "io.netty:netty-transport:4.1.28.Final"
3939
}
4040

4141
dependencyLicenses {
@@ -113,7 +113,6 @@ thirdPartyAudit.excludes = [
113113
'net.jpountz.xxhash.StreamingXXHash32',
114114
'net.jpountz.xxhash.XXHashFactory',
115115
'io.netty.internal.tcnative.CertificateRequestedCallback',
116-
'io.netty.internal.tcnative.CertificateRequestedCallback$KeyMaterial',
117116
'io.netty.internal.tcnative.CertificateVerifier',
118117
'io.netty.internal.tcnative.SessionTicketKey',
119118
'io.netty.internal.tcnative.SniHostNameMatcher',
@@ -140,6 +139,6 @@ thirdPartyAudit.excludes = [
140139

141140
'org.conscrypt.AllocatedBuffer',
142141
'org.conscrypt.BufferAllocator',
143-
'org.conscrypt.Conscrypt$Engines',
142+
'org.conscrypt.Conscrypt',
144143
'org.conscrypt.HandshakeListener'
145144
]

plugins/transport-nio/licenses/netty-buffer-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
d6c2d13492778009d33f60e05ed90bcb535d1fd1

plugins/transport-nio/licenses/netty-codec-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a38361d893900947524f8a9da980555950e73d6a

plugins/transport-nio/licenses/netty-codec-http-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
897100c1022c780b0a436b9349e507e8fa9800dc

plugins/transport-nio/licenses/netty-common-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
df69ce8bb9b544a71e7bbee290253cf7c93e6bad

plugins/transport-nio/licenses/netty-handler-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a035784682da0126bc25f10713dac732b5082a6d

plugins/transport-nio/licenses/netty-resolver-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
f33557dcb31fa20da075ac05e4808115e32ef9b7

plugins/transport-nio/licenses/netty-transport-4.1.16.Final.jar.sha1

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
d2ef28f49d726737f0ffe84bf66529b3bf6e0c0d

plugins/transport-nio/src/main/plugin-metadata/plugin-security.policy

+2
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,6 @@ grant codeBase "${codebase.netty-common}" {
2626
// This should only currently be required as we use the netty http client for tests
2727
// netty makes and accepts socket connections
2828
permission java.net.SocketPermission "*", "accept,connect";
29+
// Netty sets custom classloader for some of its internal threads
30+
permission java.lang.RuntimePermission "*", "setContextClassLoader";
2931
};

0 commit comments

Comments
 (0)