Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

AddressSanitizer: heap-use-after-free in timerJobWrapper #341

Closed
philippedistributive opened this issue May 7, 2024 · 1 comment · Fixed by #323
Closed

AddressSanitizer: heap-use-after-free in timerJobWrapper #341

philippedistributive opened this issue May 7, 2024 · 1 comment · Fixed by #323
Assignees
Milestone

Comments

@philippedistributive
Copy link
Collaborator

philippedistributive commented May 7, 2024

Issue type

Bug

How did you install PythonMonkey?

None

OS platform and distribution

No response

Python version (python --version)

No response

PythonMonkey version (pip show pythonmonkey)

No response

Bug Description

Please investigate whether this heap-use-after-free report from AddressSanitizer in timerJobWrapper while running ping.py (https://github.com/wesgarland/python-launch-job/blob/main/ping.py) is legit and needs fixing:

build pm with

image

or using the newly introduced
export BUILD_TYPE=Sanitize

run with
export ASAN_OPTIONS=detect_leaks=1;export LSAN_OPTIONS=suppressions=suppr.txt;export LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.8

where suppr.txt is
leak:_PyObject_Malloc
leak:_PyObject_Realloc
leak:__interceptor_malloc
leak:__interceptor_realloc
leak:JobQueue::JobQueue
leak:DictType::getPyObject
leak:ListType::getPyObject
leak:JSFunctionProxyMethodDefinitions::JSFunctionProxy_new
leak:BufferType::toJsTypedArray
leak:JSMethodProxyMethodDefinitions::JSMethodProxy_new
leak:eval

Report:

==398494==ERROR: AddressSanitizer: heap-use-after-free on address 0x61100026ee38 at pc 0x7e12d4a7c201 bp 0x7ffc221a18d0 sp 0x7ffc221a18c0
READ of size 1 at 0x61100026ee38 thread T0
#0 0x7e12d4a7c200 in std::__atomic_base::load(std::memory_order) const /usr/include/c++/13/bits/atomic_base.h:505
#1 0x7e12d4a7c200 in std::atomic::operator bool() const /usr/include/c++/13/atomic:87
#2 0x7e12d4a7c200 in PyEventLoop::AsyncHandle::removeRef() /home/philippe/Sources/PythonMonkey/include/PyEventLoop.hh:124
#3 0x7e12d4a7c200 in timerJobWrapper /home/philippe/Sources/PythonMonkey/src/PyEventLoop.cc:51
#4 0x7e12d7fb1db4 in cfunction_call Objects/methodobject.c:553
#5 0x7e12d7f60320 in _PyObject_MakeTpCall Objects/call.c:214
#6 0x7e12d8077273 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:90
#7 0x7e12d8077273 in context_run Python/context.c:673
#8 0x7e12d7fb2455 in cfunction_vectorcall_FASTCALL_KEYWORDS Objects/methodobject.c:443
#9 0x7e12d7f05955 in do_call_core Python/ceval.c:7352
#10 0x7e12d7f05955 in _PyEval_EvalFrameDefault Python/ceval.c:5376
#11 0x7e12d805d7f3 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:73
#12 0x7e12d805d7f3 in _PyEval_Vector Python/ceval.c:6434
#13 0x7e12d805d7f3 in PyEval_EvalCode Python/ceval.c:1148
#14 0x7e12d80a8078 in run_eval_code_obj Python/pythonrun.c:1710
#15 0x7e12d80a8078 in run_mod Python/pythonrun.c:1731
#16 0x7e12d80a9a0d in pyrun_file Python/pythonrun.c:1626
#17 0x7e12d80a9a0d in _PyRun_SimpleFileObject Python/pythonrun.c:440
#18 0x7e12d80aa08f in _PyRun_AnyFileObject Python/pythonrun.c:79
#19 0x7e12d80cae5f in pymain_run_file_obj Modules/main.c:360
#20 0x7e12d80cae5f in pymain_run_file Modules/main.c:379
#21 0x7e12d80cae5f in pymain_run_python Modules/main.c:601
#22 0x7e12d80cae5f in Py_RunMain Modules/main.c:680
#23 0x7e12d80cb3fd in pymain_main Modules/main.c:710
#24 0x7e12d80cb3fd in Py_BytesMain Modules/main.c:734
#25 0x7e12d7a2814f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#26 0x7e12d7a28208 in __libc_start_main_impl ../csu/libc-start.c:360
#27 0x57a6da8c0094 in _start (/home/philippe/.pyenv/versions/3.11.7/bin/python3.11+0x1094) (BuildId: 7798d529d8030c06d05aff3210bfcc29680c1679)

0x61100026ee38 is located 248 bytes inside of 256-byte region [0x61100026ed40,0x61100026ee40)
freed by thread T0 here:
#0 0x7e12d84e0c50 in operator delete(void*, unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:164
#1 0x7e12d4a7cbcb in std::__new_allocatorPyEventLoop::AsyncHandle::deallocate(PyEventLoop::AsyncHandle*, unsigned long) /usr/include/c++/13/bits/new_allocator.h:168
#2 0x7e12d4a7cbcb in std::allocatorPyEventLoop::AsyncHandle::deallocate(PyEventLoop::AsyncHandle*, unsigned long) /usr/include/c++/13/bits/allocator.h:210
#3 0x7e12d4a7cbcb in std::allocator_traits<std::allocatorPyEventLoop::AsyncHandle >::deallocate(std::allocatorPyEventLoop::AsyncHandle&, PyEventLoop::AsyncHandle*, unsigned long) /usr/include/c++/13/bits/alloc_traits.h:516
#4 0x7e12d4a7cbcb in std::_Vector_base<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle >::_M_deallocate(PyEventLoop::AsyncHandle*, unsigned long) /usr/include/c++/13/bits/stl_vector.h:387
#5 0x7e12d4a7cbcb in void std::vector<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle >::_M_realloc_insertPyEventLoop::AsyncHandle(__gnu_cxx::__normal_iterator<PyEventLoop::AsyncHandle*, std::vector<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle > >, PyEventLoop::AsyncHandle&&) /usr/include/c++/13/bits/vector.tcc:519
#6 0x7e12d4a7cbcb in PyEventLoop::AsyncHandle& std::vector<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle >::emplace_backPyEventLoop::AsyncHandle(PyEventLoop::AsyncHandle&&) /usr/include/c++/13/bits/vector.tcc:123
#7 0x7e12d4a7cbcb in std::vector<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle >::push_back(PyEventLoop::AsyncHandle&&) /usr/include/c++/13/bits/stl_vector.h:1296
#8 0x7e12d4a7cbcb in PyEventLoop::AsyncHandle::getUniqueId(PyEventLoop::AsyncHandle&&) /home/philippe/Sources/PythonMonkey/include/PyEventLoop.hh:74
#9 0x7e12d4a7cbcb in PyEventLoop::AsyncHandle::newEmpty() /home/philippe/Sources/PythonMonkey/include/PyEventLoop.hh:51
#10 0x7e12d4a7cbcb in PyEventLoop::enqueueWithDelay(_object*, double, bool) /home/philippe/Sources/PythonMonkey/src/PyEventLoop.cc:88
#11 0x7e12d4ababc2 in enqueueWithDelay /home/philippe/Sources/PythonMonkey/src/internalBinding/timers.cc:34
#12 0x7e1251caa697 ()
#13 0x7e1251c09acb ()
#14 0x7e1251bff4e8 ()
#15 0x7e12d2cda6e6 in js::jit::MaybeEnterJit(JSContext*, js::RunState&) (/home/philippe/Sources/PythonMonkey/python/pythonmonkey/libmozjs-115.so+0x8da6e6) (BuildId: a8d6e6a0d612ea95c5db4e0a2f2155e199b41e0e)

previously allocated by thread T0 here:
#0 0x7e12d84dfba8 in operator new(unsigned long) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:95
#1 0x7e12d4a7c92a in std::__new_allocatorPyEventLoop::AsyncHandle::allocate(unsigned long, void const*) /usr/include/c++/13/bits/new_allocator.h:147
#2 0x7e12d4a7c92a in std::allocatorPyEventLoop::AsyncHandle::allocate(unsigned long) /usr/include/c++/13/bits/allocator.h:198
#3 0x7e12d4a7c92a in std::allocator_traits<std::allocatorPyEventLoop::AsyncHandle >::allocate(std::allocatorPyEventLoop::AsyncHandle&, unsigned long) /usr/include/c++/13/bits/alloc_traits.h:482
#4 0x7e12d4a7c92a in std::_Vector_base<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle >::_M_allocate(unsigned long) /usr/include/c++/13/bits/stl_vector.h:378
#5 0x7e12d4a7c92a in void std::vector<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle >::_M_realloc_insertPyEventLoop::AsyncHandle(__gnu_cxx::__normal_iterator<PyEventLoop::AsyncHandle*, std::vector<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle > >, PyEventLoop::AsyncHandle&&) /usr/include/c++/13/bits/vector.tcc:459
#6 0x7e12d4a7c92a in PyEventLoop::AsyncHandle& std::vector<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle >::emplace_backPyEventLoop::AsyncHandle(PyEventLoop::AsyncHandle&&) /usr/include/c++/13/bits/vector.tcc:123
#7 0x7e12d4a7c92a in std::vector<PyEventLoop::AsyncHandle, std::allocatorPyEventLoop::AsyncHandle >::push_back(PyEventLoop::AsyncHandle&&) /usr/include/c++/13/bits/stl_vector.h:1296
#8 0x7e12d4a7c92a in PyEventLoop::AsyncHandle::getUniqueId(PyEventLoop::AsyncHandle&&) /home/philippe/Sources/PythonMonkey/include/PyEventLoop.hh:74
#9 0x7e12d4a7c92a in PyEventLoop::AsyncHandle::newEmpty() /home/philippe/Sources/PythonMonkey/include/PyEventLoop.hh:51
#10 0x7e12d4a7c92a in PyEventLoop::enqueueWithDelay(_object*, double, bool) /home/philippe/Sources/PythonMonkey/src/PyEventLoop.cc:88
#11 0x7e12d4ababc2 in enqueueWithDelay /home/philippe/Sources/PythonMonkey/src/internalBinding/timers.cc:34
#12 0x7e12d25514e3 in js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct, js::CallReason) (/home/philippe/Sources/PythonMonkey/python/pythonmonkey/libmozjs-115.so+0x1514e3) (BuildId: a8d6e6a0d612ea95c5db4e0a2f2155e199b41e0e)

SUMMARY: AddressSanitizer: heap-use-after-free /usr/include/c++/13/bits/atomic_base.h:505 in std::__atomic_base::load(std::memory_order) const
Shadow bytes around the buggy address:
0x61100026eb80: fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa fa
0x61100026ec00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x61100026ec80: 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa fa
0x61100026ed00: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
0x61100026ed80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
=>0x61100026ee00: fd fd fd fd fd fd fd[fd]fa fa fa fa fa fa fa fa
0x61100026ee80: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x61100026ef00: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x61100026ef80: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x61100026f000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x61100026f080: 00 00 00 00 00 00 00 fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==398494==ABORTING

Standalone code to reproduce the issue

No response

Relevant log output or backtrace

No response

Additional info if applicable

No response

What branch of PythonMonkey were you developing on? (If applicable)

No response

@zollqir
Copy link
Collaborator

zollqir commented May 7, 2024

just added a Sanitize build type to enable AddressSanitizer. you can build it with BUILD_TYPE=Sanitize poetry install, though note you may still need to set environment variables when actually running the code, such as ASAN_OPTIONS, LSAN_OPTIONS, or LD_PRELOAD, as those variables matter at runtime

Xmader added a commit that referenced this issue May 8, 2024
…matically unref'ed sometimes

See issue: heap-use-after-free in timerJobWrapper (#341)

We need to ensure the memory block doesn't move for reallocation before we can use the pointer to the timer's `AsyncHandle`, as we could have multiple new `setTimeout` calls to expand the `_timeoutIdMap` vector while running the job function in parallel.
@github-project-automation github-project-automation bot moved this from Ready To Do to Done in PythonMonkey Kanban Board May 8, 2024
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
Status: Done
3 participants