Skip to content

Conversation

@juanarbol
Copy link
Member


I'm a bit rusty with my C++. Any feedback will be more than valuable.

@juanarbol juanarbol requested a review from BridgeAR July 5, 2025 06:32
@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Jul 5, 2025
@juanarbol juanarbol changed the title Juan/filepath v8 src,lib: support path in v8.writeHeapSnapshot output Jul 5, 2025
@codecov
Copy link

codecov bot commented Jul 5, 2025

Codecov Report

❌ Patch coverage is 79.48718% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.51%. Comparing base (a65421a) to head (070a019).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
src/heap_utils.cc 72.41% 3 Missing and 5 partials ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #58959      +/-   ##
==========================================
- Coverage   88.54%   88.51%   -0.03%     
==========================================
  Files         703      703              
  Lines      208545   208569      +24     
  Branches    40216    40240      +24     
==========================================
- Hits       184652   184625      -27     
- Misses      15905    15954      +49     
- Partials     7988     7990       +2     
Files with missing lines Coverage Δ
lib/v8.js 99.04% <100.00%> (+0.01%) ⬆️
src/node_internals.h 83.01% <ø> (ø)
src/heap_utils.cc 79.54% <72.41%> (-0.60%) ⬇️

... and 37 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@juanarbol juanarbol added semver-minor PRs that contain new features and should be released in the next minor version. v8 module Issues and PRs related to the "v8" subsystem. labels Jul 6, 2025
Copy link
Member

@jasnell jasnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BufferValue uses need to be cleaned up

@juanarbol juanarbol force-pushed the juan/filepath-v8 branch 2 times, most recently from b956356 to 0055948 Compare July 18, 2025 23:05
@juanarbol
Copy link
Member Author

@addaleax @jasnell @Renegade334 PTAL :-)

if (WriteSnapshot(env, final_filename.c_str(), options).IsNothing()) return;

args.GetReturnValue().Set(
String::NewFromUtf8(isolate, final_filename.c_str()).ToLocalChecked());
Copy link
Member

@jasnell jasnell Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately this is going to be a problem because it assumes the final_filename is utf8 encoded. Consider the following case:

const path = Buffer.from([0xe6]);  // latin 1 character
fs.mkdirSync(path);
const res = v8.writeHeapSnapshot(undefined, { path });
fs.readfileSync(res);  // fails! path doesn't exist

The reason fs.readfileSync would fail here is because the returned res will have interpreted the 0xe6 character incorrectly and will have replaced it with the unicode replacement char. The snapshot will have been written to disk correctly, but the returned path is wrong.

This likely needs to return the resulting path as a Buffer if the path was given as a Buffer and allow the API to accept an encoding option that optionally decodes the result as a string. But, that gets a bit awkward.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love how picky this is, aaah, let me put the encoding option to make this a bit more consistent and leave utf8 as default encoding.

Nice catch, thanks! Anything else missing?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing that sticks out, but I should have time to take another pass through by end of day monday

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey James, I know its been a while; I've been quite busy lately, but now I have some bandwidth...

James, your snippet won't work.

node:fs:1326
  const result = binding.mkdir(
                         ^

Error: EILSEQ: illegal byte sequence, mkdir '�'
    at Object.mkdirSync (node:fs:1326:26)
    at Object.<anonymous> (/private/tmp/case.js:5:4)
    at Module._compile (node:internal/modules/cjs/loader:1759:14)
    at Object..js (node:internal/modules/cjs/loader:1890:10)
    at Module.load (node:internal/modules/cjs/loader:1480:32)
    at Module._load (node:internal/modules/cjs/loader:1299:12)
    at TracingChannel.traceSync (node:diagnostics_channel:328:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:245:24)
    at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5)
    at node:internal/main/run_main_module:33:47 {
  errno: -92,
  code: 'EILSEQ',
  syscall: 'mkdir',
  path: '�'
}

I'm not able to create a latin1 folder in Node.js. I get the encoding requirements and stuff... but your snippet per se is not valid. What would you like me to do in this case? What should I consider adding in the test case?

Copy link
Member Author

@juanarbol juanarbol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm gonna use StringBytes::Encode but I would like to get my question answered before doing something

if (WriteSnapshot(env, final_filename.c_str(), options).IsNothing()) return;

args.GetReturnValue().Set(
String::NewFromUtf8(isolate, final_filename.c_str()).ToLocalChecked());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey James, I know its been a while; I've been quite busy lately, but now I have some bandwidth...

James, your snippet won't work.

node:fs:1326
  const result = binding.mkdir(
                         ^

Error: EILSEQ: illegal byte sequence, mkdir '�'
    at Object.mkdirSync (node:fs:1326:26)
    at Object.<anonymous> (/private/tmp/case.js:5:4)
    at Module._compile (node:internal/modules/cjs/loader:1759:14)
    at Object..js (node:internal/modules/cjs/loader:1890:10)
    at Module.load (node:internal/modules/cjs/loader:1480:32)
    at Module._load (node:internal/modules/cjs/loader:1299:12)
    at TracingChannel.traceSync (node:diagnostics_channel:328:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:245:24)
    at Module.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:154:5)
    at node:internal/main/run_main_module:33:47 {
  errno: -92,
  code: 'EILSEQ',
  syscall: 'mkdir',
  path: '�'
}

I'm not able to create a latin1 folder in Node.js. I get the encoding requirements and stuff... but your snippet per se is not valid. What would you like me to do in this case? What should I consider adding in the test case?

@juanarbol
Copy link
Member Author

@jasnell PTAL

@juanarbol
Copy link
Member Author

Fixing linter and CI, sorry.

Fixes: nodejs#58857
Signed-off-by: Juan José Arboleda <soyjuanarbol@gmail.com>
Comment on lines +499 to +501
if (StringBytes::Encode(isolate, final_filename.c_str(), encoding)
.ToLocal(&ret)) {
args.GetReturnValue().Set(ret);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with the position of this StringBytes operation is that if it fails, the function call will throw but will still have had meaningful side-effects. It would probably be better to attempt the encoding before snapshotting.

Comment on lines +97 to +98
const encoding = options?.encoding || 'utf8';
return triggerHeapSnapshot(filename, optionArray, options?.path, encoding);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Defaulting this here shouldn't be necessary; ParseEncoding will fall back to the provided default if the value is undefined or not a string.

Suggested change
const encoding = options?.encoding || 'utf8';
return triggerHeapSnapshot(filename, optionArray, options?.path, encoding);
return triggerHeapSnapshot(filename, optionArray, options?.path, options?.encoding);

filename = getValidatedPath(filename);
}

if (options?.path !== undefined) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I believe the general convention for options validation is to check for any nullish value, unless null has a discrete meaning for that option.

Suggested change
if (options?.path !== undefined) {
if (options?.path != undefined) {

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

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. semver-minor PRs that contain new features and should be released in the next minor version. v8 module Issues and PRs related to the "v8" subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants