Skip to content

Napi::Env::GetAndClearPendingException assumes exceptions are Error objects #912

Closed
@legendecas

Description

@legendecas

On common checks on each node-api calls in node-addon-api (e.g. NAPI_THROW_IF_FAILED), Napi::Error::New(env) is used to construct proper error representative types to indicate the exception value. In https://github.com/nodejs/node-addon-api/blob/main/napi.h#L1354 Napi::Error extends Napi::ObjectReference, which in the term of itself is correct, JavaScript errors are objects. However, exceptions are not, they can be any JavaScript values like string, or number, although the meaning might not be clear when throwing primitives like numbers but it is still valid JavaScript codes.

Thus, in the case of throwing non-object and non-function types between the border of node-addon-api and javascript (or using napi_throw values directly in c++ land), node-addon-api complains (fatal error) that Napi::Error cannot be constructed with non-objects and non-functions.

#include <napi.h>

namespace {
void Test(const Napi::CallbackInfo& info) {
  info[0].As<Napi::Function>().Call({});
}

Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
  exports.Set("test", Napi::Function::New<Test>(env));
}

NODE_API_MODULE(addon, InitAll)
}

example of calling into the addon:

const addon = require('./build/Debug/test_napi_exception.node');
addon.test(() => {
    throw 'foobar';
});

This is what we will get:

FATAL ERROR: Error::Error napi_create_reference
 1: 0xadd3a0 node::Abort() [../node/out/Release/node]
 2: 0xade3dc node::OnFatalError(char const*, char const*) [../node/out/Release/node]
 3: 0xade479  [../node/out/Release/node]
 4: 0xaa454b napi_fatal_error [../node/out/Release/node]
 5: 0x7f8e504cb8d6 Napi::Error::Error() [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
 6: 0x7f8e504cb9c4 Napi::Error::Error(napi_env__*, napi_value__*) [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
 7: 0x7f8e504cb840 Napi::Error::New(napi_env__*) [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
 8: 0x7f8e504cb4ac Napi::Function::Call(napi_value__*, unsigned long, napi_value__* const*) const [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
 9: 0x7f8e504cb3da Napi::Function::Call(napi_value__*, std::initializer_list<napi_value__*> const&) const [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
10: 0x7f8e504cb36e Napi::Function::Call(std::initializer_list<napi_value__*> const&) const [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
11: 0x7f8e504cad59  [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
12: 0x7f8e504caf17  [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
13: 0x7f8e504cafb0  [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
14: 0x7f8e504caf84  [/disks/chengzhong.wcz/repro-napi-v8impl-refbase-double-free/build/Debug/test_napi_exception.node]
15: 0xa88545  [../node/out/Release/node]
16: 0xd65c3a  [../node/out/Release/node]
17: 0xd677ec v8::internal::Builtin_HandleApiCall(int, unsigned long*, v8::internal::Isolate*) [../node/out/Release/node]
18: 0x15f1699  [../node/out/Release/node]

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