profile
viewpoint
Bastien Orivel Eijebong https://bananium.fr Sometimes I don't update dependencies. Times I've broken firefox's build: 7

ArnaudLevaufre/banana 1

Game made for school project during my first year at Enib

Eijebong/alacritty 0

A cross-platform, GPU-accelerated terminal emulator

Eijebong/ammonia 0

An HTML sanitizer

Eijebong/android_logger-rs 0

A Rust logging implementation for `log` which hooks to android log output

Eijebong/angle 0

A conformant OpenGL ES 2 implementation for Windows.

Eijebong/ascii-canvas 0

simple canvas for drawing lines and styled text and emitting to the terminal

Eijebong/askama 0

Type-safe, compiled Jinja-like templates for Rust

Eijebong/assert_cli 0

Test CLI Applications in Rust.

pull request commenthousleyjk/ws-rs

Limit in/out buffer growth with a Vec<u8> wrapper

Sorry, I had notifications muted for this repository. I don't have time nor motivation for open source these days but I'd be happy to add someone as maintainer

maciejhirsz

comment created time in 23 days

startedmozilla/rr

started time in a month

PR opened mgba-emu/mgba

Fix a race condition on `InputController::m_pendingEvents`

This member could be accessed at the same from different threads leading to random (rare) crashes.

Fixes #1875

+5 -0

0 comment

2 changed files

pr created time in a month

create barnchEijebong/mgba

branch : fix-race-condition-events

created branch time in a month

fork Eijebong/mgba

mGBA Game Boy Advance Emulator

https://mgba.io/

fork in a month

issue commentmgba-emu/mgba

Race condition on `InputController::m_pendingEvents` access

Sure. TSAN seems to be happy with the moved lockers. I'll play for a while and send a PR if I don't see any issue with it.

Eijebong

comment created time in 2 months

issue commentmgba-emu/mgba

Race condition on `InputController::m_pendingEvents` access

FWIW,I've been playing with this patch since then and it works fine

diff --git a/src/platform/qt/InputController.cpp b/src/platform/qt/InputController.cpp
index f19130dd..681f98d5 100644
--- a/src/platform/qt/InputController.cpp
+++ b/src/platform/qt/InputController.cpp
@@ -650,14 +650,17 @@ void InputController::sendGamepadEvent(QEvent* event) {
 }

 void InputController::postPendingEvent(GBAKey key) {
+       QWriteLocker l(&m_eventsLock);
        m_pendingEvents.insert(key);
 }

 void InputController::clearPendingEvent(GBAKey key) {
+       QWriteLocker l(&m_eventsLock);
        m_pendingEvents.remove(key);
 }

 bool InputController::hasPendingEvent(GBAKey key) const {
+       QReadLocker l(&m_eventsLock);
        return m_pendingEvents.contains(key);
 }

diff --git a/src/platform/qt/InputController.h b/src/platform/qt/InputController.h
index 5c2c8502..72a766c9 100644
--- a/src/platform/qt/InputController.h
+++ b/src/platform/qt/InputController.h
@@ -10,6 +10,7 @@

 #include <QImage>
 #include <QMutex>
+#include <QReadWriteLock>
 #include <QObject>
 #include <QSet>
 #include <QTimer>
@@ -181,6 +182,7 @@ private:
        QTimer m_gamepadTimer{nullptr};

        QSet<GBAKey> m_pendingEvents;
+       mutable QReadWriteLock m_eventsLock;
Eijebong

comment created time in 2 months

issue openedmgba-emu/mgba

Race condition on `InputController::m_pendingEvents` access

Hello,

I've been seeing a few crashes related to InputController::m_pendingEvents.

The backtrace looks like this:

Thread 1 (Thread 0x7f35f883f640 (LWP 406716)):
#0  QHashNode<GBAKey, QHashDummyValue>::same_key (key0=<synthetic pointer>: GBA_KEY_A, h0=1385392141, this=0x55b745df3af0) at /usr/include/qt/QtCore/qhash.h:175
#1  QHash<GBAKey, QHashDummyValue>::findNode (h=1385392141, akey=<synthetic pointer>: GBA_KEY_A, this=0x55b21d54e488) at /usr/include/qt/QtCore/qhash.h:931
#2  QHash<GBAKey, QHashDummyValue>::findNode (ahp=0x0, akey=<synthetic pointer>: GBA_KEY_A, this=0x55b21d54e488) at /usr/include/qt/QtCore/qhash.h:950
#3  QHash<GBAKey, QHashDummyValue>::contains (akey=<synthetic pointer>: GBA_KEY_A, this=0x55b21d54e488) at /usr/include/qt/QtCore/qhash.h:920
#4  QSet<GBAKey>::contains (value=<synthetic pointer>: GBA_KEY_A, this=0x55b21d54e488) at /usr/include/qt/QtCore/qset.h:97
#5  QGBA::InputController::hasPendingEvent (this=this@entry=0x55b21d54e258, key=key@entry=GBA_KEY_A) at /home/eijebong/mgba/src/platform/qt/InputController.cpp:661
#6  0x000055b21b78348a in QGBA::InputController::pollEvents (this=0x55b21d54e258) at /home/eijebong/mgba/src/platform/qt/InputController.cpp:392
#7  0x000055b21b755511 in QGBA::CoreController::updateKeys (this=this@entry=0x55b21d61b8c0) at /home/eijebong/mgba/src/platform/qt/CoreController.cpp:904
#8  0x000055b21b757dcd in QGBA::CoreController::finishFrame (this=0x55b21d61b8c0) at /home/eijebong/mgba/src/platform/qt/CoreController.cpp:939
#9  0x00007f36300923ac in GBAFrameEnded (gba=0x7f3624221000) at /home/eijebong/mgba/src/gba/gba.c:848
#10 0x00007f36300b87d2 in _startHdraw (timing=<optimized out>, context=0x7f3624221cd0, cyclesLate=6) at /home/eijebong/mgba/src/gba/video.c:183
#11 0x00007f36300315a2 in mTimingTick (timing=timing@entry=0x7f36242228f0, cycles=<optimized out>) at /home/eijebong/mgba/src/core/timing.c:98
#12 0x00007f3630090f20 in GBAProcessEvents (cpu=0x7f3624597000) at /home/eijebong/mgba/src/gba/gba.c:291
#13 0x00007f363003047a in _mCoreThreadRun (context=0x55b21d61b8d0) at /home/eijebong/mgba/src/core/thread.c:202
#14 0x00007f362d8603e9 in start_thread () from /usr/lib/libpthread.so.0
#15 0x00007f362c2e3293 in clone () from /usr/lib/libc.so.6

There is always a second thread that looks like this:

Thread 4 (Thread 0x7f3625bb4bc0 (LWP 406689)):
#0  0x00007f36301a434a in ?? () from /usr/lib/libSDL2-2.0.so.0
#1  0x000055b21b82f7fd in mSDLUpdateJoysticks (events=events@entry=0x55b21b9b4b40 <QGBA::InputController::s_sdlEvents>, config=0x7ffc26c28f90) at /home/eijebong/mgba/src/platform/sdl/sdl-events.c:351
#2  0x000055b21b7849e9 in QGBA::InputController::updateJoysticks (this=0x55b21d54e258) at /home/eijebong/mgba/src/platform/qt/ConfigController.h:88
#3  0x00007f362c88ba06 in ?? () from /usr/lib/libQt5Core.so.5
#4  0x00007f362c88fa7b in QTimer::timeout(QTimer::QPrivateSignal) () from /usr/lib/libQt5Core.so.5
#5  0x00007f362c8810ef in QObject::event(QEvent*) () from /usr/lib/libQt5Core.so.5
#6  0x00007f362d31e702 in QApplicationPrivate::notify_helper(QObject*, QEvent*) () from /usr/lib/libQt5Widgets.so.5
#7  0x00007f362c85479a in QCoreApplication::notifyInternal2(QObject*, QEvent*) () from /usr/lib/libQt5Core.so.5
#8  0x00007f362c8ac695 in QTimerInfoList::activateTimers() () from /usr/lib/libQt5Core.so.5
#9  0x00007f362c8acf42 in ?? () from /usr/lib/libQt5Core.so.5
#10 0x00007f362806c43c in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
#11 0x00007f36280ba1d9 in ?? () from /usr/lib/libglib-2.0.so.0
#12 0x00007f362806b221 in g_main_context_iteration () from /usr/lib/libglib-2.0.so.0
#13 0x00007f362c8ad311 in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/libQt5Core.so.5
#14 0x00007f362c85311c in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) () from /usr/lib/libQt5Core.so.5
#15 0x00007f362c85b5a4 in QCoreApplication::exec() () from /usr/lib/libQt5Core.so.5
#16 0x000055b21b72034d in main (argc=<optimized out>, argv=0x7ffc26c28eb0) at /home/eijebong/mgba/src/platform/qt/main.cpp:116

In frame 0, the hash_node it's trying to compare to is not valid anymore which lead me to think it was a race condition on m_pendingEvents, thread 0 reading it while thread 4 is writing it.

After recompiling with thread-sanitizer, I got this:

WARNING: ThreadSanitizer: data race (pid=413887)
  Read of size 8 at 0x7b24000084f0 by thread T22:
    #0 QHash<GBAKey, QHashDummyValue>::findNode(GBAKey const&, unsigned int) const /usr/include/qt/QtCore/qhash.h:931 (mgba-qt+0x13361d)
    #1 QHash<GBAKey, QHashDummyValue>::findNode(GBAKey const&, unsigned int*) const /usr/include/qt/QtCore/qhash.h:950 (mgba-qt+0x13361d)
    #2 QHash<GBAKey, QHashDummyValue>::contains(GBAKey const&) const /usr/include/qt/QtCore/qhash.h:920 (mgba-qt+0x13361d)
    #3 QSet<GBAKey>::contains(GBAKey const&) const /usr/include/qt/QtCore/qset.h:97 (mgba-qt+0x13361d)
    #4 QGBA::InputController::hasPendingEvent(GBAKey) const /home/eijebong/mgba_asan/src/platform/qt/InputController.cpp:661 (mgba-qt+0x13361d)
    #5 QGBA::InputController::pollEvents() /home/eijebong/mgba_asan/src/platform/qt/InputController.cpp:392 (mgba-qt+0x133748)
    #6 QGBA::CoreController::updateKeys() /home/eijebong/mgba_asan/src/platform/qt/CoreController.cpp:904 (mgba-qt+0xe4b24)
    #7 QGBA::CoreController::finishFrame() /home/eijebong/mgba_asan/src/platform/qt/CoreController.cpp:939 (mgba-qt+0xe8aa7)
    #8 operator() /home/eijebong/mgba_asan/src/platform/qt/CoreController.cpp:101 (mgba-qt+0xe8c61)
    #9 _FUN /home/eijebong/mgba_asan/src/platform/qt/CoreController.cpp:102 (mgba-qt+0xe8c61)
    #10 _frameEnded /home/eijebong/mgba_asan/src/core/thread.c:120 (libmgba.so.0.9+0x83359)
    #11 GBAFrameEnded /home/eijebong/mgba_asan/src/gba/gba.c:848 (libmgba.so.0.9+0x14e1d5)
    #12 _startHdraw /home/eijebong/mgba_asan/src/gba/video.c:183 (libmgba.so.0.9+0x188a98)
    #13 mTimingTick /home/eijebong/mgba_asan/src/core/timing.c:98 (libmgba.so.0.9+0x872c4)
    #14 GBAProcessEvents /home/eijebong/mgba_asan/src/gba/gba.c:291 (libmgba.so.0.9+0x14bd2c)
    #15 ARMRunLoop /home/eijebong/mgba_asan/src/arm/arm.c:275 (libmgba.so.0.9+0xc8ad1)
    #16 _GBACoreRunLoop /home/eijebong/mgba_asan/src/gba/core.c:662 (libmgba.so.0.9+0x144e2d)
    #17 _mCoreThreadRun /home/eijebong/mgba_asan/src/core/thread.c:202 (libmgba.so.0.9+0x85249)

  Previous write of size 8 at 0x7b24000084f0 by main thread:
    #0 operator new[](unsigned long) /build/gcc/src/gcc/libsanitizer/tsan/tsan_new_delete.cpp:70 (libtsan.so.0+0x8d314)
    #1 QHashData::rehash(int) <null> (libQt5Core.so.5+0x107f04)
    #2 QGBA::InputController::testGamepad(int) /home/eijebong/mgba_asan/src/platform/qt/InputController.cpp:587 (mgba-qt+0x1372d5)
    #3 operator() /home/eijebong/mgba_asan/src/platform/qt/InputController.cpp:52 (mgba-qt+0x139e75)
    #4 call /usr/include/qt/QtCore/qobjectdefs_impl.h:146 (mgba-qt+0x139e75)
    #5 call<QtPrivate::List<>, void> /usr/include/qt/QtCore/qobjectdefs_impl.h:256 (mgba-qt+0x139e75)
    #6 impl /usr/include/qt/QtCore/qobjectdefs_impl.h:443 (mgba-qt+0x139e75)
    #7 <null> <null> (libQt5Core.so.5+0x2e8a05)
    #8 __libc_start_main <null> (libc.so.6+0x28151)

  Location is heap block of size 136 at 0x7b24000084c0 allocated by main thread:
    #0 operator new[](unsigned long) /build/gcc/src/gcc/libsanitizer/tsan/tsan_new_delete.cpp:70 (libtsan.so.0+0x8d314)
    #1 QHashData::rehash(int) <null> (libQt5Core.so.5+0x107f04)
    #2 QGBA::InputController::testGamepad(int) /home/eijebong/mgba_asan/src/platform/qt/InputController.cpp:587 (mgba-qt+0x1372d5)
    #3 operator() /home/eijebong/mgba_asan/src/platform/qt/InputController.cpp:52 (mgba-qt+0x139e75)
    #4 call /usr/include/qt/QtCore/qobjectdefs_impl.h:146 (mgba-qt+0x139e75)
    #5 call<QtPrivate::List<>, void> /usr/include/qt/QtCore/qobjectdefs_impl.h:256 (mgba-qt+0x139e75)
    #6 impl /usr/include/qt/QtCore/qobjectdefs_impl.h:443 (mgba-qt+0x139e75)
    #7 <null> <null> (libQt5Core.so.5+0x2e8a05)
    #8 __libc_start_main <null> (libc.so.6+0x28151)

  Thread T22 'CPU Thread' (tid=413913, running) created by main thread at:
    #0 pthread_create /build/gcc/src/gcc/libsanitizer/tsan/tsan_interceptors_posix.cpp:962 (libtsan.so.0+0x5efab)
    #1 ThreadCreate /home/eijebong/mgba_asan/include/mgba-util/platform/posix/threading.h:81 (libmgba.so.0.9+0x83914)
    #2 mCoreThreadStart /home/eijebong/mgba_asan/src/core/thread.c:332 (libmgba.so.0.9+0x83914)
    #3 QGBA::CoreController::start() /home/eijebong/mgba_asan/src/platform/qt/CoreController.cpp:369 (mgba-qt+0xe43de)
    #4 QGBA::Window::setController(QGBA::CoreController*, QString const&) /home/eijebong/mgba_asan/src/platform/qt/Window.cpp:1915 (mgba-qt+0x1f1bad)
    #5 QGBA::Window::selectROM() /home/eijebong/mgba_asan/src/platform/qt/Window.cpp:337 (mgba-qt+0x1f2b1b)
    #6 void std::__invoke_impl<void, void (QGBA::Window::*&)(), QGBA::Window*&>(std::__invoke_memfun_deref, void (QGBA::Window::*&)(), QGBA::Window*&) /usr/include/c++/10.2.0/bits/invoke.h:73 (mgba-qt+0x203b47)
    #7 std::__invoke_result<void (QGBA::Window::*&)(), QGBA::Window*&>::type std::__invoke<void (QGBA::Window::*&)(), QGBA::Window*&>(void (QGBA::Window::*&)(), QGBA::Window*&) /usr/include/c++/10.2.0/bits/invoke.h:95 (mgba-qt+0x203b47)
    #8 void std::_Bind<void (QGBA::Window::*(QGBA::Window*))()>::__call<void, , 0ul>(std::tuple<>&&, std::_Index_tuple<0ul>) /usr/include/c++/10.2.0/functional:416 (mgba-qt+0x203b47)
    #9 void std::_Bind<void (QGBA::Window::*(QGBA::Window*))()>::operator()<, void>() /usr/include/c++/10.2.0/functional:499 (mgba-qt+0x203b47)
    #10 void std::__invoke_impl<void, std::_Bind<void (QGBA::Window::*(QGBA::Window*))()>&>(std::__invoke_other, std::_Bind<void (QGBA::Window::*(QGBA::Window*))()>&) /usr/include/c++/10.2.0/bits/invoke.h:60 (mgba-qt+0x203b47)
    #11 std::enable_if<std::__and_<std::is_void<void>, std::__is_invocable<std::_Bind<void (QGBA::Window::*(QGBA::Window*))()>&> >::value, void>::type std::__invoke_r<void, std::_Bind<void (QGBA::Window::*(QGBA::Window*))()>&>(std::_Bind<void (QGBA::Window::*(QGBA::Window*))()>&) /usr/include/c++/10.2.0/bits/invoke.h:153 (mgba-qt+0x203b47)
    #12 std::_Function_handler<void (), std::_Bind<void (QGBA::Window::*(QGBA::Window*))()> >::_M_invoke(std::_Any_data const&) /usr/include/c++/10.2.0/bits/std_function.h:291 (mgba-qt+0x203b47)
    #13 std::function<void ()>::operator()() const /usr/include/c++/10.2.0/bits/std_function.h:622 (mgba-qt+0xb57e7)
    #14 QGBA::Action::trigger(bool) /home/eijebong/mgba_asan/src/platform/qt/Action.cpp:75 (mgba-qt+0xb57e7)
    #15 operator() /home/eijebong/mgba_asan/src/platform/qt/ActionMapper.cpp:86 (mgba-qt+0xb5d51)
    #16 call /usr/include/qt/QtCore/qobjectdefs_impl.h:146 (mgba-qt+0xb5d51)
    #17 call<QtPrivate::List<bool>, void> /usr/include/qt/QtCore/qobjectdefs_impl.h:256 (mgba-qt+0xb5d51)
    #18 impl /usr/include/qt/QtCore/qobjectdefs_impl.h:443 (mgba-qt+0xb5d51)
    #19 <null> <null> (libQt5Core.so.5+0x2e8a05)
    #20 __libc_start_main <null> (libc.so.6+0x28151)

SUMMARY: ThreadSanitizer: data race /usr/include/qt/QtCore/qhash.h:931 in QHash<GBAKey, QHashDummyValue>::findNode(GBAKey const&, unsigned int) const

which confirms said theory. Here thread 22 is reading while thread 0 is writing.

This is related to the code here: https://github.com/mgba-emu/mgba/blob/756c6e18abfb2691a1ceac371624a5956823d303/src/platform/qt/InputController.cpp#L652-L662 which could use a QReadWriteLock I guess. Since I don't know the code base there might be a better solution though.

created time in 2 months

startedv1cont/yad

started time in 3 months

pull request commentimage-rs/image-png

Update miniz_oxide to 0.4

Oh sorry, I didn't check currently open PRs

Eijebong

comment created time in 3 months

PR opened image-rs/image-png

Update miniz_oxide to 0.4
+15 -8

0 comment

2 changed files

pr created time in 3 months

create barnchEijebong/image-png

branch : update-miniz

created branch time in 3 months

more