Skip to content

http2 server gc cause crash when header COMPRESSION_ERROR #39844

@fishioon

Description

@fishioon

Version

v16.6.1 / v14

Platform

macOS/linux

Subsystem

No response

What steps will reproduce the bug?

// ######### server.js
const http2 = require('http2')
const fs = require('fs')

const server = http2.createSecureServer({
  cert: `-----BEGIN CERTIFICATE-----\nMIIEbTCCA1WgAwIBAgIJAKiByS0TJ9MaMA0GCSqGSIb3DQEBCwUAMIGFMQswCQYDVQQGEwJDTjESMBAGA1UECAwJR3VhbmdEb25nMREwDwYDVQQHDAhTaGVuemhlbjEQMA4GA1UECgwHVGVuY2VudDEQMA4GA1UECwwHVGVuY2VudDELMAkGA1UEAwwCY2ExHjAcBgkqhkiG9w0BCQEWD3Jpb0B0ZW5jZW50LmNvbTAeFw0yMTA4MDYwNzIxMDFaFw0yNjA4MzAwNzIxMDFaMIGLMQswCQYDVQQGEwJDTjESMBAGA1UECAwJR3VhbmdEb25nMREwDwYDVQQHDAhTaGVuemhlbjEQMA4GA1UECgwHVGVuY2VudDEQMA4GA1UECwwHVGVuY2VudDERMA8GA1UEAwwIdGVzdC5jb20xHjAcBgkqhkiG9w0BCQEWD3Jpb0B0ZW5jZW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANVSIyHDQ6UZ9+eLjm/dlTA9Rg81f0gS1s7+B2n/cpA70DNAdCmOR4Oh1rUJ5C72V8LIJ6gxqjVby5jghSJ3IwYQQiJS2qHxhlEZjHzUAYBaf6Vizx8/0Koab4FIv2yMWF1WsrN+oBbWLC8co2rWZuYgLR/f4nS7x70KGmWFnfBjfbqAlDtA9MBEuH/1znk+ZsQaYtGqLd90mJ+iBdoH/11WJrp0fWntpjR+4xZbDq/bxT+83sXXqEVMDWTrDK1PCrFCRn86Zpbf+ndimSZIF9axZ815xrOyL7NOvlwU+6GGAIZTb5HA8Mk1eeCa28hFUpmZdOff9CyS7Lny7Z52LKkCAwEAAaOB1zCB1DCBpAYDVR0jBIGcMIGZoYGLpIGIMIGFMQswCQYDVQQGEwJDTjESMBAGA1UECAwJR3VhbmdEb25nMREwDwYDVQQHDAhTaGVuemhlbjEQMA4GA1UECgwHVGVuY2VudDEQMA4GA1UECwwHVGVuY2VudDELMAkGA1UEAwwCY2ExHjAcBgkqhkiG9w0BCQEWD3Jpb0B0ZW5jZW50LmNvbYIJANr1uGDtKAaHMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTwMBMGA1UdEQQMMAqCCHRlc3QuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCRcq4s46jzQ89lvIVztxi1SvDMdldL+TbQCFKRyzzpawMVxTzZ3/NUl4JfaTO5RNIPpTvTHKp+lZz3UnHmARw5ykxDv95BvaEX0fGu4yml9U8uJLBQlBLAWMp2hUveVXIH4lub0BM+i4J05yVXCYg9sxBnNtxowtJhflIJjQudYkZzcGtmuen29Wzk0LJmN89Log1p2z1/cRi6rFjrZ4YrzMekxifivT6w1S/RoUXhdHoaIYxvqr33q26V5AymNbto66HkIxp/U6pfypvbbyvUMZIwtIjNdKH0oeL5sE6Ot/RbQ17qSWXVBI4etG6BCnckzXOMLsJKo2ME70XLVpeS\n-----END CERTIFICATE-----`,
  key: `-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA1VIjIcNDpRn354uOb92VMD1GDzV/SBLWzv4Haf9ykDvQM0B0KY5Hg6HWtQnkLvZXwsgnqDGqNVvLmOCFIncjBhBCIlLaofGGURmMfNQBgFp/pWLPHz/QqhpvgUi/bIxYXVays36gFtYsLxyjatZm5iAtH9/idLvHvQoaZYWd8GN9uoCUO0D0wES4f/XOeT5mxBpi0aot33SYn6IF2gf/XVYmunR9ae2mNH7jFlsOr9vFP7zexdeoRUwNZOsMrU8KsUJGfzpmlt/6d2KZJkgX1rFnzXnGs7Ivs06+XBT7oYYAhlNvkcDwyTV54JrbyEVSmZl059/0LJLsufLtnnYsqQIDAQABAoIBAAjBgFOociRatoQ4hDYvQCpkuXVyWrEYpNyGLMO7CnbFHbyczqfOAT1z7R4tM8KBtgR2trn+n9/kzqyNuqk5fqSHEk/aWsL+6OZ3R/7vrMgZ7tdZAOtlcSkqQJ1r4P+RmybpohggAG4viEy+vi5qcnrLo06FoAPumTo3KfI009DEEXplp+zVgAfNb68t+G7kOz9N/ijroSSEE7YkY8fnjoo3WUzhZXCMWrYanVAmFCyqGmd8ZPg9HwMHy0EkZfosyMA2fc9X0RjK9QCVvBgQtEyXBD6abRVmaVHAzJP3ejUKygFL5cDd0qcjOFFha3N+Ew177k9+jAV7m5/hJiY3eAECgYEA76liaNZgCMfDVtWpT4KoVUetdY92rlva2BRpR8VjSiUwZ8VC60Qqqu4j0CS9EvmUv6L47lBUYTt484ppNp++pH18bnG2bSQ6no0FJv+55x6j0nRc7OI/ycZ9bYwbj22QKDYI0f5ugwHb0OLnQOPDnr0KNhfYhUQkLMvh05WY3ykCgYEA490McA7m7iF6Y1HTeuJY9SubCemGelx3R6kYM96mwl+/ZFYyrrP2D8mPeLM+yQMla9xzkyKErmAo6i5JlLay87ddupESfj5Mfgdqg64wIV54eNWHFlxwbSRiUbDxyvCtaw2vAyQ0+QMgnI/nTAHdAuR1wpQusDCazU1Zzog8EYECgYEA2wS8/noLQXrttUmFdTg+hdD/YFQ/bZBcKuRcYk6tMnFSD0NiqIafR55h9DHe6JxVp9xUCdY3hrRHEKoJBPZvzvsu3+/je1KEj6jocH97cQ+7PvVAhussyEUxEw/bj/PcriLTZLVUYT0tmXQDSnXbrBGuZ0jbgs6HELkyI56vGiECgYEAwL9CfyPL6lF9YrhbyM3g6/rn2dmlPKos5/w8kdvcef1eO7TCiI+ILFCWwUX2bTjxFa1UQnjnfU2wLm/bJCXreEd6zI9c8lcmg1Eoo5zb784m4CfXbm3hWCF33Zxs2/r85tqbWW/uM1mW43jC8cN9va2dg2uvlrB2sgWlWxRYo4ECgYEAyjQv4tuMGj2yc8Ufq65Zz1kmJ/aM5b6HKEV6llTwCi++Zw0jhg/XpY4zpQfiMXaYeK0Vd+HCndRXMK/B4uXKL99ZLVT+DZOOcZcqGXO1bHz2imjr624nhYem3wgL7hkFSAeVj5lSamgkcQkdOQmbqFmX6w5mJq54PGRrnixy33Q=\n-----END RSA PRIVATE KEY-----`,
})

server.timeout = 1000

server.on('error', err => {
  console.log('server error', err)
})

server.on('session', session => {
  session.on('error', err => {
    console.log('session error', err)
  })
  session.on('close', () => {
    console.log('session close')
    // if HEAD_SIZE >= 87382 or COMPRESSION_ERROR , then gc() cause crash
    gc()
  })
})

server.on('stream', (stream, headers) => {
  // stream is a Duplex
  console.log('headers', headers['a'].length)
  stream.respond({
    'content-type': 'text/html; charset=utf-8',
    ':status': 200
  })
  stream.end('<h1>Hello World</h1>')
})

server.listen(8443)

// ########### test.js
const tls = require('tls');

const SERVER = {
  host: '127.0.0.1',
  port: 8443,
}

const pack = [
  // Magic
  //  PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n
  '505249202a20485454502f322e300d0a0d0a534d0d0a0d0a',
  // SETTINGS
  '000000040000000000',
  // HEADERS
  '00001b010500000001',
    //  :path /
    '84',
    //  :scheme https
    '87',
    //  :authority 127.0.0.1:8443
    '418a089d5c0b8170dc79e7df',
    //  :method GET
    '82',
    // Representation: Literal Header Field with Incremental Indexing - New Name
    //  a: AAAAAAAAAA
    // Error: COMPRESSION_ERROR (9)
    // correct data: 40016188861861861861861f
    '40066188861861861861861f',
]

async function main() {
  const socket = await connect();
  const buf = Buffer.from(pack.join(''), 'hex');
  console.log(buf);
  socket.write(buf);
}

function connect() {
  return new Promise((resolve, reject) => {
    const socket = tls.connect(Object.assign({
      ALPNProtocols: ['h2'],
      rejectUnauthorized: false
    }, SERVER), () => resolve(socket));
    socket.on('error', reject);
  });
}

main();

// node --expose-gc server.js
// node test.js

node[82270]: ../src/node_http2.cc:525:virtual node::http2::Http2Session::~Http2Sessi
on(): Assertion `(current_nghttp2_memory_) == (0)' failed.
1: 0x10faf9a68 node::Abort() [/usr/local/bin/node]
2: 0x10faf98b6 node::AppendExceptionLine(node::Environment*, v8::Localv8::Value,
v8::Localv8::Message, node::ErrorHandlingMode) [/usr/local/bin/node]
3: 0x10fb16b7e node::http2::Http2Session::~Http2Session() [/usr/local/bin/node]
4: 0x10fb16ba4 node::http2::Http2Session::~Http2Session() [/usr/local/bin/node]
5: 0x10fd43de7 unsigned long v8::internal::GlobalHandles::InvokeFirstPassWeakCallba
cksv8::internal::GlobalHandles::Node(std::__1::vector<std::1::pair<v8::internal:
:GlobalHandles::Node*, v8::internal::GlobalHandles::PendingPhantomCallback>, std::

1::allocator<std::__1::pair<v8::internal::GlobalHandles::Node*, v8::internal::Global
Handles::PendingPhantomCallback> > >) [/usr/local/bin/node]
6: 0x10fd43d5d v8::internal::GlobalHandles::InvokeFirstPassWeakCallbacks() [/usr/lo
cal/bin/node]
7: 0x10fd73c11 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCo
llector, v8::GCCallbackFlags) [/usr/local/bin/node]
8: 0x10fd72249 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8
::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
9: 0x10fd730a3 v8::internal::Heap::PreciseCollectAllGarbage(int, v8::internal::Garb
ageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
10: 0x10fc7eba3 v8::internal::FunctionCallbackArguments::Call(v8::internal::CallHand
lerInfo) [/usr/local/bin/node]
11: 0x10fc7e392 v8::internal::MaybeHandlev8::internal::Object v8::internal::(anony
mous namespace)::HandleApiCallHelper(v8::internal::Isolate
, v8::internal::Ha
ndlev8::internal::HeapObject, v8::internal::Handlev8::internal::HeapObject, v8::
internal::Handlev8::internal::FunctionTemplateInfo, v8::internal::Handle<v8::inter
nal::Object>, v8::internal::BuiltinArguments) [/usr/local/bin/node]
12: 0x10fc7db9a v8::internal::Builtin_Impl_HandleApiCall(v8::internal::BuiltinArgume
nts, v8::internal::Isolate*) [/usr/local/bin/node]
13: 0x11026d9d9 Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_BuiltinExit [/usr
/local/bin/node]

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

No response

What is the expected behavior?

No crash

What do you see instead?

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    http2Issues or PRs related to the http2 subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions