Repository navigation
AsyncProgressWorker::OnProgress is invoked without arg sometimes #821
Copy link
Copy link
Closed
Labels
Description
I've got a basic AsyncProgressWorker that's very similar to the example. I'm invoking progress.Send(thing, 1) a few hundred times per second, and seeing OnProgress invoked sometimes with (info=nullptr, count=0):
Thread 1 "node" received signal SIGSEGV, Segmentation fault.
0x00007ffff523ae45 in UmapWorker::OnProgress (this=0x486e420, info=0x0, count=<optimized out>) at /home/zbjornson/node-cuml/node_modules/node-addon-api/napi-inl.h:4248
4248 return Napi::Env(_env);
(gdb) bt
#0 0x00007ffff523ae45 in UmapWorker::OnProgress (this=0x486e420, info=0x0, count=<optimized out>) at /home/zbjornson/node-cuml/node_modules/node-addon-api/napi-inl.h:4248
#1 0x00007ffff52354ef in Napi::AsyncProgressWorker<ProgressInfo>::OnWorkProgress (this=0x486e420) at /usr/include/x86_64-linux-gnu/c++/8/bits/gthr-default.h:778
#2 Napi::AsyncProgressWorkerBase<void>::OnAsyncWorkProgress (data=<optimized out>) at /home/zbjornson/node-cuml/node_modules/node-addon-api/napi-inl.h:4732
#3 0x00007ffff5237083 in std::function<void (Napi::Env, Napi::Function)>::operator()(Napi::Env, Napi::Function) const (__args#1=..., __args#0=..., this=0x7fff466e62f0) at /usr/include/c++/8/bits/std_function.h:682
#4 Napi::ThreadSafeFunction::CallJS (env=0x47e10c0, jsCallback=0x45443b8, data=0x7fff466e62f0) at /home/zbjornson/node-cuml/node_modules/node-addon-api/napi-inl.h:4667
#5 0x0000000000a0d738 in v8impl::(anonymous namespace)::ThreadSafeFunction::IdleCb(uv_idle_s*) ()
#6 0x00000000013772e9 in uv__run_idle (loop=loop@entry=0x4444220 <default_loop_struct>) at ../deps/uv/src/unix/loop-watcher.c:68
#7 0x0000000001370110 in uv_run (loop=0x4444220 <default_loop_struct>, mode=UV_RUN_DEFAULT) at ../deps/uv/src/unix/core.c:374
#8 0x0000000000a7ab94 in node::NodeMainInstance::Run() ()
#9 0x0000000000a0a861 in node::Start(int, char**) ()
#10 0x00007ffff7a780b3 in __libc_start_main (main=0x9a3cf0 <main>, argc=3, argv=0x7fffffffdfa8, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdf98) at ../csu/libc-start.c:308
#11 0x00000000009a526c in _start ()It happens with less frequent invocations also, but far less frequently.
That's easy enough to guard for, but is that expected? I don't see it mentioned in the docs.
Edit 13-Oct I can't find a way to reproduce this by modifying the example. In my real scenario, the async work is CUDA code. Not sure if that's different in some critical way from sleeping the thread. Here's a pair of strace captures from when count=0 (top) and count=1 (bottom):
getpid() = 5091
futex(0x45bd1a4, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x45bd150, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x45bd150, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x45bd1a0, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x45bd150, FUTEX_WAKE_PRIVATE, 1) = 1
getpid() = 5091
futex(0x44441ec, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4444180, FUTEX_WAKE_PRIVATE, 1) = 1
epoll_wait(13, [{EPOLLIN, {u32=16, u64=16}}], 1024, 2886) = 1
read(16, "\2\0\0\0\0\0\0\0", 1024) = 8
epoll_wait(13, [{EPOLLIN, {u32=16, u64=16}}], 1024, 2886) = 1
read(16, "\1\0\0\0\0\0\0\0", 1024) = 8
futex(0x45e2b48, FUTEX_WAKE_PRIVATE, 1) = 0
epoll_wait(13, [{EPOLLIN, {u32=16, u64=16}}], 1024, 2183) = 1
read(16, "\1\0\0\0\0\0\0\0", 1024) = 8
epoll_wait(13, [{EPOLLIN, {u32=16, u64=16}}], 1024, 2182) = 1
read(16, "\1\0\0\0\0\0\0\0", 1024) = 8
futex(0x45e2b48, FUTEX_WAKE_PRIVATE, 1) = 0
epoll_wait(13, [{EPOLLIN, {u32=16, u64=16}}], 1024, 2182) = 1
read(16, "\1\0\0\0\0\0\0\0", 1024) = 8
write(1, "count=0\n", 8) = 8
rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, ~[RTMIN RT_1], [], 8) = 0
getpid() = 5091
gettid() = 5091
tgkill(5091, 5091, SIGABRT) = 0
getpid() = 5005
futex(0x5c421a0, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x5c421a0, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x5c421a0, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x5c42150, FUTEX_WAKE_PRIVATE, 1) = 1
getpid() = 5005
futex(0x44441ec, FUTEX_WAKE_PRIVATE, 1) = 1
futex(0x4444180, FUTEX_WAKE_PRIVATE, 1) = 1
epoll_wait(13, [{EPOLLIN, {u32=16, u64=16}}], 1024, 5917) = 1
read(16, "\2\0\0\0\0\0\0\0", 1024) = 8
write(1, "count=1\n", 8) = 8
epoll_wait(13, strace: Process 5005 detached
<detached ...>
Reactions are currently unavailable
Activity
mhdawson commentedon Nov 2, 2020
@zbjornson can you share the code? Since you can't recreate with the sample, its probably something in the code that you've not shared in the issue.
zbjornson commentedon Nov 4, 2020
@mhdawson here's a repro minimally modified from the example (only
ExecuteandOnProgressmodified)This prints something like:
mhdawson commentedon Nov 4, 2020
Can you give me all the files for the cut down example needed to build/run?
Possibly not relevant, I'm wondering if there is something going on with
statuspart inprogress.Send(&pi, 1)is going to make a copy of pi, but not a deep copy of the status field (that might be just fine but just not 100% of the lifetime for the string defined in the initializer). I see that is not referred elsewhere in the code, do you still see the problem if you remove that field from ProgressInfo?zbjornson commentedon Nov 4, 2020
Sure, full repo here: https://gist.github.com/zbjornson/5edc22bb7381e4c2a1f00aee44abe4b7 (or
git clone git@gist.github.com:5edc22bb7381e4c2a1f00aee44abe4b7.git).I pared it down further so it's just
AsyncProgressWorker<float>.legendecas commentedon Nov 8, 2020
@zbjornson thanks for your detailed re-produce and reporting here!
I investigated the re-produce and found out the issue may be related to the timing of SendProgress been called during two async callback of thread-safe function:
As far as I can tell, the AsyncProgressWorker guarantees at least once of the progress callback. However, in the issue, the callback was called with unexpected data (data with
nullptrand count with 0 - never been sent with that progress), so this is a confirmed bug.I'll file a fix.
zbjornson commentedon Nov 11, 2020
Thank you!
src: empty data OnProgress in AsyncProgressWorker
src: empty data OnProgress in AsyncProgressWorker
src: empty data OnProgress in AsyncProgressWorker
src: empty data OnProgress in AsyncProgressWorker