diff --git a/src/crypto/crypto_hash.cc b/src/crypto/crypto_hash.cc index f9f5e18f2b106a..5aff90cd9587ff 100644 --- a/src/crypto/crypto_hash.cc +++ b/src/crypto/crypto_hash.cc @@ -1,6 +1,8 @@ #include "crypto/crypto_hash.h" #include "async_wrap-inl.h" #include "base_object-inl.h" +#include "cppgc/allocation.h" +#include "cppgc_helpers-inl.h" #include "env-inl.h" #include "memory_tracker-inl.h" #include "string_bytes.h" @@ -31,14 +33,23 @@ using v8::Object; using v8::Uint32; using v8::Value; +#ifdef ASSIGN_OR_RETURN_UNWRAP +#undef ASSIGN_OR_RETURN_UNWRAP +#endif + +#define ASSIGN_OR_RETURN_UNWRAP ASSIGN_OR_RETURN_UNWRAP_CPPGC namespace crypto { -Hash::Hash(Environment* env, Local wrap) : BaseObject(env, wrap) { - MakeWeak(); +Hash::Hash(Environment* env, Local wrap) { + CppgcMixin::Wrap(this, env, wrap); +} + +void Hash::Trace(cppgc::Visitor* visitor) const { + CppgcMixin::Trace(visitor); } void Hash::MemoryInfo(MemoryTracker* tracker) const { - tracker->TrackFieldWithSize("mdctx", mdctx_ ? kSizeOf_EVP_MD_CTX : 0); - tracker->TrackFieldWithSize("md", digest_ ? md_len_ : 0); + tracker->TrackFieldWithSize("mdctx", mdctx_ ? kSizeOf_EVP_MD_CTX : 0, "EVP_MD_CTX"); + tracker->TrackFieldWithSize("md", digest_ ? md_len_ : 0, "ByteSource"); } #if OPENSSL_VERSION_MAJOR >= 3 @@ -312,7 +323,8 @@ void Hash::New(const FunctionCallbackInfo& args) { xof_md_len = Just(args[1].As()->Value()); } - Hash* hash = new Hash(env, args.This()); + Hash* hash = cppgc::MakeGarbageCollected( + env->isolate()->GetCppHeap()->GetAllocationHandle(), env, args.This()); if (md == nullptr || !hash->HashInit(md, xof_md_len)) { return ThrowCryptoError(env, ERR_get_error(), "Digest method not supported"); diff --git a/src/crypto/crypto_hash.h b/src/crypto/crypto_hash.h index 0a839733cc156e..a28506f0be53d2 100644 --- a/src/crypto/crypto_hash.h +++ b/src/crypto/crypto_hash.h @@ -3,7 +3,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS -#include "base_object.h" +#include "cppgc_helpers.h" #include "crypto/crypto_keys.h" #include "crypto/crypto_util.h" #include "env.h" @@ -12,15 +12,16 @@ namespace node { namespace crypto { -class Hash final : public BaseObject { + +class Hash final : CPPGC_MIXIN(Hash) { public: + SET_CPPGC_NAME(Hash) + void Trace(cppgc::Visitor* visitor) const final; + void MemoryInfo(MemoryTracker* tracker) const override; + static void Initialize(Environment* env, v8::Local target); static void RegisterExternalReferences(ExternalReferenceRegistry* registry); - void MemoryInfo(MemoryTracker* tracker) const override; - SET_MEMORY_INFO_NAME(Hash) - SET_SELF_SIZE(Hash) - bool HashInit(const EVP_MD* md, v8::Maybe xof_md_len); bool HashUpdate(const char* data, size_t len); @@ -28,13 +29,13 @@ class Hash final : public BaseObject { static void GetCachedAliases(const v8::FunctionCallbackInfo& args); static void OneShotDigest(const v8::FunctionCallbackInfo& args); + Hash(Environment* env, v8::Local wrap); + protected: static void New(const v8::FunctionCallbackInfo& args); static void HashUpdate(const v8::FunctionCallbackInfo& args); static void HashDigest(const v8::FunctionCallbackInfo& args); - Hash(Environment* env, v8::Local wrap); - private: ncrypto::EVPMDCtxPointer mdctx_{}; unsigned int md_len_ = 0; diff --git a/src/crypto/crypto_util.h b/src/crypto/crypto_util.h index 4842bf0e4c791e..c896ee544f845a 100644 --- a/src/crypto/crypto_util.h +++ b/src/crypto/crypto_util.h @@ -4,6 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "async_wrap.h" +#include "cppgc_helpers.h" #include "env.h" #include "node_errors.h" #include "node_external_reference.h" @@ -57,7 +58,12 @@ void Decode(const v8::FunctionCallbackInfo& args, void (*callback)(T*, const v8::FunctionCallbackInfo&, const char*, size_t)) { T* ctx; - ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); + if constexpr (std::is_base_of_v) { + ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This()); + } else { + ctx = CppgcMixin::Unwrap(args.This()); + if (ctx == nullptr) return; + } if (args[0]->IsString()) { StringBytes::InlineDecoder decoder; diff --git a/test/pummel/test-heapdump-hash.js b/test/pummel/test-heapdump-hash.js new file mode 100644 index 00000000000000..3a80c0e8b74295 --- /dev/null +++ b/test/pummel/test-heapdump-hash.js @@ -0,0 +1,33 @@ +'use strict'; +require('../common'); +const { validateByRetainingPath } = require('../common/heap'); +const { createHash } = require('crypto'); +const assert = require('assert'); + +// In case the bootstrap process creates any Hash objects, capture a snapshot first +// and save the initial length. +const originalNodes = validateByRetainingPath('Node / Hash', [ + { edge_name: 'mdctx' }, +], true); + +const count = 5; +const arr = []; +for (let i = 0; i < count; ++i) { + arr.push(createHash('sha1')); +} + +const nodesWithCtx = validateByRetainingPath('Node / Hash', [ + { edge_name: 'mdctx', node_name: 'Node / EVP_MD_CTX' }, +]); + +assert.strictEqual(nodesWithCtx.length - originalNodes.length, count); + +for (let i = 0; i < count; ++i) { + arr[i].update('test').digest('hex'); +} + +const nodesWithDigest = validateByRetainingPath('Node / Hash', [ + { edge_name: 'md', node_name: 'Node / ByteSource' }, +]); + +assert.strictEqual(nodesWithDigest.length - originalNodes.length, count);