Skip to content
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

在协程里面不能使用JsContext? #68

Open
zhousj888 opened this issue Apr 3, 2019 · 4 comments
Open

在协程里面不能使用JsContext? #68

zhousj888 opened this issue Apr 3, 2019 · 4 comments
Assignees
Labels
bug Something isn't working

Comments

@zhousj888
Copy link

在协程里面使用JsContext会出现exception

Environment Details

  • coobjc version:master
  • iOS version:ios12
  • Xcode version:10
  • Other informations:

Steps to Reproduce

co_launch(^{
        JSContext *mJsContext = [[JSContext alloc] init];
        mJsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
            NSLog(@"%@", exception);
        };
        [mJsContext evaluateScript:@"var a  = 1"];
    });

运行上述代码,会出现jsException

@pengyutang125
Copy link
Contributor

收到,正在排查

@pengyutang125
Copy link
Contributor

pengyutang125 commented Apr 9, 2019

在协程里面使用JsContext会出现exception

Environment Details

  • coobjc version:master
  • iOS version:ios12
  • Xcode version:10
  • Other informations:

Steps to Reproduce

co_launch(^{
        JSContext *mJsContext = [[JSContext alloc] init];
        mJsContext.exceptionHandler = ^(JSContext *context, JSValue *exception) {
            NSLog(@"%@", exception);
        };
        [mJsContext evaluateScript:@"var a  = 1"];
    });

运行上述代码,会出现jsException

问题原因找到了,coobjc协程的实现是自建调用栈,JavascriptCore在实现的时候,会先创建一个Thread的C++对象,然后用TLS关联到当前线程,在这个Thread对象中会初始化一个StackBound对象,用来存储栈的边界,栈边界的创建如下:

StackBounds StackBounds::currentThreadStackBoundsInternal()
{
    ASSERT(stackDirection() == StackDirection::Downward);
    if (pthread_main_np()) {
        // FIXME: <rdar://problem/13741204>
        // pthread_get_size lies to us when we're the main thread, use get_rlimit instead
        void* origin = pthread_get_stackaddr_np(pthread_self());
        rlimit limit;
        getrlimit(RLIMIT_STACK, &limit);
        rlim_t size = limit.rlim_cur;
        void* bound = static_cast<char*>(origin) - size;
        return StackBounds { origin, bound };
    }
    return newThreadStackBounds(pthread_self());
}

在上述JavascriptCore代码中会先获取线程的栈基址以及栈空间大小,计算得到origin和bound,然后传给StackBounds,然后在JSEvaluateScript的时候,内部会检查当前栈地址是否在origin和bound中间,防止出现越栈的情况,

void* currentStackPointer()
{
#if COMPILER(GCC_COMPATIBLE)
    return reinterpret_cast<uint8_t*>(__builtin_frame_address(0)) + sizeOfFrameHeader;
#else
    // Make sure that sp is the only local variable declared in this function.
    void* sp = reinterpret_cast<uint8_t*>(&sp) + sizeOfFrameHeader + sizeof(sp);
    return sp;
#endif
}

void checkConsistency() const
    {
#if !ASSERT_DISABLED
        void* currentPosition = currentStackPointer();
        ASSERT(m_origin != m_bound);
        ASSERT(isGrowingDownward()
            ? (currentPosition < m_origin && currentPosition > m_bound)
            : (currentPosition > m_origin && currentPosition < m_bound));
#endif
    }

由于在协程中替换了当前执行的栈空间,导致currentStackPointer获取的地址是我们自建栈空间中的地址,因此会导致currentPosition不在m_origin和m_bound所代表的栈空间范围,导致触发异常,然后该异常会转化为JS异常向上层抛出

image

目前这个问题暂时还无法修复,我们正在研究Stackless的协程实现方式,还需要一定的时间,因此暂时请不要在协程中调用JavascriptCore相关的代码,我们会尽快找到解决方案

@pengyutang125 pengyutang125 added the bug Something isn't working label Apr 9, 2019
@penglzh
Copy link

penglzh commented Sep 18, 2019

这个bug修复了么

@seuzxh
Copy link

seuzxh commented Sep 11, 2020

@pengyutang125 如果将调用方法 dispatch_async 到 main_thread 再执行是不是就可以解决了

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

5 participants