Skip to content

http: fix http server connection list when close#43949

Merged
nodejs-github-bot merged 1 commit intonodejs:mainfrom
theanarkh:fix_server_connection_list
Jul 24, 2022
Merged

http: fix http server connection list when close#43949
nodejs-github-bot merged 1 commit intonodejs:mainfrom
theanarkh:fix_server_connection_list

Conversation

@theanarkh
Copy link
Copy Markdown
Contributor

@theanarkh theanarkh commented Jul 22, 2022

Refs: Failed CI
Refs: Failed CI
Refs: #43638 (comment)

When the socket close, the related parser should be removed out of the server connection list.

When the socket close, the related parser will be cleared(_http_server.js:socketOnClose -> freeParser), the related code of freeParser is as follows.

cleanParser(parser);
if (parsers.free(parser) === false) {
    setImmediate(closeParserInstance, parser);
} else {
    parser.free();
}

cleanParser(parser) make the socket.parser is null, and if parsers.free(parser) is true anything is ok because it will remove the parser out of server.connectionList. But if it is false it will trigger bugs.

  1. If the user listen to close event of socket and call server.close in the callback of close event, the server.close will call closeIdleConnections to close all idle sockets, the code is as follows.
Server.prototype.closeIdleConnections = function() {
    const connections = this[kConnections].idle();
    for (let i = 0, l = connections.length; i < l; i++) {
        if (connections[i].socket._httpMessage && !connections[i].socket._httpMessage.finished) {
          continue;
        }
    }
};

connections[i] is a parser object, and parser.socket is null which make the bug(Cannot read properties of null (reading '_httpMessage')).

  1. If user call the code as follows in callback of close event
setImmediate(() => {
    server.close();
});

it will make the process crashed because when closeParserInstance in setImmediate(closeParserInstance, parser); is called, it will delete the C++ parser object. Then Node.js will call the second callback(() => { server.close(); }) of setImmediate, server.close() will call this[kConnections].idle() which will access C++ layer to get the parser list, but the parser is delete so make the process crashed. The codedump is as follows.

    frame #0: 0x0000000101cf0498 node`v8::internal::JSObject::AddDataElement(v8::internal::Handle<v8::internal::JSObject>, unsigned int, v8::internal::Handle<v8::internal::Object>, v8::internal::PropertyAttributes) [inlined] v8::internal::Handle<v8::internal::Object>::operator*(this=<unavailable>) const at handles.h:141:37 [opt]
    frame #1: 0x0000000101cf0498 node`v8::internal::JSObject::AddDataElement(v8::internal::Handle<v8::internal::JSObject>, unsigned int, v8::internal::Handle<v8::internal::Object>, v8::internal::PropertyAttributes) [inlined] v8::internal::Handle<v8::internal::Object>::operator->(this=<unavailable>) const at handles.h:135 [opt]
    frame #2: 0x0000000101cf0498 node`v8::internal::JSObject::AddDataElement(object=Handle<v8::internal::JSObject> @ 0x00007ffeee585a28, index=<unavailable>, value=<unavailable>, attributes=NONE) at js-objects.cc:5194 [opt]
    frame #3: 0x0000000101d535f2 node`v8::internal::Object::AddDataProperty(it=0x00007ffeee585ae0, value=<unavailable>, attributes=<unavailable>, should_throw=(has_value_ = true, value_ = kDontThrow), store_origin=<unavailable>, semantics=<unavailable>) at objects.cc:2914:5 [opt]
    frame #4: 0x00000001018c5efc node`v8::Object::Set(v8::Local<v8::Context>, unsigned int, v8::Local<v8::Value>) [inlined] v8::internal::Object::SetElement(isolate=<unavailable>, object=Handle<v8::internal::Object> @ r15, index=<unavailable>, value=Handle<v8::internal::Object> @ r14, should_throw=kDontThrow) at objects-inl.h:657:3 [opt]
    frame #5: 0x00000001018c5ec1 node`v8::Object::Set(this=0x00007fb667814658, context=<unavailable>, index=<unavailable>, value=(val_ = 0x0000000000000000)) at api.cc:4282 [opt]
    frame #6: 0x000000010176499c node`node::(anonymous namespace)::ConnectionsList::Idle(args=0x00007ffeee585c50) at node_http_parser.cc:1065:17 [opt]
    frame #7: 0x000000010191c228 node`v8::internal::FunctionCallbackArguments::Call(this=0x00007ffeee585ca8, handler=<unavailable>) at api-arguments-inl.h:147:3 [opt]
    frame #8: 0x000000010191bd42 node`v8::internal::MaybeHandle<v8::internal::Object> v8::internal::(anonymous namespace)::HandleApiCallHelper<false>(isolate=0x00007fb66752b000, function=<unavailable>, new_target=<unavailable>, fun_data=Handle<v8::internal::FunctionTemplateInfo> @ r13, receiver=<unavailable>, args=BuiltinArguments @ 0x00007ffeee585d50) at builtins-api.cc:112:36 [opt]
    frame #9: 0x000000010191b38f node`v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) at builtins-api.cc:142:5 [opt]
    frame #10: 0x000000010191b2aa node`v8::internal::Builtin_HandleApiCall(args_length=<unavailable>, args_object=0x00007ffeee585e00, isolate=0x00007fb66752b000) at builtins-api.cc:130 [opt]
    frame #11: 0x000000010225d479 node`Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit + 57
    frame #12: 0x00000001021e13d0 node`Builtins_InterpreterEntryTrampoline + 208
    frame #13: 0x00000001021e13d0 node`Builtins_InterpreterEntryTrampoline + 208
    frame #14: 0x00000001021e13d0 node`Builtins_InterpreterEntryTrampoline + 208
    frame #15: 0x00000001021e13d0 node`Builtins_InterpreterEntryTrampoline + 208
    frame #16: 0x00000001021df9dc node`Builtins_JSEntryTrampoline + 92
    frame #17: 0x00000001021df703 node`Builtins_JSEntry + 131
    frame #18: 0x00000001019e68bc node`v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) [inlined] v8::internal::GeneratedCode<unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, long, unsigned long**>::Call(this=<unavailable>, args=<unavailable>, args=<unavailable>, args=<unavailable>, args=<unavailable>, args=<unavailable>, args=<unavailable>) at simulator.h:156:12 [opt]
    frame #19: 0x00000001019e68b9 node`v8::internal::(anonymous namespace)::Invoke(isolate=0x00007fb66752b000, params=0x00007ffeee586190)::InvokeParams const&) at execution.cc:425 [opt]
    frame #20: 0x00000001019e5ca5 node`v8::internal::Execution::Call(isolate=0x00007fb66752b000, callable=<unavailable>, receiver=<unavailable>, argc=0, argv=0x0000000000000000) at execution.cc:523:10 [opt]
    frame #21: 0x00000001018cc5f9 node`v8::Function::Call(this=0x00007fb66783a520, context=<unavailable>, recv=<unavailable>, argc=<unavailable>, argv=0x0000000000000000) at api.cc:5255:7 [opt]
    frame #22: 0x000000010167af2f node`node::InternalMakeCallback(env=0x00007fb66814e600, resource=(val_ = 0x00007fb66783a600), recv=<unavailable>, callback=<unavailable>, argc=0, argv=0x0000000000000000, asyncContext=(async_id = 0, trigger_async_id = 0)) at callback.cc:211:21 [opt]
    frame #23: 0x000000010167b33c node`node::MakeCallback(isolate=0x00007fb66752b000, recv=(val_ = 0x00007fb66783a600), callback=(val_ = 0x00007fb66783a520), argc=0, argv=0x0000000000000000, asyncContext=(async_id = 0, trigger_async_id = 0)) at callback.cc:282:7 [opt]
    frame #24: 0x00000001016e8645 node`node::Environment::CheckImmediate(handle=<unavailable>) at env.cc:1331:5 [opt]
    frame #25: 0x00000001021c87c4 node`uv__run_check(loop=0x00000001053cb630) at loop-watcher.c:67:1 [opt]
    frame #26: 0x00000001021c1d31 node`uv_run(loop=0x00000001053cb630, mode=UV_RUN_DEFAULT) at core.c:398:5 [opt]
    frame #27: 0x000000010167b743 node`node::SpinEventLoop(env=0x00007fb66814e600) at embed_helpers.cc:37:7 [opt]
    frame #28: 0x00000001017879e1 node`node::NodeMainInstance::Run(this=<unavailable>, exit_code=0x00007ffeee5866fc, env=0x00007fb66814e600) at node_main_instance.cc:140:18 [opt]
    frame #29: 0x0000000101787653 node`node::NodeMainInstance::Run(this=<unavailable>) at node_main_instance.cc:132:3 [opt]
    frame #30: 0x00000001017170c6 node`node::Start(argc=<unavailable>, argv=<unavailable>) at node.cc:1199:38 [opt]
    frame #31: 0x00007fff205fe621 libdyld.dylib`start + 1
    frame #32: 0x00007fff205fe621 libdyld.dylib`start + 1

cc @ShogunPanda

  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author ready PRs that have at least one approval, no pending requests for changes, and a CI started. c++ Issues and PRs that require attention from people who are familiar with C++. fast-track PRs that do not need to wait for 72 hours to land. http_parser Issues and PRs related to the HTTP Parser dependency or the http_parser binding. http Issues or PRs related to the http subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants