From a7cf4a3fbc3af348f749e3197ba985eb54dec76a Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 13 Jun 2024 17:37:11 +0200 Subject: [PATCH] src: return non-empty data in context data serializer For pointer values in the context data, we need to return non-empty data in the serializer so that V8 does not serialize them verbatim, making the snapshot unreproducible. PR-URL: https://github.com/nodejs/node/pull/50983 Refs: https://github.com/nodejs/build/issues/3043 Reviewed-By: Daniel Lemire Reviewed-By: James M Snell --- src/node_snapshotable.cc | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index ec01c2d0d5ac18..aefd479b83cd05 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -1262,18 +1262,30 @@ void DeserializeNodeContextData(Local holder, int index, StartupData payload, void* callback_data) { - // This is unreachable for now. We will reset all the pointers in - // Environment::AssignToContext() via the realm constructor. - UNREACHABLE(); + // We will reset all the pointers in Environment::AssignToContext() + // via the realm constructor. + switch (index) { + case ContextEmbedderIndex::kEnvironment: + case ContextEmbedderIndex::kContextifyContext: + case ContextEmbedderIndex::kRealm: + case ContextEmbedderIndex::kContextTag: { + uint64_t index_64; + int size = sizeof(index_64); + CHECK_EQ(payload.raw_size, size); + memcpy(&index_64, payload.data, payload.raw_size); + CHECK_EQ(index_64, static_cast(index)); + break; + } + default: + UNREACHABLE(); + } } StartupData SerializeNodeContextData(Local holder, int index, void* callback_data) { - // For now we just reset all of them in Environment::AssignToContext(). - // We return empty data here to make sure that the embedder data serialized - // into the snapshot is reproducible and V8 doesn't have to try to serialize - // the pointer values that won't be useful during deserialization. + // For pointer values, we need to return some non-empty data so that V8 + // does not serialize them verbatim, making the snapshot unreproducible. switch (index) { case ContextEmbedderIndex::kEnvironment: case ContextEmbedderIndex::kContextifyContext: @@ -1286,7 +1298,13 @@ StartupData SerializeNodeContextData(Local holder, static_cast(index), *holder, data); - return {nullptr, 0}; + // We use uint64_t to avoid padding. + uint64_t index_64 = static_cast(index); + // It must be allocated with new[] because V8 will call delete[] on it. + size_t size = sizeof(index_64); + char* startup_data = new char[size]; + memcpy(startup_data, &index_64, size); + return {startup_data, static_cast(size)}; } default: UNREACHABLE();