diff --git a/src/README.md b/src/README.md index 20453b405b312f..0541ad87fd3764 100644 --- a/src/README.md +++ b/src/README.md @@ -589,6 +589,70 @@ void InitializeHttpParser(Local target, } ``` + + +### Argument validation in public APIs vs. internal code + +#### Public API argument sanitization + +When arguments come directly from user code, Node.js validates them at the +JavaScript layer and throws user-friendly +[errors](https://github.com/nodejs/node/blob/main/doc/contributing/using-internal-errors.md) +(e.g., `ERR_INVALID_*`), if they are invalid. This helps end users +quickly understand and fix mistakes in their own code. + +This approach ensures that the error message pinpoints which argument is wrong +and how it should be fixed. Additionally, problems in user code do not cause +mysterious crashes or hard-to-diagnose failures deeper in the engine. + +Example from `zlib.js`: + +```js +function crc32(data, value = 0) { + if (typeof data !== 'string' && !isArrayBufferView(data)) { + throw new ERR_INVALID_ARG_TYPE('data', ['Buffer', 'TypedArray', 'DataView','string'], data); + } + validateUint32(value, 'value'); + return crc32Native(data, value); +} +``` + +The corresponding C++ assertion code for the above example from it's binding `node_zlib.cc`: + +```cpp +CHECK(args[0]->IsArrayBufferView() || args[0]->IsString()); +CHECK(args[1]->IsUint32()); +``` + +#### Internal code and C++ binding checks + +Inside Node.js’s internal layers, especially the C++ [binding function][]s +typically assume their arguments have already been checked and sanitized +by the upper-level (JavaScript) callers. As a result, internal C++ code +often just uses `CHECK()` or similar assertions to confirm that the +types/values passed in are correct. If that assertion fails, Node.js will +crash or abort with an internal diagnostic message. This is to avoid +re-validating every internal function argument repeatedly which can slow +down the system. + +However, in a less common case where the API is implemented completely in +C++, the arguments would be validated directly in C++, with the errors +thrown using `THROW_ERR_INVALID_*` macros from `src/node_errors.h`. + +For example in `worker_threads.moveMessagePortToContext`: + +```cpp +void MessagePort::MoveToContext(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + if (!args[0]->IsObject() || + !env->message_port_constructor_template()->HasInstance(args[0])) { + return THROW_ERR_INVALID_ARG_TYPE(env, + "The \"port\" argument must be a MessagePort instance"); + } + // ... +} +``` + ### Exception handling