Introduce Function::FunctionProtoToString()
Add a new function on the public API to allow serializing a function to a string using the built-in toString() implementation, allowing serialization without worrying about untrusted author script overriding the toString() implementation. This is similar in nature to Object::ObjectProtoToString() (but that only returns "[object Function]" for any passed function). Add tests for the same. Bug: chromium:1144841 Change-Id: Ie4c29b870034c0817c23bf91f9424f956098823d Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2514768 Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Devlin <rdevlin.cronin@chromium.org> Cr-Commit-Position: refs/heads/master@{#70976}
This commit is contained in:
parent
a3e67fea74
commit
2ccd4dc564
@ -4621,6 +4621,15 @@ class V8_EXPORT Function : public Object {
|
|||||||
*/
|
*/
|
||||||
Local<Value> GetBoundFunction() const;
|
Local<Value> GetBoundFunction() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls builtin Function.prototype.toString on this function.
|
||||||
|
* This is different from Value::ToString() that may call a user-defined
|
||||||
|
* toString() function, and different than Object::ObjectProtoToString() which
|
||||||
|
* always serializes "[object Function]".
|
||||||
|
*/
|
||||||
|
V8_WARN_UNUSED_RESULT MaybeLocal<String> FunctionProtoToString(
|
||||||
|
Local<Context> context);
|
||||||
|
|
||||||
ScriptOrigin GetScriptOrigin() const;
|
ScriptOrigin GetScriptOrigin() const;
|
||||||
V8_INLINE static Function* Cast(Value* obj);
|
V8_INLINE static Function* Cast(Value* obj);
|
||||||
static const int kLineOffsetNotFound;
|
static const int kLineOffsetNotFound;
|
||||||
|
@ -5126,6 +5126,18 @@ Local<v8::Value> Function::GetBoundFunction() const {
|
|||||||
return v8::Undefined(reinterpret_cast<v8::Isolate*>(self->GetIsolate()));
|
return v8::Undefined(reinterpret_cast<v8::Isolate*>(self->GetIsolate()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeLocal<String> v8::Function::FunctionProtoToString(Local<Context> context) {
|
||||||
|
PREPARE_FOR_EXECUTION(context, Function, FunctionProtoToString, String);
|
||||||
|
auto self = Utils::OpenHandle(this);
|
||||||
|
Local<Value> result;
|
||||||
|
has_pending_exception = !ToLocal<Value>(
|
||||||
|
i::Execution::CallBuiltin(isolate, isolate->function_to_string(), self, 0,
|
||||||
|
nullptr),
|
||||||
|
&result);
|
||||||
|
RETURN_ON_FAILED_EXECUTION(String);
|
||||||
|
RETURN_ESCAPED(Local<String>::Cast(result));
|
||||||
|
}
|
||||||
|
|
||||||
int Name::GetIdentityHash() {
|
int Name::GetIdentityHash() {
|
||||||
auto self = Utils::OpenHandle(this);
|
auto self = Utils::OpenHandle(this);
|
||||||
return static_cast<int>(self->Hash());
|
return static_cast<int>(self->Hash());
|
||||||
|
@ -1571,8 +1571,10 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
|||||||
Builtins::kFastFunctionPrototypeBind, 1, false);
|
Builtins::kFastFunctionPrototypeBind, 1, false);
|
||||||
SimpleInstallFunction(isolate_, prototype, "call",
|
SimpleInstallFunction(isolate_, prototype, "call",
|
||||||
Builtins::kFunctionPrototypeCall, 1, false);
|
Builtins::kFunctionPrototypeCall, 1, false);
|
||||||
SimpleInstallFunction(isolate_, prototype, "toString",
|
Handle<JSFunction> function_to_string =
|
||||||
Builtins::kFunctionPrototypeToString, 0, false);
|
SimpleInstallFunction(isolate_, prototype, "toString",
|
||||||
|
Builtins::kFunctionPrototypeToString, 0, false);
|
||||||
|
native_context()->set_function_to_string(*function_to_string);
|
||||||
|
|
||||||
// Install the @@hasInstance function.
|
// Install the @@hasInstance function.
|
||||||
Handle<JSFunction> has_instance = InstallFunctionAtSymbol(
|
Handle<JSFunction> has_instance = InstallFunctionAtSymbol(
|
||||||
|
@ -739,6 +739,7 @@ class RuntimeCallTimer final {
|
|||||||
V(Float64Array_New) \
|
V(Float64Array_New) \
|
||||||
V(Function_Call) \
|
V(Function_Call) \
|
||||||
V(Function_New) \
|
V(Function_New) \
|
||||||
|
V(Function_FunctionProtoToString) \
|
||||||
V(Function_NewInstance) \
|
V(Function_NewInstance) \
|
||||||
V(FunctionTemplate_GetFunction) \
|
V(FunctionTemplate_GetFunction) \
|
||||||
V(FunctionTemplate_New) \
|
V(FunctionTemplate_New) \
|
||||||
|
@ -311,6 +311,7 @@ enum ContextLookupFlags {
|
|||||||
V(FINALIZATION_REGISTRY_CLEANUP_SOME, JSFunction, \
|
V(FINALIZATION_REGISTRY_CLEANUP_SOME, JSFunction, \
|
||||||
finalization_registry_cleanup_some) \
|
finalization_registry_cleanup_some) \
|
||||||
V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \
|
V(FUNCTION_HAS_INSTANCE_INDEX, JSFunction, function_has_instance) \
|
||||||
|
V(FUNCTION_TO_STRING_INDEX, JSFunction, function_to_string) \
|
||||||
V(OBJECT_TO_STRING, JSFunction, object_to_string) \
|
V(OBJECT_TO_STRING, JSFunction, object_to_string) \
|
||||||
V(OBJECT_VALUE_OF_FUNCTION_INDEX, JSFunction, object_value_of_function) \
|
V(OBJECT_VALUE_OF_FUNCTION_INDEX, JSFunction, object_value_of_function) \
|
||||||
V(PROMISE_ALL_INDEX, JSFunction, promise_all) \
|
V(PROMISE_ALL_INDEX, JSFunction, promise_all) \
|
||||||
|
@ -17566,6 +17566,33 @@ THREADED_TEST(FunctionGetBoundFunction) {
|
|||||||
original_function->GetScriptColumnNumber());
|
original_function->GetScriptColumnNumber());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
THREADED_TEST(FunctionProtoToString) {
|
||||||
|
LocalContext context;
|
||||||
|
v8::Isolate* isolate = CcTest::isolate();
|
||||||
|
v8::HandleScope scope(isolate);
|
||||||
|
|
||||||
|
// Replace Function.prototype.toString.
|
||||||
|
CompileRun(R"(
|
||||||
|
Function.prototype.toString = function() {
|
||||||
|
return 'customized toString';
|
||||||
|
})");
|
||||||
|
|
||||||
|
constexpr char kTestFunction[] = "function testFunction() { return 7; }";
|
||||||
|
std::string wrapped_function("(");
|
||||||
|
wrapped_function.append(kTestFunction).append(")");
|
||||||
|
Local<Function> function =
|
||||||
|
CompileRun(wrapped_function.c_str()).As<Function>();
|
||||||
|
|
||||||
|
Local<String> value = function->ToString(context.local()).ToLocalChecked();
|
||||||
|
CHECK(value->IsString());
|
||||||
|
CHECK(
|
||||||
|
value->Equals(context.local(), v8_str("customized toString")).FromJust());
|
||||||
|
|
||||||
|
// FunctionProtoToString() should not call the replaced toString function.
|
||||||
|
value = function->FunctionProtoToString(context.local()).ToLocalChecked();
|
||||||
|
CHECK(value->IsString());
|
||||||
|
CHECK(value->Equals(context.local(), v8_str(kTestFunction)).FromJust());
|
||||||
|
}
|
||||||
|
|
||||||
static void GetterWhichReturns42(
|
static void GetterWhichReturns42(
|
||||||
Local<String> name,
|
Local<String> name,
|
||||||
|
Loading…
Reference in New Issue
Block a user