JohnMasen / ChakraCore.NET

A dotnet hosting library for chakra (javascript) engine
MIT License
71 stars 22 forks source link

Linux/Mac OS - *Stack Smashing Detected* when using Promises #27

Open vms20591 opened 5 years ago

vms20591 commented 5 years ago

Hi,

When running any JS code that has promises in them like the following example, a stack smashing detected error is thrown and program crashes.

function asyncTask() {
    return new Promise((res, rej) => {
        res();
    });
}

asyncTask().then(() => {
    // code
});

I have created a repro project here.

Tried analyzing the coredump using gdb and got the following,

Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `dotnet exec /home/user/ChakraNetTest/SegFaultRepro/bin/Debug/ne'.
Program terminated with signal SIGABRT, Aborted.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50  ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
[Current thread is 1 (Thread 0x7fad8887d700 (LWP 3192))]
(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007fb669f9c535 in __GI_abort () at abort.c:79
#2  0x00007fb66a003516 in __libc_message (action=action@entry=do_abort, fmt=fmt@entry=0x7fb66a1279ee "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:181
#3  0x00007fb66a0a7431 in __GI___fortify_fail_abort (need_backtrace=need_backtrace@entry=false, msg=msg@entry=0x7fb66a1279cc "stack smashing detected") at fortify_fail.c:33
#4  0x00007fb66a0a73f2 in __stack_chk_fail () at stack_chk_fail.c:29
#5  0x00007fb6557fac8e in sigsegv_handler(int, siginfo_t*, void*) () from /usr/lib/libChakraCore.so
#6  0x0000000000000000 in ?? ()

Details:

OS: Ubuntu 18.10
.NET Core - 2.1 & 2.2
ChakraCore.NET - 1.3.2
Microsoft.ChakraCore - 1.11.7

Edit:

JohnMasen commented 5 years ago

thanks for your feedback, I'll look at it soon.

JohnMasen commented 5 years ago

hi, I tried it on my windows 10 laptop, but I can't repro this issue. however I found a related issue at https://github.com/Microsoft/ChakraCore/issues/5973 , maybe this could help.

vms20591 commented 5 years ago

Hi,

Thanks for the update. No issues on Windows 10, it occurs on Linux and Mac OS. I did look at the above issue and built ChakraCore with the changes mentioned. I don't get stack smashed error, but SIGSEV instead.

So, wondering if anything can be done from ChakraCore.NET for this.

JohnMasen commented 5 years ago

I'm do some test later, but not sure if I could fix it at the wrapper side.

vezaynk commented 4 years ago

@JohnMasen Any progress on it?

JohnMasen commented 4 years ago

Sorry for late response. SIGSEV seems shared the same root cause of "stack smashing" . can you please try update to the latest chakracore and see if the problem still exists?

JohnMasen commented 4 years ago

I think I may found the root cause. SIGSEV exception hides the real exception which is NullReferenceException, it is triggered by javascript calls to an CLR object which has been disposed. the root cause is chakracore context begins to dispose before the promise callback is triggered.

Chakracore will track the object reference and keep it alive until the value has been garbage collected in chakracore context. ideally your object will live as long as js code lives.

However chakracore uses separated threads to run the "main" thread and "promise" thread. it is possible the main thread begins to GC before the promise thread calls back. this happens when context object is no longer used and .NET GC begins to dispose it. As the "promise" thread was referenced by "main" thread object, GC will always dispose the "main" thread first.

solution : keep the context alive until promise method is completed. In a context with "promise" code, there's no guarantee when the js code will finish, I didn't find a good solution in the wrapper level without memory leak. it is suggested keep the context alive until all works finished.
you can find the unit test "PromiseCallFromJS" is checking a flag variable to keep the context alive until promise call is completed. although it was designed to collect the result from promise call, it becomes a workaround of this issue. I just remember I got the same problem when I was testing the code at early stage.

another way is a WorkDone() callback to host in your js code, this soltuion doesn't require host keep checking the flag variable. however it may turns your code a bit more complex.