Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fd leak on HTTPServerResponse when error occurs while writing the response #2484

Closed
tchaloupka opened this issue Oct 16, 2020 · 0 comments
Closed

Comments

@tchaloupka
Copy link
Contributor

How to reproduce:

import vibe.core.core;
import vibe.core.log;
import vibe.http.router;
import vibe.http.server;
import std.algorithm;
import std.array;
import std.range;

struct Foo { int id; }

void main() {
    auto router = new URLRouter;
    router.get("*", &test);
    router.rebuild();
    auto settings = new HTTPServerSettings();
    settings.port = 9090;
    listenHTTP(settings, router);
    runApplication();
}

void test(HTTPServerRequest req, HTTPServerResponse res) {
    res.writeJsonBody(iota(0, 1024).map!(a => Foo(a)).array);
}

Create a file with content like:

GET / HTTP/1.1
Host: 192.168.0.128
Content-Length: 0


Install netcat (tested on Fedora Linux 31) and run:

cat test.rest | nc --send-only 127.0.0.1 9090

--send-only causes:

Exception while handling request GET /api/v1/notifications?take=1000: object.Exception@../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/core/net.d(812): Connection closed while writing data.
----------------
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/core/net.d:812 @safe ulong vibe.core.net.TCPConnection.write(in ubyte[], eventcore.driver.IOMode) [0x95a686]
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/internal/interfaceproxy.d-mixin-314:314 @safe ulong vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.Stream).InterfaceProxy.ProxyImpl!(vibe.core.net.TCPConnection).ProxyImpl.__mixin8.__mixin3.__mixin3.__mixin3.__mixin3.__mixin3.__mixin2.write(void[], const(ubyte[]), eventcore.driver.IOMode) [0x869579]
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/internal/interfaceproxy.d-mixin-203:203 @safe ulong vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy.__mixin22.__mixin2.write(const(ubyte[]), eventcore.driver.IOMode) [0x925086]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/stream/vibe/stream/counting.d:191 @safe ulong vibe.stream.counting.CountingOutputStream.write(in ubyte[], eventcore.driver.IOMode) [0x943443]
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/core/stream.d:180 @safe void vibe.core.stream.OutputStream.write(in ubyte[]) [0x96565a]
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/internal/interfaceproxy.d-mixin-314:314 @safe void vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy.ProxyImpl!(vibe.internal.freelistref.FreeListRef!(vibe.stream.counting.CountingOutputStream, true).FreeListRef).ProxyImpl.__mixin8.__mixin2.write(void[], const(ubyte[])) [0x81cbdc]
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/internal/interfaceproxy.d-mixin-203:203 @safe void vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy.__mixin22.__mixin2.write(const(ubyte[])) [0x9250cd]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/stream/vibe/stream/wrapper.d:321 @safe void vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange.flush() [0x7d35f5]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/stream/vibe/stream/wrapper.d:333 @safe void vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange.put(ubyte) [0x7d3685]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/stream/vibe/stream/wrapper.d:354 @safe void vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange.put(char) [0x7d386e]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/data/vibe/data/json.d:1989 @safe void vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer.startCompositeEntry() [0x7d3cdb]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/data/vibe/data/json.d:1954 @safe void vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer.beginWriteArrayEntry!(vibe.data.serialization.SubTraits!(vibe.data.serialization.Traits!(app.Foo[], vibe.data.serialization.DefaultPolicy).Traits, app.Foo).SubTraits).beginWriteArrayEntry(ulong) [0x7d51a8]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/data/vibe/data/serialization.d:419 @safe void vibe.data.serialization.serializeValueImpl!(vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, vibe.data.serialization.DefaultPolicy).serializeValueDeduced!(app.Foo[]).serializeValueDeduced(ref vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, ref app.Foo[]) [0x7d5123]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/data/vibe/data/serialization.d:354 @safe void vibe.data.serialization.serializeValueImpl!(vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, vibe.data.serialization.DefaultPolicy).serializeValue!(app.Foo[]).serializeValue(ref vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, ref app.Foo[]) [0x7d50a8]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/data/vibe/data/serialization.d:205 @safe void vibe.data.serialization.serializeWithPolicy!(vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, vibe.data.serialization.DefaultPolicy, app.Foo[]).serializeWithPolicy(ref vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, ref app.Foo[]) [0x7d3e30]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/data/vibe/data/serialization.d:152 @safe void vibe.data.serialization.serialize!(vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, app.Foo[]).serialize(ref vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, ref app.Foo[]) [0x7d3e10]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/data/vibe/data/serialization.d:146 @safe void vibe.data.serialization.serialize!(vibe.data.json.JsonStringSerializer!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, false).JsonStringSerializer, app.Foo[], vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*).serialize(ref app.Foo[], vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*) [0x7d3de5]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/data/vibe/data/json.d:1463 @safe void vibe.data.json.serializeToJson!(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, app.Foo[]).serializeToJson(vibe.stream.wrapper.StreamOutputRange!(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.OutputStream).InterfaceProxy, 1024uL).StreamOutputRange*, ref app.Foo[]) [0x7d3c5c]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/server.d:1391 @safe void vibe.http.server.HTTPServerResponse.doWriteJsonBody!(app.Foo[], false).doWriteJsonBody(app.Foo[], bool) [0x7cdd0f]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/server.d:1357 @safe void vibe.http.server.HTTPServerResponse.writeJsonBody!(app.Foo[]).writeJsonBody(app.Foo[], bool) [0x7cdb66]
source/app.d:28 void app.test(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) [0x7c54e6]
/home/tomas/dlang/dmd-2.094.0/linux/bin64/../../src/phobos/std/functional.d-mixin-1616:1627 void std.functional.DelegateFaker!(void function(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse)*).DelegateFaker.doIt(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) [0x7ca5a7]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/router.d:274 @trusted void vibe.http.router.URLRouter.handlerDelegate!(void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse)).handlerDelegate(void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse)).__lambda3!(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse).__lambda3(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) [0x7cd244]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/router.d:218 @safe bool vibe.http.router.URLRouter.handleRequest(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse).__lambda4!(ulong, immutable(char)[][]).__lambda4(ulong, scope immutable(char)[][]) [0x7d99c3]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/router.d:674 const @safe bool vibe.http.router.MatchTree!(vibe.http.router.Route).MatchTree.doMatch(immutable(char)[], scope bool delegate(ulong, scope immutable(char)[][]) @safe) [0x7dc372]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/router.d:607 @safe bool vibe.http.router.MatchTree!(vibe.http.router.Route).MatchTree.match(immutable(char)[], scope bool delegate(ulong, scope immutable(char)[][]) @safe) [0x7dbb93]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/router.d:211 @safe void vibe.http.router.URLRouter.handleRequest(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) [0x7d9638]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/server.d:2287 @safe bool vibe.http.server.handleRequest(vibe.internal.interfaceproxy.InterfaceProxy!(vibe.core.stream.Stream).InterfaceProxy, vibe.core.net.TCPConnection, vibe.http.server.HTTPServerContext, ref vibe.http.server.HTTPServerSettings, ref bool, scope stdx.allocator.IAllocator) [0x8543b7]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/server.d:247 @trusted void vibe.http.server.handleHTTPConnection(vibe.core.net.TCPConnection, vibe.http.server.HTTPServerContext).__lambda4() [0x8525df]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/server.d:239 @safe void vibe.http.server.handleHTTPConnection(vibe.core.net.TCPConnection, vibe.http.server.HTTPServerContext) [0x8521f0]
../../../.dub/packages/vibe-d-0.9.2/vibe-d/http/vibe/http/server.d:2042 nothrow @safe void vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe).doListen(vibe.http.server.HTTPServerContext, bool, bool, bool, bool).__lambda6(vibe.core.net.TCPConnection) [0x7e6dfa]
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/core/task.d:703 void vibe.core.task.TaskFuncInfo.set!(void delegate(vibe.core.net.TCPConnection) @safe, vibe.core.net.TCPConnection).set(ref void delegate(vibe.core.net.TCPConnection) @safe, ref vibe.core.net.TCPConnection).callDelegate(ref vibe.core.task.TaskFuncInfo) [0x9a096a]
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/core/task.d:724 void vibe.core.task.TaskFuncInfo.call() [0x975d19]
../../../.dub/packages/vibe-core-1.10.2/vibe-core/source/vibe/core/task.d:433 nothrow void vibe.core.task.TaskFiber.run() [0x974fdf]
??:? void core.thread.context.Callable.opCall() [0xa1c694]
??:? fiber_entryPoint [0xa7b267]

And each of this requests ads one FD to this output:

> sudo lsof -a -p (pidof test) | grep "protocol: TCP"
test    918373 tomas   11u     sock                0,8      0t0 63554744 protocol: TCPv6
test    918373 tomas   12u     sock                0,8      0t0 63554752 protocol: TCPv6
test    918373 tomas   20u     sock                0,8      0t0 63554753 protocol: TCPv6

Normal requests closes client FD on the server correctly.

Found this with some buggy client that closed request too early, but can easily happen ie with timeout on the client side.

tchaloupka added a commit to tchaloupka/vibe.d that referenced this issue Oct 16, 2020
tchaloupka added a commit to tchaloupka/vibe.d that referenced this issue Oct 16, 2020
tchaloupka added a commit to tchaloupka/vibe.d that referenced this issue Oct 19, 2020
s-ludwig added a commit that referenced this issue Oct 25, 2020
Fix #2484 - clear  `m_fill` on flush exception
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant