Skip to content

Flooding requests results in memory leak #43548

Closed
@nitcord

Description

@nitcord

Version

v16.15.1

Platform

Linux DNSBox 5.15.0-39-generic #42-Ubuntu SMP Thu Jun 9 23:42:32 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

Subsystem

HTTP

What steps will reproduce the bug?

1. Run the code below using node without requiring any additional dependencies

const fs = require('fs');
const http = require('http');

const app = (req, res) => {
  res.end(JSON.stringify({
    message: 'Hello World!'
  }));
};

const httpServer = http.createServer(app);

httpServer.listen(80, () => {
    console.log('HTTP Server running on port 80');
});

2. Use this site to stress-test the server using the following configuration below.

Type: Layer 7
Target URL: ...
Duration (Seconds): 300
Network (Power): Basic (1 Thread)
Request Type: GET
Attack Method: HTTP/s (SPAM)

How often does it reproduce? Is there a required condition?

You might have to run the test twice for it to take effect but you have to wait for the current test to finish before sending another one. After all of the tests are complete, the server will get a lot of MaxListenersExceededWarning errors and will eventually crash because it will reach the memory limit.

What is the expected behavior?

It shouldn't show a memory leak error and should just continue the requests as normal.

What do you see instead?

(node:16418) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 error listeners added to [TLSSocket]. Use emitter.setMaxListeners() to increase limit
    at _addListener (node:events:601:17)
    at TLSSocket.addListener (node:events:619:10)
    at TLSSocket.Readable.on (node:internal/streams/readable:875:35)
    at TLSSocket.socketListenerWrap [as on] (node:_http_server:1007:54)
    at TLSSocket.socketOnError (node:_http_server:672:8)
    at onParserExecuteCommon (node:_http_server:702:19)
    at onParserExecute (node:_http_server:646:3)

Additional information

Source

What I have debugged so far in Node.js is that the case seems to be a flaw in the logic of that internal socketOnError function. When it is called, it removes itself from the list of error listeners and then adds a new error listener, noop. It seems that at some point, that listener was the only way socketOnError was invoked. But you will find in their code there are now multiple places in which socketOnError is invoked, and removing that error listener doesn't stop them all. Additional invokations for the same socket keep adding that noop listener, and the state at which the warning happens, there are 10 noop listeners on the socket, and the warning happens when the 11th noop listener is added.

Metadata

Metadata

Assignees

No one assigned

    Labels

    httpIssues or PRs related to the http subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions