Skip to content

node:perf_hooks: validate performance.measure name argument #3088

Description

@andrewtdiz

Summary

performance.measure(name, ...) requires name to be a string in Node. Perry currently coerces name with the same String(value) behavior used by performance.mark(), so undefined, null, numbers, booleans, objects, arrays, and symbols can create measure entries instead of throwing.

Node behavior

Probe run with npx --yes node@25.9.0:

const { performance } = require("node:perf_hooks");
for (const value of [undefined, null, 0, true, {}, [], Symbol("s")]) {
  try {
    performance.measure(value);
    console.log(String(value), "no throw");
  } catch (err) {
    console.log(String(value), err.name, err.code || "no-code", err.message);
  }
}

Observed result: every non-string value throws TypeError [ERR_INVALID_ARG_TYPE] for the "name" argument. This differs from performance.mark(), which intentionally string-coerces non-symbol names.

Perry implementation evidence

  • crates/perry-runtime/src/perf_hooks.rs::js_perf_mark() explicitly checks symbols and otherwise calls coerce_to_string(name_val), matching Node mark-name coercion.
  • crates/perry-runtime/src/perf_hooks.rs::js_perf_measure() also starts with let name = coerce_to_string(name_val); and has no string-type validation or symbol-specific error path.
  • crates/perry-runtime/src/object/native_module_dispatch.rs routes ("perf_hooks", "measure") directly to js_perf_measure(arg(0), arg(1), arg(2)).
  • Existing perf_hooks fixtures cover valid measure names and option endpoint validation, but not invalid name types.

Expected fix

  • Validate that performance.measure() receives a string name before creating an entry.
  • Throw TypeError [ERR_INVALID_ARG_TYPE] for missing, null, primitive non-string, object, array, and symbol names.
  • Preserve the existing performance.mark() name coercion behavior.
  • Add parity coverage for invalid measure() name values and one control case showing mark(1).name === "1" still works.

Activity

  1. andrewtdiz commented on May 31, 2026

    @andrewtdiz
    ContributorAuthor

    I am taking this in a focused node:perf_hooks timing and validation PR cut with #3012, #3013, #3011, #3010, and #3008. Intended scope: make performance.now() relative to a process-start timeOrigin, support two-argument eventLoopUtilization() diffs, and align the related User Timing / observer validation behavior. Non-goals: timerify() function entries and markResourceTiming() resource entries, which fit a separate observable-entry cut.

  2. andrewtdiz commented on May 31, 2026

    @andrewtdiz
    ContributorAuthor

    Opened PR #3508 to close this: #3508

    Verification on the rebased branch:

    • Node 24 parity: ./run_parity_tests.sh --suite node-suite --module perf_hooks passed 78/78.
    • cargo check -p perry-runtime -p perry-codegen -p perry-hir -p perry-api-manifest -p perry passed.
    • cargo fmt --all -- --check, ./scripts/check_file_size.sh, jq empty test-parity/known_failures.json, and git diff HEAD~1..HEAD --check passed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions