Skip to content

gh-150175: Fix ThreadingMock call_count race condition#150176

Merged
cjw296 merged 1 commit into
python:mainfrom
saisneha196:fix-threadingmock-call-count-race
May 21, 2026
Merged

gh-150175: Fix ThreadingMock call_count race condition#150176
cjw296 merged 1 commit into
python:mainfrom
saisneha196:fix-threadingmock-call-count-race

Conversation

@saisneha196
Copy link
Copy Markdown
Contributor

Problem

ThreadingMock._increment_mock_call() is not thread-safe.
Multiple threads calling the mock simultaneously lose increments
due to race conditions on call_count and other attributes.

This causes intermittent test failures like:
AssertionError: 983 != 1000

Reported in Yocto Project bug:
https://bugzilla.yoctoproject.org/show_bug.cgi?id=16213

Fixes gh-150175

Root Cause

In the base Mock class, _increment_mock_call does:
self.called = True
self.call_count += 1 # not atomic!
self.call_args = _call
self.call_args_list.append(_call)

These are not protected by any lock in ThreadingMock.

Fix

Override _increment_mock_call in ThreadingMixin and wrap it
with the existing _mock_calls_events_lock:

def _increment_mock_call(self, /, *args, **kwargs):
    with self._mock_calls_events_lock:
        super()._increment_mock_call(*args, **kwargs)

Testing

Verified on both x86 and ARM64 (qemuarm64):

  • Before fix: 23/30 failures with 50 threads x 10000 calls
  • After fix: 0/30 failures with 50 threads x 10000 calls

@saisneha196 saisneha196 requested a review from cjw296 as a code owner May 21, 2026 05:31
@python-cla-bot
Copy link
Copy Markdown

python-cla-bot Bot commented May 21, 2026

All commit authors signed the Contributor License Agreement.

CLA signed

@bedevere-app
Copy link
Copy Markdown

bedevere-app Bot commented May 21, 2026

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@bedevere-app
Copy link
Copy Markdown

bedevere-app Bot commented May 21, 2026

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

ThreadingMock._increment_mock_call() was not thread-safe.
Multiple threads calling the mock simultaneously could lose
increments due to race conditions on call_count and other
attributes.

Fix by overriding _increment_mock_call in ThreadingMixin
and wrapping it with the existing _mock_calls_events_lock.
@saisneha196 saisneha196 force-pushed the fix-threadingmock-call-count-race branch from d444e47 to 8e08b9c Compare May 21, 2026 06:32
@cjw296 cjw296 merged commit 388e023 into python:main May 21, 2026
52 checks passed
@cjw296 cjw296 added 3.13 bugs and security fixes 3.14 bugs and security fixes needs backport to 3.13 bugs and security fixes needs backport to 3.14 bugs and security fixes 3.15 pre-release feature fixes, bugs and security fixes 3.16 new features, bugs and security fixes needs backport to 3.15 pre-release feature fixes, bugs and security fixes labels May 21, 2026
@miss-islington-app
Copy link
Copy Markdown

Thanks @saisneha196 for the PR, and @cjw296 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.14.
🐍🍒⛏🤖

@miss-islington-app
Copy link
Copy Markdown

Thanks @saisneha196 for the PR, and @cjw296 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.13.
🐍🍒⛏🤖

@miss-islington-app
Copy link
Copy Markdown

Thanks @saisneha196 for the PR, and @cjw296 for merging it 🌮🎉.. I'm working now to backport this PR to: 3.15.
🐍🍒⛏🤖

@bedevere-app
Copy link
Copy Markdown

bedevere-app Bot commented May 21, 2026

GH-150180 is a backport of this pull request to the 3.13 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.13 bugs and security fixes label May 21, 2026
@bedevere-app
Copy link
Copy Markdown

bedevere-app Bot commented May 21, 2026

GH-150181 is a backport of this pull request to the 3.14 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.14 bugs and security fixes label May 21, 2026
@bedevere-app
Copy link
Copy Markdown

bedevere-app Bot commented May 21, 2026

GH-150182 is a backport of this pull request to the 3.15 branch.

@bedevere-app bedevere-app Bot removed the needs backport to 3.15 pre-release feature fixes, bugs and security fixes label May 21, 2026
halstead pushed a commit to openembedded/openembedded-core that referenced this pull request May 26, 2026
ThreadingMock._increment_mock_call() was not thread-safe causing
intermittent ptest failures on qemuarm64:

  FAIL: test_call_count_thread_safe
  AssertionError: 983 != 1000

Each time a mock is called, Python reads the call_count, adds 1,
and writes it back. When multiple threads do this simultaneously,
some increments get lost because two threads can read the same
value before either writes back.

The fix adds a lock around this operation in ThreadingMock so
only one thread can update call_count at a time.

Reproduction and testing:
- x86 stress test (50 threads x 10000 calls x 30 runs):
    Before fix: 23/30 failures, missing up to 42095 calls
    After fix:  0/30 failures
- qemuarm64 (10 threads x 100 calls x 20 runs):
    Before fix: 3/20 failures, missing up to 49 calls
    After fix:  0/20 failures
- All 19 existing ThreadingMock tests pass

Upstream fix merged into CPython main:
python/cpython#150176

Fixes [YOCTO #16213]

Signed-off-by: Sai Sneha <saisneha196@gmail.com>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
gpshead pushed a commit that referenced this pull request May 26, 2026
) (#150182)

gh-150175: Fix ThreadingMock call_count race condition (GH-150176)

ThreadingMock._increment_mock_call() was not thread-safe.
Multiple threads calling the mock simultaneously could lose
increments due to race conditions on call_count and other
attributes.

Fix by overriding _increment_mock_call in ThreadingMixin
and wrapping it with the existing _mock_calls_events_lock.
(cherry picked from commit 388e023)

Co-authored-by: saisneha196 <156835592+saisneha196@users.noreply.github.com>
gpshead pushed a commit that referenced this pull request May 26, 2026
) (#150181)

gh-150175: Fix ThreadingMock call_count race condition (GH-150176)

ThreadingMock._increment_mock_call() was not thread-safe.
Multiple threads calling the mock simultaneously could lose
increments due to race conditions on call_count and other
attributes.

Fix by overriding _increment_mock_call in ThreadingMixin
and wrapping it with the existing _mock_calls_events_lock.
(cherry picked from commit 388e023)

Co-authored-by: saisneha196 <156835592+saisneha196@users.noreply.github.com>
gpshead pushed a commit that referenced this pull request May 26, 2026
) (#150180)

gh-150175: Fix ThreadingMock call_count race condition (GH-150176)

ThreadingMock._increment_mock_call() was not thread-safe.
Multiple threads calling the mock simultaneously could lose
increments due to race conditions on call_count and other
attributes.

Fix by overriding _increment_mock_call in ThreadingMixin
and wrapping it with the existing _mock_calls_events_lock.
(cherry picked from commit 388e023)

Co-authored-by: saisneha196 <156835592+saisneha196@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

3.13 bugs and security fixes 3.14 bugs and security fixes 3.15 pre-release feature fixes, bugs and security fixes 3.16 new features, bugs and security fixes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ThreadingMock.call_count is not thread-safe (race condition)

3 participants