Skip to content

StackOverFlowError and memory leaking when sending large files slowly with Webflux + Undertow [SPR-16702] #21243

@spring-projects-issues

Description

@spring-projects-issues

Napster opened SPR-16702 and commented

Experiencing a StackOverFlowException when serving a text/plain output with about 9k lines / total size of about 700kB in production.
Reproducing turns out to be a bit finicky. I provided sample code and a sample curl request below, but it might not trigger always and usually requires a lot more data attempted to be sent to be triggered in a test environment.

This is happening when using undertow with Spring Boot 2.0.0 and 2.0.1, with java 8 and java 9. Removing undertow (and using the default, which would be netty), it does not happen.

java.lang.StackOverflowError: null
	at io.undertow.server.protocol.http.HttpResponseConduit.write(HttpResponseConduit.java:615) ~[undertow-core-1.4.23.Final.jar:1.4.23.Final]
	at io.undertow.conduits.AbstractFixedLengthStreamSinkConduit.write(AbstractFixedLengthStreamSinkConduit.java:106) ~[undertow-core-1.4.23.Final.jar:1.4.23.Final]
	at org.xnio.conduits.ConduitStreamSinkChannel.write(ConduitStreamSinkChannel.java:150) ~[xnio-api-3.3.8.Final.jar:3.3.8.Final]
	at io.undertow.channels.DetachableStreamSinkChannel.write(DetachableStreamSinkChannel.java:240) ~[undertow-core-1.4.23.Final.jar:1.4.23.Final]
	at io.undertow.server.HttpServerExchange$WriteDispatchChannel.write(HttpServerExchange.java:2094) ~[undertow-core-1.4.23.Final.jar:1.4.23.Final]
	at org.springframework.http.server.reactive.UndertowServerHttpResponse$ResponseBodyProcessor.writeByteBuffer(UndertowServerHttpResponse.java:196) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.UndertowServerHttpResponse$ResponseBodyProcessor.write(UndertowServerHttpResponse.java:176) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.UndertowServerHttpResponse$ResponseBodyProcessor.write(UndertowServerHttpResponse.java:147) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor$State$3.onWritePossible(AbstractListenerWriteProcessor.java:276) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.onWritePossible(AbstractListenerWriteProcessor.java:103) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.writeIfPossible(AbstractListenerWriteProcessor.java:212) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.access$300(AbstractListenerWriteProcessor.java:44) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor$State$3.onWritePossible(AbstractListenerWriteProcessor.java:294) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.onWritePossible(AbstractListenerWriteProcessor.java:103) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.writeIfPossible(AbstractListenerWriteProcessor.java:212) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.access$300(AbstractListenerWriteProcessor.java:44) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor$State$3.onWritePossible(AbstractListenerWriteProcessor.java:294) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.onWritePossible(AbstractListenerWriteProcessor.java:103) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.writeIfPossible(AbstractListenerWriteProcessor.java:212) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
	at org.springframework.http.server.reactive.AbstractListenerWriteProcessor.access$300(AbstractListenerWriteProcessor.java:44) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
.
.
.

curl -i -v -o /dev/null --limit-rate 1m localhost:8080/count?till=5000000

@RestController
public class TestController {

    @GetMapping("/count")
    public Mono<String> test(@RequestParam("till") long till) {
        return Mono.fromCallable(() ->
                count(till)
        );
    }

    private String count(long till) {
        StringBuilder sb = new StringBuilder();
        for (int ii = 0; ii < till; ii++) {
            sb.append(ii).append("\n");
        }
        return sb.toString();
    }
}

Affects: 5.0.5

Attachments:

Issue Links:

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions