-
Notifications
You must be signed in to change notification settings - Fork 30.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
n-api: avoid crash in napi_escape_scope() #13651
Changes from 5 commits
da0edd4
039811f
d534bd3
120eff1
08c3151
f849ae6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ | |
#include <vector> | ||
#include "uv.h" | ||
#include "node_api.h" | ||
#include "node_internals.h" | ||
|
||
#define NAPI_VERSION 1 | ||
|
||
|
@@ -156,14 +157,20 @@ class HandleScopeWrapper { | |
// across different versions. | ||
class EscapableHandleScopeWrapper { | ||
public: | ||
explicit EscapableHandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {} | ||
explicit EscapableHandleScopeWrapper(v8::Isolate* isolate) | ||
: scope(isolate), escape_called_(false) {} | ||
bool escape_called() const { | ||
return escape_called_; | ||
} | ||
template <typename T> | ||
v8::Local<T> Escape(v8::Local<T> handle) { | ||
escape_called_ = true; | ||
return scope.Escape(handle); | ||
} | ||
|
||
private: | ||
v8::EscapableHandleScope scope; | ||
bool escape_called_; | ||
}; | ||
|
||
napi_handle_scope JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) { | ||
|
@@ -718,7 +725,8 @@ const char* error_messages[] = {nullptr, | |
"An array was expected", | ||
"Unknown failure", | ||
"An exception is pending", | ||
"The async work item was cancelled"}; | ||
"The async work item was cancelled", | ||
"napi_escape_handle already called on scope"}; | ||
|
||
static napi_status napi_clear_last_error(napi_env env) { | ||
CHECK_ENV(env); | ||
|
@@ -746,10 +754,14 @@ napi_status napi_get_last_error_info(napi_env env, | |
CHECK_ENV(env); | ||
CHECK_ARG(env, result); | ||
|
||
// you must udpate this assert to reference the last message | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo: update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks will fix. I wish I could type :) |
||
// in the napi_status enum each time a new error message is added. | ||
// We don't have a napi_status_last as this would result in an ABI | ||
// change each time a message was added. | ||
static_assert( | ||
(sizeof (error_messages) / sizeof (*error_messages)) == napi_status_last, | ||
node::arraysize(error_messages) == napi_escape_called_twice + 1, | ||
"Count of error messages must match count of error values"); | ||
assert(env->last_error.error_code < napi_status_last); | ||
assert(env->last_error.error_code <= napi_escape_called_twice); | ||
|
||
// Wait until someone requests the last error information to fetch the error | ||
// message string | ||
|
@@ -2211,9 +2223,12 @@ napi_status napi_escape_handle(napi_env env, | |
|
||
v8impl::EscapableHandleScopeWrapper* s = | ||
v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope); | ||
*result = v8impl::JsValueFromV8LocalValue( | ||
s->Escape(v8impl::V8LocalValueFromJsValue(escapee))); | ||
return napi_clear_last_error(env); | ||
if (!s->escape_called()) { | ||
*result = v8impl::JsValueFromV8LocalValue( | ||
s->Escape(v8impl::V8LocalValueFromJsValue(escapee))); | ||
return napi_clear_last_error(env); | ||
} | ||
return napi_set_last_error(env, napi_escape_called_twice); | ||
} | ||
|
||
napi_status napi_new_instance(napi_env env, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,19 @@ napi_value NewScopeEscape(napi_env env, napi_callback_info info) { | |
return escapee; | ||
} | ||
|
||
napi_value NewScopeEscapeTwice(napi_env env, napi_callback_info info) { | ||
napi_escapable_handle_scope scope; | ||
napi_value output = NULL; | ||
napi_value escapee = NULL; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nullptr There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is C, not C++. |
||
|
||
NAPI_CALL(env, napi_open_escapable_handle_scope(env, &scope)); | ||
NAPI_CALL(env, napi_create_object(env, &output)); | ||
NAPI_CALL(env, napi_escape_handle(env, scope, output, &escapee)); | ||
NAPI_CALL(env, napi_escape_handle(env, scope, output, &escapee)); | ||
NAPI_CALL(env, napi_close_escapable_handle_scope(env, scope)); | ||
return escapee; | ||
} | ||
|
||
napi_value NewScopeWithException(napi_env env, napi_callback_info info) { | ||
napi_handle_scope scope; | ||
size_t argc; | ||
|
@@ -57,6 +70,7 @@ void Init(napi_env env, napi_value exports, napi_value module, void* priv) { | |
napi_property_descriptor properties[] = { | ||
DECLARE_NAPI_PROPERTY("NewScope", NewScope), | ||
DECLARE_NAPI_PROPERTY("NewScopeEscape", NewScopeEscape), | ||
DECLARE_NAPI_PROPERTY("NewScopeEscapeTwice", NewScopeEscapeTwice), | ||
DECLARE_NAPI_PROPERTY("NewScopeWithException", NewScopeWithException), | ||
}; | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style issues: method should be
bool escape_called() const {
, the data member should beescape_called_
.