Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 7, 2026

Description

ThreadSanitizer reported data races in the unit test framework on three shared fields accessed by multiple threads without synchronization: tc->runner, tc->result, and parallel_msg.

Changes:

  • unittest.c: Added optional pj_mutex_t *mutex parameter to run_test_case()

    • Protects tc->runner writes with mutex when running multi-threaded
    • Protects tc->result writes by storing result in local variable first, then writing inside mutex-protected critical section
    • Test functions are called outside mutex to avoid serializing test execution
    • Single-threaded basic runner passes NULL for zero overhead
    • Multi-threaded text runner passes its existing mutex
  • unittest_test.c: Added parallel_msg_mutex to serialize concurrent writes to shared buffer

    • Protects pj_ansi_strxcat() calls in parallel_func()
    • Initialized/destroyed in unittest_parallel_test()

Implementation:

static void run_test_case(pj_test_runner *runner, int tid, pj_test_case *tc,
                          pj_mutex_t *mutex)
{
    // ... test setup ...
    
    if (mutex)
        pj_mutex_lock(mutex);
    tc->runner = runner;
    if (mutex)
        pj_mutex_unlock(mutex);
    
    // Run test function (not serialized)
    int result = tc->test_func(tc->arg);
    if (result == PJ_EPENDING)
        result = -12345;
    
    // Write result inside mutex to prevent race
    if (mutex)
        pj_mutex_lock(mutex);
    tc->result = result;
    if (tc->result && runner->prm.stop_on_error)
        runner->stopping = PJ_TRUE;
    if (mutex)
        pj_mutex_unlock(mutex);
}

Motivation and Context

TSan warnings indicate undefined behavior from concurrent access to shared memory. These races could cause test framework instability or incorrect test results under high concurrency.

How Has This Been Tested?

  • Built with make -j3 - no compilation errors
  • Ran pjlib-test-x86_64-pc-linux-gnu - 20/21 tests pass (SSL timeout expected in sandbox)
  • Parallel test scheduling validates correct order enforcement ("abdecfghkji")
  • Quick PJSUA integration test confirms basic functionality
  • Addressed additional TSan warning reported during review by moving tc->result write inside mutex

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the CODING STYLE of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
Original prompt

This section details on the original issue you should resolve

<issue_title>Attempt to fix data race warnings reported by TSan</issue_title>
<issue_description>### Describe the bug

WARNING: ThreadSanitizer: data race (pid=55117)
  Read of size 8 at 0x00016dd4b7d0 by thread T15 (mutexes: write M0):
    pjsip/pjproject#0 get_first_running unittest.c:569 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000920e0)
    pjsip/pjproject#1 text_runner_get_next_test_case unittest.c:677 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100091ee4)
    pjsip/pjproject#2 text_runner_thread_proc unittest.c:739 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100091534)
    pjsip/pjproject#3 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004ea90)

  Previous write of size 8 at 0x00016dd4b7d0 by thread T7:
    pjsip/pjproject#0 run_test_case unittest.c:534 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000917f0)
    pjsip/pjproject#1 text_runner_thread_proc unittest.c:741 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10009156c)
    pjsip/pjproject#2 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004ea90)

  Location is stack of main thread.

  Mutex M0 (0x000108100108) created at:
    pjsip/pjproject#0 pthread_mutex_init <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x344f0)
    pjsip/pjproject#1 init_mutex os_core_unix.c:1519 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100049d9c)
    pjsip/pjproject#2 pj_mutex_create os_core_unix.c:1572 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004ca10)
    pjsip/pjproject#3 pj_test_create_text_runner unittest.c:823 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090e8c)
    pjsip/pjproject#4 unittest_parallel_test unittest_test.c:626 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100045078)
    pjsip/pjproject#5 unittest_parallel_test unittest_test.c:578 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100044e00)
    pjsip/pjproject#6 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b08c)
    pjsip/pjproject#7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c15c)
    pjsip/pjproject#8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Thread T15 (tid=123483221, running) created by main thread at:
    pjsip/pjproject#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
    pjsip/pjproject#1 create_thread os_core_unix.c:837 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004b87c)
    pjsip/pjproject#2 pj_thread_create os_core_unix.c:895 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004b37c)
    pjsip/pjproject#3 pj_test_create_text_runner unittest.c:841 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100091004)
    pjsip/pjproject#4 unittest_parallel_test unittest_test.c:626 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100045078)
    pjsip/pjproject#5 unittest_parallel_test unittest_test.c:578 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100044e00)
    pjsip/pjproject#6 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b08c)
    pjsip/pjproject#7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c15c)
    pjsip/pjproject#8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Thread T7 (tid=123483213, running) created by main thread at:
    pjsip/pjproject#0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
    pjsip/pjproject#1 create_thread os_core_unix.c:837 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004b87c)
    pjsip/pjproject#2 pj_thread_create os_core_unix.c:895 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004b37c)
    pjsip/pjproject#3 pj_test_create_text_runner unittest.c:841 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100091004)
    pjsip/pjproject#4 unittest_parallel_test unittest_test.c:626 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100045078)
    pjsip/pjproject#5 unittest_parallel_test unittest_test.c:578 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100044e00)
    pjsip/pjproject#6 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b08c)
    pjsip/pjproject#7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c15c)
    pjsip/pjproject#8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

SUMMARY: ThreadSanitizer: data race unittest.c:569 in get_first_running
==================
==================
WARNING: ThreadSanitizer: data race (pid=55117)
  Write of size 4 at 0x00016dd4b7ac by thread T7:
    pjsip/pjproject#0 run_test_case unittest.c:544 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000918c0)
    pjsip/pjproject#1 text_runner_thread_proc unittest.c:741 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10009156c)
    pjsip/pjproject#2 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004ea90)

  Previous read of size 4 at 0x00016dd4b7ac by thread T8 (mutexes: w...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes pjsip/pjproject#4726

<!-- START COPILOT CODING AGENT TIPS -->
---

✨ Let Copilot coding agent [set things up for you](https://github.com/pjsip/pjproject/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 3 commits January 7, 2026 08:55
- Add mutex parameter to run_test_case() to protect shared test case fields
- Protect tc->runner write with mutex in multi-threaded mode
- Protect tc->result read/write synchronization with mutex
- Add mutex protection for parallel_msg global variable in unittest_test
- Basic runner (single-threaded) passes NULL for mutex parameter
- Text runner (multi-threaded) passes its mutex to protect concurrent access

Co-authored-by: sauwming <[email protected]>
- Clarify memory barrier semantics in tc->result synchronization comment
- Make mutex initialization/cleanup more explicit in unittest_test.c
- Ensure parallel_msg_mutex is NULL before creation and on error path

Co-authored-by: sauwming <[email protected]>
- Remove redundant NULL assignment (static variables are auto-initialized)
- Eliminate code duplication by consolidating mutex lock/unlock logic
- Maintain same functionality with cleaner code structure

Co-authored-by: sauwming <[email protected]>
Copilot AI changed the title [WIP] Fix data race warnings reported by TSan Fix ThreadSanitizer data race warnings in unittest framework Jan 7, 2026
Copilot AI requested a review from sauwming January 7, 2026 09:14
@sauwming
Copy link
Member

sauwming commented Jan 7, 2026

@copilot:

WARNING: ThreadSanitizer: data race (pid=69410)
  Write of size 4 at 0x00016d1c433c by thread T7:
    #0 run_test_case unittest.c:557 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090a60)
    #1 text_runner_thread_proc unittest.c:768 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000906d0)
    #2 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004dbd8)

  Previous read of size 4 at 0x00016d1c433c by thread T17 (mutexes: write M0):
    #0 get_first_running unittest.c:596 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000912d0)
    #1 text_runner_get_next_test_case unittest.c:704 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000910b4)
    #2 text_runner_thread_proc unittest.c:766 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090678)
    #3 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004dbd8)

  As if synchronized via sleep:
    #0 usleep <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x30df0)
    #1 pj_thread_sleep os_core_unix.c:1100 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004b398)
    #2 parallel_func unittest_test.c:571 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004450c)
    #3 run_test_case unittest.c:557 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090a4c)
    #4 text_runner_thread_proc unittest.c:768 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000906d0)
    #5 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004dbd8)

  Location is stack of main thread.

  Mutex M0 (0x000109000198) created at:
    #0 pthread_mutex_init <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x344f0)
    #1 init_mutex os_core_unix.c:1519 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100048ee4)
    #2 pj_mutex_create os_core_unix.c:1572 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004bb58)
    #3 pj_test_create_text_runner unittest.c:850 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10008ffd0)
    #4 unittest_parallel_test unittest_test.c:645 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000440d4)
    #5 unittest_parallel_test unittest_test.c:587 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100043cf4)
    #6 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Thread T7 (tid=123533602, running) created by main thread at:
    #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
    #1 create_thread os_core_unix.c:837 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004a9c4)
    #2 pj_thread_create os_core_unix.c:895 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004a4c4)
    #3 pj_test_create_text_runner unittest.c:868 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090148)
    #4 unittest_parallel_test unittest_test.c:645 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000440d4)
    #5 unittest_parallel_test unittest_test.c:587 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100043cf4)
    #6 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Thread T17 (tid=123533612, running) created by main thread at:
    #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
    #1 create_thread os_core_unix.c:837 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004a9c4)
    #2 pj_thread_create os_core_unix.c:895 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004a4c4)
    #3 pj_test_create_text_runner unittest.c:868 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090148)
    #4 unittest_parallel_test unittest_test.c:645 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000440d4)
    #5 unittest_parallel_test unittest_test.c:587 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100043cf4)
    #6 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

SUMMARY: ThreadSanitizer: data race unittest.c:557 in run_test_case
==================
WARNING: ThreadSanitizer: data race (pid=69410)
  Write of size 4 at 0x00016d1c43ec by thread T7:
    #0 run_test_case unittest.c:557 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090a60)
    #1 text_runner_thread_proc unittest.c:768 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000906d0)
    #2 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004dbd8)

  Previous read of size 4 at 0x00016d1c43ec by main thread (mutexes: write M0):
    #0 get_first_running unittest.c:596 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000912d0)
    #1 text_runner_get_next_test_case unittest.c:704 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000910b4)
    #2 text_runner_thread_proc unittest.c:766 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090678)
    #3 text_runner_main unittest.c:797 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000903d4)
    #4 pj_test_run unittest.c:235 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10008ed10)
    #5 unittest_parallel_test unittest_test.c:648 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100044204)
    #6 unittest_parallel_test unittest_test.c:587 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100043cf4)
    #7 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #8 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #9 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  As if synchronized via sleep:
    #0 usleep <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x30df0)
    #1 pj_thread_sleep os_core_unix.c:1100 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004b398)
    #2 parallel_func unittest_test.c:571 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004450c)
    #3 run_test_case unittest.c:557 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090a4c)
    #4 text_runner_thread_proc unittest.c:768 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000906d0)
    #5 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004dbd8)

  Location is stack of main thread.

  Mutex M0 (0x000109000198) created at:
    #0 pthread_mutex_init <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x344f0)
    #1 init_mutex os_core_unix.c:1519 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100048ee4)
    #2 pj_mutex_create os_core_unix.c:1572 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004bb58)
    #3 pj_test_create_text_runner unittest.c:850 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10008ffd0)
    #4 unittest_parallel_test unittest_test.c:645 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000440d4)
    #5 unittest_parallel_test unittest_test.c:587 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100043cf4)
    #6 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Thread T7 (tid=123533602, running) created by main thread at:
    #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
    #1 create_thread os_core_unix.c:837 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004a9c4)
    #2 pj_thread_create os_core_unix.c:895 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004a4c4)
    #3 pj_test_create_text_runner unittest.c:868 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090148)
    #4 unittest_parallel_test unittest_test.c:645 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000440d4)
    #5 unittest_parallel_test unittest_test.c:587 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100043cf4)
    #6 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

SUMMARY: ThreadSanitizer: data race unittest.c:557 in run_test_case

==================
WARNING: ThreadSanitizer: data race (pid=69410)
  Write of size 4 at 0x00016d1c4cec by main thread:
    #0 run_test_case unittest.c:557 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090a60)
    #1 text_runner_thread_proc unittest.c:768 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000906d0)
    #2 text_runner_main unittest.c:797 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000903d4)
    #3 pj_test_run unittest.c:235 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10008ed10)
    #4 usage_test unittest_test.c:340 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000424cc)
    #5 unittest_test unittest_test.c:683 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000447b4)
    #6 essential_tests test.c:225 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bc50)
    #7 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #8 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #9 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Previous read of size 4 at 0x00016d1c4cec by thread T19 (mutexes: write M0):
    #0 get_first_running unittest.c:596 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000912d0)
    #1 text_runner_get_next_test_case unittest.c:704 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000910b4)
    #2 text_runner_thread_proc unittest.c:766 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090678)
    #3 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004dbd8)

  As if synchronized via sleep:
    #0 usleep <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x30df0)
    #1 pj_thread_sleep os_core_unix.c:1100 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004b398)
    #2 func_to_test unittest_test.c:262 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000462c4)
    #3 run_test_case unittest.c:557 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090a4c)
    #4 text_runner_thread_proc unittest.c:768 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000906d0)
    #5 text_runner_main unittest.c:797 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000903d4)
    #6 pj_test_run unittest.c:235 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10008ed10)
    #7 usage_test unittest_test.c:340 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000424cc)
    #8 unittest_test unittest_test.c:683 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000447b4)
    #9 essential_tests test.c:225 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bc50)
    #10 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #11 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #12 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Location is stack of main thread.

  Mutex M0 (0x000109000108) created at:
    #0 pthread_mutex_init <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x344f0)
    #1 init_mutex os_core_unix.c:1519 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100048ee4)
    #2 pj_mutex_create os_core_unix.c:1572 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004bb58)
    #3 pj_test_create_text_runner unittest.c:850 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10008ffd0)
    #4 usage_test unittest_test.c:335 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100042398)
    #5 unittest_test unittest_test.c:683 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000447b4)
    #6 essential_tests test.c:225 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bc50)
    #7 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #8 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #9 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Thread T19 (tid=123533661, running) created by main thread at:
    #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
    #1 create_thread os_core_unix.c:837 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004a9c4)
    #2 pj_thread_create os_core_unix.c:895 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004a4c4)
    #3 pj_test_create_text_runner unittest.c:868 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100090148)
    #4 usage_test unittest_test.c:335 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100042398)
    #5 unittest_test unittest_test.c:683 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000447b4)
    #6 essential_tests test.c:225 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bc50)
    #7 essential_tests test.c:95 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003b07c)
    #8 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003bd1c)
    #9 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

SUMMARY: ThreadSanitizer: data race unittest.c:557 in run_test_case

==================
WARNING: ThreadSanitizer: data race (pid=69560)
  Write of size 4 at 0x00010287a6a4 by main thread:
    #0 run_test_case unittest.c:555 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100091b0c)
    #1 text_runner_thread_proc unittest.c:768 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000917dc)
    #2 text_runner_main unittest.c:797 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000914e0)
    #3 pj_test_run unittest.c:235 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10008fe1c)
    #4 ut_run_tests test_util.h:210 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003ce04)
    #5 features_tests test.c:362 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c0a4)
    #6 test_inner test.c:421 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003ae98)
    #7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c15c)
    #8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Previous read of size 4 at 0x00010287a6a4 by thread T1 (mutexes: write M0):
    #0 get_first_running unittest.c:596 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000923dc)
    #1 text_runner_get_next_test_case unittest.c:704 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000921c0)
    #2 text_runner_thread_proc unittest.c:766 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100091784)
    #3 thread_main os_core_unix.c:765 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004ece4)

  Location is global 'test_app' at 0x00010287a530 (pjlib-test-aarch64-apple-darwin24.5.0+0x1002f26a4)

  Mutex M0 (0x000108a004f0) created at:
    #0 pthread_mutex_init <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x344f0)
    #1 init_mutex os_core_unix.c:1519 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100049ff0)
    #2 pj_mutex_create os_core_unix.c:1572 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004cc64)
    #3 pj_test_create_text_runner unittest.c:850 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000910dc)
    #4 ut_run_tests test_util.h:202 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003cc3c)
    #5 features_tests test.c:362 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c0a4)
    #6 test_inner test.c:421 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003ae98)
    #7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c15c)
    #8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

  Thread T1 (tid=123535067, finished) created by main thread at:
    #0 pthread_create <null> (libclang_rt.tsan_osx_dynamic.dylib:arm64e+0x32b00)
    #1 create_thread os_core_unix.c:837 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004bad0)
    #2 pj_thread_create os_core_unix.c:895 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10004b5d0)
    #3 pj_test_create_text_runner unittest.c:868 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x100091254)
    #4 ut_run_tests test_util.h:202 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003cc3c)
    #5 features_tests test.c:362 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c0a4)
    #6 test_inner test.c:421 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003ae98)
    #7 test_main test.c:469 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x10003c15c)
    #8 main main.c:124 (pjlib-test-aarch64-apple-darwin24.5.0:arm64+0x1000013f8)

SUMMARY: ThreadSanitizer: data race unittest.c:555 in run_test_case

Move tc->result assignment inside mutex-protected critical section.
The test function is still called outside the mutex to avoid serialization,
but the result is stored in a local variable first, then written to
tc->result inside the mutex to prevent race with concurrent reads in
get_first_running().

Co-authored-by: sauwming <[email protected]>
Copy link
Contributor Author

Copilot AI commented Jan 7, 2026

@copilot:

WARNING: ThreadSanitizer: data race (pid=69410)

...

Fixed in commit bf6d1d8. The issue was that tc->result was being written outside the mutex while other threads read it inside the mutex. Now the test function is called outside the mutex (to avoid serialization), but the result is stored in a local variable first, then written to tc->result inside the mutex-protected critical section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants