Skip to content

Commit 9ef7a8b

Browse files
committed
crypto: use cppgc to manage Hash
1 parent b3d479e commit 9ef7a8b

File tree

5 files changed

+86
-27
lines changed

5 files changed

+86
-27
lines changed

src/crypto/crypto_hash.cc

+17-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "crypto/crypto_hash.h"
22
#include "async_wrap-inl.h"
33
#include "base_object-inl.h"
4+
#include "cppgc/allocation.h"
5+
#include "cppgc_helpers-inl.h"
46
#include "env-inl.h"
57
#include "memory_tracker-inl.h"
68
#include "string_bytes.h"
@@ -31,14 +33,23 @@ using v8::Object;
3133
using v8::Uint32;
3234
using v8::Value;
3335

36+
#ifdef ASSIGN_OR_RETURN_UNWRAP
37+
#undef ASSIGN_OR_RETURN_UNWRAP
38+
#endif
39+
40+
#define ASSIGN_OR_RETURN_UNWRAP ASSIGN_OR_RETURN_UNWRAP_CPPGC
3441
namespace crypto {
35-
Hash::Hash(Environment* env, Local<Object> wrap) : BaseObject(env, wrap) {
36-
MakeWeak();
42+
Hash::Hash(Environment* env, Local<Object> wrap) {
43+
CppgcMixin::Wrap(this, env, wrap);
44+
}
45+
46+
void Hash::Trace(cppgc::Visitor* visitor) const {
47+
CppgcMixin::Trace(visitor);
3748
}
3849

3950
void Hash::MemoryInfo(MemoryTracker* tracker) const {
40-
tracker->TrackFieldWithSize("mdctx", mdctx_ ? kSizeOf_EVP_MD_CTX : 0);
41-
tracker->TrackFieldWithSize("md", digest_ ? md_len_ : 0);
51+
tracker->TrackFieldWithSize("mdctx", mdctx_ ? kSizeOf_EVP_MD_CTX : 0, "EVP_MD_CTX");
52+
tracker->TrackFieldWithSize("md", digest_ ? md_len_ : 0, "ByteSource");
4253
}
4354

4455
#if OPENSSL_VERSION_MAJOR >= 3
@@ -322,7 +333,8 @@ void Hash::New(const FunctionCallbackInfo<Value>& args) {
322333
xof_md_len = Just<unsigned int>(args[1].As<Uint32>()->Value());
323334
}
324335

325-
Hash* hash = new Hash(env, args.This());
336+
Hash* hash = cppgc::MakeGarbageCollected<Hash>(
337+
env->isolate()->GetCppHeap()->GetAllocationHandle(), env, args.This());
326338
if (md == nullptr || !hash->HashInit(md, xof_md_len)) {
327339
return ThrowCryptoError(env, ERR_get_error(),
328340
"Digest method not supported");

src/crypto/crypto_hash.h

+9-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

6-
#include "base_object.h"
6+
#include "cppgc_helpers.h"
77
#include "crypto/crypto_keys.h"
88
#include "crypto/crypto_util.h"
99
#include "env.h"
@@ -12,29 +12,30 @@
1212

1313
namespace node {
1414
namespace crypto {
15-
class Hash final : public BaseObject {
15+
16+
class Hash final : CPPGC_MIXIN(Hash) {
1617
public:
18+
SET_CPPGC_NAME(Hash)
19+
void Trace(cppgc::Visitor* visitor) const final;
20+
void MemoryInfo(MemoryTracker* tracker) const override;
21+
1722
static void Initialize(Environment* env, v8::Local<v8::Object> target);
1823
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
1924

20-
void MemoryInfo(MemoryTracker* tracker) const override;
21-
SET_MEMORY_INFO_NAME(Hash)
22-
SET_SELF_SIZE(Hash)
23-
2425
bool HashInit(const EVP_MD* md, v8::Maybe<unsigned int> xof_md_len);
2526
bool HashUpdate(const char* data, size_t len);
2627

2728
static void GetHashes(const v8::FunctionCallbackInfo<v8::Value>& args);
2829
static void GetCachedAliases(const v8::FunctionCallbackInfo<v8::Value>& args);
2930
static void OneShotDigest(const v8::FunctionCallbackInfo<v8::Value>& args);
3031

32+
Hash(Environment* env, v8::Local<v8::Object> wrap);
33+
3134
protected:
3235
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
3336
static void HashUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
3437
static void HashDigest(const v8::FunctionCallbackInfo<v8::Value>& args);
3538

36-
Hash(Environment* env, v8::Local<v8::Object> wrap);
37-
3839
private:
3940
ncrypto::EVPMDCtxPointer mdctx_{};
4041
unsigned int md_len_ = 0;

src/crypto/crypto_util.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

66
#include "async_wrap.h"
7+
#include "cppgc_helpers.h"
78
#include "env.h"
89
#include "node_errors.h"
910
#include "node_external_reference.h"
@@ -74,7 +75,12 @@ void Decode(const v8::FunctionCallbackInfo<v8::Value>& args,
7475
void (*callback)(T*, const v8::FunctionCallbackInfo<v8::Value>&,
7576
const char*, size_t)) {
7677
T* ctx;
77-
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This());
78+
if constexpr (std::is_base_of_v<BaseObject, T>) {
79+
ASSIGN_OR_RETURN_UNWRAP(&ctx, args.This());
80+
} else {
81+
ctx = CppgcMixin::Unwrap<T>(args.This());
82+
if (ctx == nullptr) return;
83+
}
7884

7985
if (args[0]->IsString()) {
8086
StringBytes::InlineDecoder decoder;

test/common/heap.js

+20-13
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,13 @@ function validateSnapshotNodes(...args) {
231231
* node_type?: string,
232232
* edge_type?: string,
233233
* }]} retainingPath The retaining path specification to search from the root nodes.
234+
* @param {boolean} allowEmpty Whether the function should fail if no matching nodes can be found.
235+
*
234236
* @returns {[object]} All the leaf nodes matching the retaining path specification. If none can be found,
235237
* logs the nodes found in the last matching step of the path (if any), and throws an
236238
* assertion error.
237239
*/
238-
function findByRetainingPath(rootName, retainingPath) {
240+
function findByRetainingPath(rootName, retainingPath, allowEmpty = false) {
239241
const nodes = createJSHeapSnapshot();
240242
let haystack = nodes.filter((n) => n.name === rootName && n.type !== 'string');
241243

@@ -269,19 +271,23 @@ function findByRetainingPath(rootName, retainingPath) {
269271
}
270272

271273
if (newHaystack.length === 0) {
272-
const format = (val) => util.inspect(val, { breakLength: 128, depth: 3 });
273-
console.error('#');
274-
console.error('# Retaining path to search for:');
275-
for (let j = 0; j < retainingPath.length; ++j) {
276-
console.error(`# - '${format(retainingPath[j])}'${i === j ? '\t<--- not found' : ''}`);
277-
}
278-
console.error('#\n');
279-
console.error('# Nodes found in the last step include:');
280-
for (let j = 0; j < haystack.length; ++j) {
281-
console.error(`# - '${format(haystack[j])}`);
274+
if (allowEmpty) {
275+
return [];
276+
} else {
277+
const format = (val) => util.inspect(val, { breakLength: 128, depth: 3 });
278+
console.error('#');
279+
console.error('# Retaining path to search for:');
280+
for (let j = 0; j < retainingPath.length; ++j) {
281+
console.error(`# - '${format(retainingPath[j])}'${i === j ? '\t<--- not found' : ''}`);
282+
}
283+
console.error('#\n');
284+
console.error('# Nodes found in the last step include:');
285+
for (let j = 0; j < haystack.length; ++j) {
286+
console.error(`# - '${format(haystack[j])}`);
287+
}
288+
289+
assert.fail(`Could not find target edge ${format(expected)} in the heap snapshot.`);
282290
}
283-
284-
assert.fail(`Could not find target edge ${format(expected)} in the heap snapshot.`);
285291
}
286292

287293
haystack = newHaystack;
@@ -326,4 +332,5 @@ module.exports = {
326332
validateSnapshotNodes,
327333
findByRetainingPath,
328334
getHeapSnapshotOptionTests,
335+
createJSHeapSnapshot,
329336
};

test/pummel/test-heapdump-hash.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
require('../common');
3+
const { findByRetainingPath, createJSHeapSnapshot } = require('../common/heap');
4+
const { createHash } = require('crypto');
5+
const assert = require('assert');
6+
7+
// In case the bootstrap process creates any Hash objects, capture a snapshot first
8+
// and save the initial length.
9+
const originalNodes = findByRetainingPath('Node / Hash', [
10+
{ edge_name: 'mdctx' },
11+
], true);
12+
13+
const count = 5;
14+
const arr = [];
15+
for (let i = 0; i < count; ++i) {
16+
arr.push(createHash('sha1'));
17+
}
18+
19+
const nodesWithCtx = findByRetainingPath('Node / Hash', [
20+
{ edge_name: 'mdctx', node_name: 'Node / EVP_MD_CTX' },
21+
]);
22+
23+
assert.strictEqual(nodesWithCtx.length - originalNodes.length, count);
24+
25+
for (let i = 0; i < count; ++i) {
26+
arr[i].update('test').digest('hex');
27+
}
28+
29+
const nodesWithDigest = findByRetainingPath('Node / Hash', [
30+
{ edge_name: 'md', node_name: 'Node / ByteSource' },
31+
]);
32+
33+
assert.strictEqual(nodesWithDigest.length - originalNodes.length, count);

0 commit comments

Comments
 (0)