Skip to content

Commit 946ec7e

Browse files
committed
Fix memory leaks in ProtobufDecoder
Issue: SPR-17418
1 parent a64e85f commit 946ec7e

File tree

3 files changed

+32
-29
lines changed

3 files changed

+32
-29
lines changed

spring-core/src/test/java/org/springframework/core/io/buffer/AbstractDataBufferAllocatingTestCase.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -66,9 +66,12 @@ protected DataBuffer createDataBuffer(int capacity) {
6666
}
6767

6868
protected DataBuffer stringBuffer(String value) {
69-
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
70-
DataBuffer buffer = this.bufferFactory.allocateBuffer(bytes.length);
71-
buffer.write(bytes);
69+
return byteBuffer(value.getBytes(StandardCharsets.UTF_8));
70+
}
71+
72+
protected DataBuffer byteBuffer(byte[] value) {
73+
DataBuffer buffer = this.bufferFactory.allocateBuffer(value.length);
74+
buffer.write(value);
7275
return buffer;
7376
}
7477

spring-web/src/main/java/org/springframework/http/codec/protobuf/ProtobufDecoder.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,18 @@ public Iterable<? extends Message> apply(DataBuffer input) {
216216
} while (remainingBytesToRead > 0);
217217
return messages;
218218
}
219+
catch (DecodingException ex) {
220+
throw ex;
221+
}
219222
catch (IOException ex) {
220223
throw new DecodingException("I/O error while parsing input stream", ex);
221224
}
222225
catch (Exception ex) {
223226
throw new DecodingException("Could not read Protobuf message: " + ex.getMessage(), ex);
224227
}
228+
finally {
229+
DataBufferUtils.release(input);
230+
}
225231
}
226232
}
227233

spring-web/src/test/java/org/springframework/http/codec/protobuf/ProtobufDecoderTests.java

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@
3636
import org.springframework.util.MimeType;
3737

3838
import static java.util.Collections.emptyMap;
39-
import static org.junit.Assert.assertFalse;
40-
import static org.junit.Assert.assertTrue;
39+
import static org.junit.Assert.*;
4140
import static org.springframework.core.ResolvableType.forClass;
4241

4342
/**
@@ -81,7 +80,7 @@ public void canDecode() {
8180

8281
@Test
8382
public void decodeToMono() {
84-
DataBuffer data = this.bufferFactory.wrap(testMsg.toByteArray());
83+
DataBuffer data = byteBuffer(testMsg.toByteArray());
8584
ResolvableType elementType = forClass(Msg.class);
8685

8786
Mono<Message> mono = this.decoder.decodeToMono(Flux.just(data), elementType, null, emptyMap());
@@ -106,12 +105,12 @@ public void decodeToMonoWithLargerDataBuffer() {
106105

107106
@Test
108107
public void decodeChunksToMono() {
109-
DataBuffer buffer = this.bufferFactory.wrap(testMsg.toByteArray());
108+
DataBuffer buffer = byteBuffer(testMsg.toByteArray());
110109
Flux<DataBuffer> chunks = Flux.just(
111-
buffer.slice(0, 4),
112-
buffer.slice(4, buffer.readableByteCount() - 4));
113-
DataBufferUtils.retain(buffer);
110+
DataBufferUtils.retain(buffer.slice(0, 4)),
111+
DataBufferUtils.retain(buffer.slice(4, buffer.readableByteCount() - 4)));
114112
ResolvableType elementType = forClass(Msg.class);
113+
release(buffer);
115114

116115
Mono<Message> mono = this.decoder.decodeToMono(chunks, elementType, null,
117116
emptyMap());
@@ -123,10 +122,11 @@ public void decodeChunksToMono() {
123122

124123
@Test
125124
public void decode() throws IOException {
126-
DataBuffer buffer = bufferFactory.allocateBuffer();
125+
DataBuffer buffer = this.bufferFactory.allocateBuffer();
127126
testMsg.writeDelimitedTo(buffer.asOutputStream());
128-
DataBuffer buffer2 = bufferFactory.allocateBuffer();
127+
DataBuffer buffer2 = this.bufferFactory.allocateBuffer();
129128
testMsg2.writeDelimitedTo(buffer2.asOutputStream());
129+
130130
Flux<DataBuffer> source = Flux.just(buffer, buffer2);
131131
ResolvableType elementType = forClass(Msg.class);
132132

@@ -136,22 +136,22 @@ public void decode() throws IOException {
136136
.expectNext(testMsg)
137137
.expectNext(testMsg2)
138138
.verifyComplete();
139-
140-
DataBufferUtils.release(buffer);
141-
DataBufferUtils.release(buffer2);
142139
}
143140

144141
@Test
145142
public void decodeSplitChunks() throws IOException {
146-
DataBuffer buffer = bufferFactory.allocateBuffer();
143+
DataBuffer buffer = this.bufferFactory.allocateBuffer();
147144
testMsg.writeDelimitedTo(buffer.asOutputStream());
148-
DataBuffer buffer2 = bufferFactory.allocateBuffer();
145+
DataBuffer buffer2 = this.bufferFactory.allocateBuffer();
149146
testMsg2.writeDelimitedTo(buffer2.asOutputStream());
147+
150148
Flux<DataBuffer> chunks = Flux.just(
151-
buffer.slice(0, 4),
152-
buffer.slice(4, buffer.readableByteCount() - 4),
153-
buffer2.slice(0, 2),
154-
buffer2.slice(2, buffer2.readableByteCount() - 2));
149+
DataBufferUtils.retain(buffer.slice(0, 4)),
150+
DataBufferUtils.retain(buffer.slice(4, buffer.readableByteCount() - 4)),
151+
DataBufferUtils.retain(buffer2.slice(0, 2)),
152+
DataBufferUtils.retain(buffer2
153+
.slice(2, buffer2.readableByteCount() - 2)));
154+
release(buffer, buffer2);
155155

156156
ResolvableType elementType = forClass(Msg.class);
157157
Flux<Message> messages = this.decoder.decode(chunks, elementType, null, emptyMap());
@@ -160,9 +160,6 @@ public void decodeSplitChunks() throws IOException {
160160
.expectNext(testMsg)
161161
.expectNext(testMsg2)
162162
.verifyComplete();
163-
164-
DataBufferUtils.release(buffer);
165-
DataBufferUtils.release(buffer2);
166163
}
167164

168165
@Test
@@ -178,15 +175,12 @@ public void decodeMergedChunks() throws IOException {
178175
.expectNext(testMsg)
179176
.expectNext(testMsg)
180177
.verifyComplete();
181-
182-
DataBufferUtils.release(buffer);
183178
}
184179

185180
@Test
186181
public void exceedMaxSize() {
187182
this.decoder.setMaxMessageSize(1);
188-
byte[] body = testMsg.toByteArray();
189-
Flux<DataBuffer> source = Flux.just(this.bufferFactory.wrap(body));
183+
Flux<DataBuffer> source = Flux.just(byteBuffer(testMsg.toByteArray()));
190184
ResolvableType elementType = forClass(Msg.class);
191185
Flux<Message> messages = this.decoder.decode(source, elementType, null,
192186
emptyMap());

0 commit comments

Comments
 (0)