njs: Segfault when using .call.call construction.

> eval.call.call(function(){return String})
Segmentation fault
> URIError.apply.apply(RegExp)
Segmentation fault
> isNaN.apply.call(isNaN)
Segmentation fault

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 16 (16 by maintainers)

Commits related to this issue

Most upvoted comments

@xeioex

Here’s the final version of this patch.

# HG changeset patch
# User hongzhidao <hongzhidao@gmail.com>
# Date 1556279874 -28800
# Node ID 73effc1318a90da6cf8fa0204c2318e0733d2bff
# Parent  43dc900bc914b1d8d2eaf36008f8690d21c54447
Improved njs_function_native_call().

diff -r 43dc900bc914 -r 73effc1318a9 njs/njs_function.c
--- a/njs/njs_function.c	Thu Apr 25 19:50:20 2019 +0300
+++ b/njs/njs_function.c	Fri Apr 26 19:57:54 2019 +0800
@@ -566,7 +566,7 @@ njs_function_lambda_call(njs_vm_t *vm, n
 njs_ret_t
 njs_function_native_call(njs_vm_t *vm, njs_function_native_t native,
     njs_value_t *args, uint8_t *args_types, nxt_uint_t nargs,
-    njs_index_t retval)
+    njs_index_t retval, u_char *return_address)
 {
     njs_ret_t           ret;
     njs_value_t         *value;
@@ -617,6 +617,8 @@ njs_function_native_call(njs_vm_t *vm, n
             *value = vm->retval;
         }

+        vm->current = return_address;
+
         njs_function_frame_free(vm, frame);

         return NXT_OK;
diff -r 43dc900bc914 -r 73effc1318a9 njs/njs_function.h
--- a/njs/njs_function.h	Thu Apr 25 19:50:20 2019 +0300
+++ b/njs/njs_function.h	Fri Apr 26 19:57:54 2019 +0800
@@ -173,7 +173,7 @@ njs_ret_t njs_function_lambda_call(njs_v
     u_char *return_address);
 njs_ret_t njs_function_native_call(njs_vm_t *vm, njs_function_native_t native,
     njs_value_t *args, uint8_t *args_types, nxt_uint_t nargs,
-    njs_index_t retval);
+    njs_index_t retval, u_char *return_address);
 void njs_function_frame_free(njs_vm_t *vm, njs_native_frame_t *frame);


diff -r 43dc900bc914 -r 73effc1318a9 njs/njs_vm.c
--- a/njs/njs_vm.c	Thu Apr 25 19:50:20 2019 +0300
+++ b/njs/njs_vm.c	Fri Apr 26 19:57:54 2019 +0800
@@ -2047,7 +2047,8 @@ njs_vmcode_function_call(njs_vm_t *vm, n
             ret = njs_function_native_call(vm, function->u.native,
                                            frame->arguments,
                                            function->args_types, frame->nargs,
-                                           (njs_index_t) retval);
+                                           (njs_index_t) retval,
+                                           return_address);
         }

     } else {
@@ -2055,16 +2056,7 @@ njs_vmcode_function_call(njs_vm_t *vm, n
                                        return_address);
     }

-    switch (ret) {
-    case NXT_OK:
-        return sizeof(njs_vmcode_function_call_t);
-
-    case NJS_APPLIED:
-        return 0;
-
-    default:
-        return ret;
-    }
+    return (ret == NJS_APPLIED) ? 0 : ret;
 }


@@ -2304,19 +2296,9 @@ njs_vmcode_continuation(njs_vm_t *vm, nj

     ret = njs_function_native_call(vm, cont->function, frame->arguments,
                                    cont->args_types, frame->nargs,
-                                   cont->retval);
-
-    switch (ret) {
-    case NXT_OK:
-        vm->current = return_address;
-        /* Fall through. */
-
-    case NJS_APPLIED:
-        return 0;
-
-    default:
-        return ret;
-    }
+                                   cont->retval, return_address);
+
+    return (ret == NJS_APPLIED) ? 0 : ret;
 }


# HG changeset patch
# User hongzhidao <hongzhidao@gmail.com>
# Date 1556285404 -28800
# Node ID f2e74147ee5474e10a16159c45a876c92a4775a0
# Parent  73effc1318a90da6cf8fa0204c2318e0733d2bff
Improved njs_vm_continuation().

diff -r 73effc1318a9 -r f2e74147ee54 njs/njs_function.c
--- a/njs/njs_function.c	Fri Apr 26 19:57:54 2019 +0800
+++ b/njs/njs_function.c	Fri Apr 26 21:30:04 2019 +0800
@@ -294,6 +294,7 @@ njs_function_native_frame(njs_vm_t *vm,
     size_t continuation_size, nxt_bool_t ctor)
 {
     size_t              size;
+    u_char              *continuation;
     nxt_uint_t          n;
     njs_value_t         *value, *bound;
     njs_native_frame_t  *frame;
@@ -312,7 +313,13 @@ njs_function_native_frame(njs_vm_t *vm,
     frame->nargs = function->args_offset + nargs;
     frame->ctor = ctor;

-    value = (njs_value_t *) (njs_continuation(frame) + continuation_size);
+    continuation = (u_char *) frame + NJS_NATIVE_FRAME_SIZE;
+
+    if (continuation_size > 0) {
+        frame->continuation = (njs_continuation_t *) continuation;
+    }
+
+    value = (njs_value_t *) (continuation + continuation_size);
     frame->arguments = value;

     bound = function->bound;
@@ -770,6 +777,10 @@ njs_function_frame_free(njs_vm_t *vm, nj
     do {
         previous = frame->previous;

+        if (frame->continuation != NULL) {
+            vm->current = frame->continuation->return_address;
+        }
+
         /* GC: free frame->local, etc. */

         if (frame->size != 0) {
diff -r 73effc1318a9 -r f2e74147ee54 njs/njs_function.h
--- a/njs/njs_function.h	Fri Apr 26 19:57:54 2019 +0800
+++ b/njs/njs_function.h	Fri Apr 26 21:30:04 2019 +0800
@@ -66,10 +66,7 @@ typedef struct {


 #define njs_vm_continuation(vm)                                               \
-    (void *) njs_continuation((vm)->top_frame)
-
-#define njs_continuation(frame)                                               \
-    ((u_char *) frame + NJS_NATIVE_FRAME_SIZE)
+    (void *) ((vm)->top_frame->continuation)

 #define njs_continuation_size(size)                                           \
     nxt_align_size(sizeof(size), sizeof(njs_value_t))
@@ -104,6 +101,8 @@ struct njs_native_frame_s {
     njs_function_t                 *function;
     njs_native_frame_t             *previous;

+    njs_continuation_t             *continuation;
+
     njs_value_t                    *arguments;
     njs_object_t                   *arguments_object;

diff -r 73effc1318a9 -r f2e74147ee54 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Fri Apr 26 19:57:54 2019 +0800
+++ b/njs/test/njs_unit_test.c	Fri Apr 26 21:30:04 2019 +0800
@@ -6039,6 +6039,21 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("function f (x){ return x**2}; f(2\n)"),
       nxt_string("4") },

+    { nxt_string("var fn = Function.prototype.call; fn.call(() => 1)"),
+      nxt_string("1") },
+
+    { nxt_string("var fn = Function.prototype.call; fn.call(fn, () => 1)"),
+      nxt_string("1") },
+
+    { nxt_string("var fn = Function.prototype.call; fn.call(fn, fn, () => 1)"),
+      nxt_string("1") },
+
+    { nxt_string("eval.call.call(Number)"),
+      nxt_string("0") },
+
+    { nxt_string("URIError.apply.apply(RegExp)"),
+      nxt_string("/(?:)/") },
+
     /* Recursive factorial. */

     { nxt_string("function f(a) {"

@drsm thanks for your help 😃

@xeioex wait a moment. For the second patch, I think it’s still not ideal.

@hongzhidao

>> var x = function() { console.log('x'); }
undefined
>> eval.call(x)
InternalError: Not implemented
    at eval (native)
    at Function.prototype.call (native)
    at main (native)

>> eval.call.call(x) // should call x there
[Function]
>> x.call()
x
undefined
>> x()
x
undefined

@xeioex

  1. Fixed function prototype call and apply. (Still have problem, ignore this)
deleted.
  1. Help test and add unit tests, please. @drsm @xeioex (I’m not familiar with call/apply)

  2. What’s the actual return value of xxx.call(...)? For example.

eval.call.call(function() { return 1 });

BTW, according to my understanding. Function.prototype.call always call this as a function. So, eval.call(...) will call the eval function since this is object eval with property call. eval.call.call(foo) will call foo since this is bound to foo. Right?

the_object.the_function(arguments) the_function.call(the_object, arguments) the_function.apply(the_object, [arguments])

@hongzhidao

Is URIError.apply.apply the same as URIError.apply is?

Yes, they are both equal to Function.prototype.apply.

With apply function. What is the value of this?

URIError.apply.apply(undefined);

this = URIError.apply thisArg = undefined

see apply