mirror of https://github.com/svaarala/duktape.git
Browse Source
Make Function.prototype.name writable so that user code can set a "name" property for Duktape/C functions. Duktape/C functions don't have a "name" property by default and a non-writable ancestor prevents creating one. Fixes GH-79.pull/85/head
Sami Vaarala
10 years ago
4 changed files with 141 additions and 2 deletions
@ -0,0 +1,55 @@ |
|||||
|
/*
|
||||
|
* Duktape 1.0 issue: cannot set Duktape/C function 'name' property after |
||||
|
* creation. |
||||
|
* |
||||
|
* The cause: Function.prototype.name, containing an empty string, is |
||||
|
* non-writable. This is an unintended side effect of all built-in |
||||
|
* functions (such as Array, Math.cos, etc) having a non-writable name. |
||||
|
* Function.prototype, although never really called, is technically a |
||||
|
* function so its empty name is unintentionally non-writable. |
||||
|
* |
||||
|
* Fixed in Duktape 1.1 so that Function.prototype.name is writable. |
||||
|
* The best fix would actually be to have the property non-writable |
||||
|
* while simultaneously allowing a Function instance's 'name' property |
||||
|
* to be set - but Ecmascript cannot express such an access control |
||||
|
* policy. |
||||
|
*/ |
||||
|
|
||||
|
/*===
|
||||
|
*** test_1 (duk_safe_call) |
||||
|
writable: true |
||||
|
enumerable: false |
||||
|
configurable: false |
||||
|
MyFunc.name: my_func_name |
||||
|
final top: 0 |
||||
|
==> rc=0, result='undefined' |
||||
|
===*/ |
||||
|
|
||||
|
static duk_ret_t my_func(duk_context *ctx) { |
||||
|
(void) ctx; |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static duk_ret_t test_1(duk_context *ctx) { |
||||
|
/* Check that Function.prototype.name is writable. */ |
||||
|
duk_eval_string_noresult(ctx, |
||||
|
"var pd = Object.getOwnPropertyDescriptor(Function.prototype, 'name');\n" |
||||
|
"print('writable:', pd.writable);\n" |
||||
|
"print('enumerable:', pd.enumerable);\n" |
||||
|
"print('configurable:', pd.configurable);\n"); |
||||
|
|
||||
|
duk_push_c_function(ctx, my_func, 0); |
||||
|
duk_push_string(ctx, "my_func_name"); |
||||
|
duk_put_prop_string(ctx, -2, "name"); |
||||
|
duk_put_global_string(ctx, "MyFunc"); |
||||
|
|
||||
|
duk_eval_string_noresult(ctx, |
||||
|
"print('MyFunc.name:', MyFunc.name);\n"); |
||||
|
|
||||
|
printf("final top: %ld\n", (long) duk_get_top(ctx)); |
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void test(duk_context *ctx) { |
||||
|
TEST_SAFE_CALL(test_1); |
||||
|
} |
@ -0,0 +1,73 @@ |
|||||
|
/*
|
||||
|
* A Duktape/C function does not have an automatic name in Duktape 1.x. |
||||
|
* You can set it yourself in Duktape 1.1 to get nicer tracebacks. |
||||
|
* In Duktape 1.0 Function.prototype.name is not writable so you can't |
||||
|
* do this. |
||||
|
*/ |
||||
|
|
||||
|
/*===
|
||||
|
*** test_without_name (duk_safe_call) |
||||
|
my name is: '' |
||||
|
URIError: uri error (rc -106) |
||||
|
anon native strict preventsyield |
||||
|
forEach native strict preventsyield |
||||
|
eval XXX preventsyield |
||||
|
==> rc=0, result='undefined' |
||||
|
*** test_with_name (duk_safe_call) |
||||
|
my name is: 'my_func' |
||||
|
URIError: uri error (rc -106) |
||||
|
my_func native strict preventsyield |
||||
|
forEach native strict preventsyield |
||||
|
eval XXX preventsyield |
||||
|
==> rc=0, result='undefined' |
||||
|
===*/ |
||||
|
|
||||
|
static duk_ret_t my_func(duk_context *ctx) { |
||||
|
duk_push_current_function(ctx); |
||||
|
duk_get_prop_string(ctx, -1, "name"); |
||||
|
printf("my name is: '%s'\n", duk_safe_to_string(ctx, -1)); |
||||
|
duk_pop_2(ctx); |
||||
|
|
||||
|
return DUK_RET_URI_ERROR; |
||||
|
} |
||||
|
|
||||
|
static duk_ret_t test_without_name(duk_context *ctx) { |
||||
|
duk_push_c_function(ctx, my_func, 0); |
||||
|
duk_put_global_string(ctx, "MyFunc"); |
||||
|
|
||||
|
duk_eval_string_noresult(ctx, |
||||
|
"try {\n" |
||||
|
" [1].forEach(MyFunc);\n" |
||||
|
"} catch (e) {\n" |
||||
|
" print(sanitize(e.stack || e));\n" |
||||
|
"}\n"); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static duk_ret_t test_with_name(duk_context *ctx) { |
||||
|
duk_get_global_string(ctx, "MyFunc"); |
||||
|
duk_push_string(ctx, "my_func"); |
||||
|
duk_put_prop_string(ctx, -2, "name"); |
||||
|
duk_pop(ctx); |
||||
|
|
||||
|
duk_eval_string_noresult(ctx, |
||||
|
"try {\n" |
||||
|
" [1].forEach(MyFunc);\n" |
||||
|
"} catch (e) {\n" |
||||
|
" print(sanitize(e.stack || e));\n" |
||||
|
"}\n"); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void test(duk_context *ctx) { |
||||
|
duk_eval_string_noresult(ctx, |
||||
|
"var sanitize = function(v) {\n" |
||||
|
" v = v.replace(/eval \\S+/, 'eval XXX');\n" |
||||
|
" return v;\n" |
||||
|
"}\n"); |
||||
|
|
||||
|
TEST_SAFE_CALL(test_without_name); |
||||
|
TEST_SAFE_CALL(test_with_name); |
||||
|
} |
Loading…
Reference in new issue