Skip to content

Inconsistent validation of custom signals #44749

@fasttime

Description

@fasttime

Version

18.9.0

Platform

Darwin

Subsystem

child_process
os

What steps will reproduce the bug?

In the current implementation, spawn and related functions throw synchronous errors for invalid signals, e.g.:

import { spawn } from 'node:child_process'; // TypeError [ERR_UNKNOWN_SIGNAL] spawn(process.execPath, ['-v'], { killSignal: 12345 });

Anyway, it's easy to define custom signals that pass the validation:

import { spawn } from 'node:child_process'; import { constants } from 'node:os'; constants.signals.FOOBAR = 12345; // no error spawn(process.execPath, ['-v'], { killSignal: 12345 });

The same applies when signals are identified by name, i.e:

import { spawn } from 'node:child_process'; // TypeError [ERR_UNKNOWN_SIGNAL] spawn(process.execPath, ['-v'], { killSignal: 'FOOBAR' });

and

import { spawn } from 'node:child_process'; import { constants } from 'node:os'; constants.signals.FOOBAR = 12345; // no error spawn(process.execPath, ['-v'], { killSignal: 'FOOBAR' });

but if a custom signal is added after the internal mapping of numeric codes to names signals has been generated, validation fails for numeric codes (but not for signal names):

import { spawn } from 'node:child_process'; import { constants } from 'node:os'; spawn(process.execPath, ['-v'], { killSignal: 1 }); constants.signals.FOOBAR = 12345; spawn(process.execPath, ['-v'], { killSignal: 'FOOBAR' }); // no error spawn(process.execPath, ['-v'], { killSignal: 12345 }); // TypeError [ERR_UNKNOWN_SIGNAL]

This strikes to me as issue of improper memoization:

node/lib/internal/util.js

Lines 272 to 283 in 9ae2af4

let signalsToNamesMapping;
function getSignalsToNamesMapping() {
if (signalsToNamesMapping !== undefined)
return signalsToNamesMapping;
signalsToNamesMapping = ObjectCreate(null);
for (const key in signals) {
signalsToNamesMapping[signals[key]] = key;
}
return signalsToNamesMapping;
}

where signalsToNamesMapping never changes once created.

On the other hand, I'm not convinced that the current behavior - being able to add, remove, and change signals at will - is intended. If it is, then the validation logic should be fixed. If it is not, then constants.signals should be better frozen to prevent changes.

How often does it reproduce? Is there a required condition?

All the time.

What is the expected behavior?

Either custom numeric signals should always be accepted as valid, or they should always be rejected. If they should be rejected, then custom string signals should be rejected, too.

What do you see instead?

Inconsistent behavior, depending on (possibly unrelated) previous operations.

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    child_processIssues and PRs related to the child_process subsystem.good first issueIssues that are suitable for first-time contributors.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions