<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/58535>58535</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            False positive in -Wthread-safety-analysis when using mutexes in collections
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang:diagnostics,
            false-positive
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          rupprecht
      </td>
    </tr>
</table>

<pre>
    I found this while making fixes for [D129755](https://reviews.llvm.org/D129755), but it looks like this is an existing limitation of `-Wthread-safety-analysis`.

When using mutexes as part of a collection, thread safety analysis seems to get confused and think that all mutexes in the collection are the same.

```c++
void bad_loop() {
    std::vector<std::mutex *> mutexes{new std::mutex(), new std::mutex()};

    for (std::mutex *m : mutexes) { // error: expecting mutex 'm' to be held at start of each loop [-Werror,-Wthread-safety-analysis]
        m->lock(); // note: mutex acquired here
    }

    // This is where we do stuff that's only safe when _all_ locks are locked

    for (std::mutex *m : mutexes) {
        m->unlock(); // error: releasing mutex 'm' that was not held [-Werror,-Wthread-safety-analysis]
    }
}
```

The analysis _would_ make sense if we were locking the same mutex over and over again, but `m` is a different mutex on each loop iteration. Maybe the analysis is confused because, due to being in a loop, `m` has the same name on each iteration. But it also fails if we unroll:

```c++
void bad_unroll() {
    std::vector<std::mutex *> mutexes{new std::mutex(), new std::mutex()};

    mutexes[0]->lock(); // note: mutex acquired here
    mutexes[1]->lock(); // error: acquiring mutex 'operator[](mutexes, 1)' that is already held [-Werror,-Wthread-safety-analysis]

    // This is where we do stuff that's only safe when _all_ locks are locked

    mutexes[0]->unlock(); // note: mutex released here
    mutexes[1]->unlock(); // error: releasing mutex 'operator[](mutexes, 1)' that was not held [-Werror,-Wthread-safety-analysis]
}
```

This could be a valid warning if thread safety analysis is conservatively assuming that mutexes[0] and mutexes[1] might point to the same thing, but since [alias analysis is unsupported](https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#no-alias-analysis), I don't think that's it.

This might be something that's intentionally unsupported by thread safety analysis, but I didn't see any documentation for it being a known failure.

Live demo: https://godbolt.org/z/1sn5TMj3h
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzNVl1v4jgU_TXh5QoECSnwwENpt9JIO09baR4rJ74hHhybtR0Y9tfvtZ0EaMtsdyqtFoUQ4vh-HJ9z4kLz0_oLVLpVHFwtLBxrIREathNqC5X4gZZGDST55nGWrhZ5nuSPSbqsndvbJLtP0ic6DB4EHu1EykMz0WZLt_qn01WSPkDROhAOpNY7C1LsMCajgynAH8I6n06KRjjmhFagK0jupuNvrjbI-NiyCt1pzBSTJyssDU2S6WMyvY_nbzUqaK2P0bQOfdHMwp4Z5wMxKLWUWPrAvpgYE2JM6GOCRWwsOA1bdDRDVa1FTsMBGLWjM3PApBxSCEX38CI4MIPhlmUNXhVIBcejTNKNP8LdgxYcCsZfCJc9gUpgQbLoBoE-1nGPcXZ_oATaJNnDcCcUAUlK17_1FdFchUe4fibG9X3fHFs8JtnmslyfO6x6unybsAH6N6SMJUPkAaAxvsx7WtO9x6RfEBpfNPT18BYINUpC1lE13RIhK2vPjr0n2vhbDJM-3Fx_4uBQqP80Y4JB6nLXdZQNFSntcKgXWPlnKwwta40GzyE8Aq_a76Y_dzQ9-glwROCaqm6rKtCBOrKglTwFMvmHFLwQRV7A12IDH_wV8k-h-06vrXq32wF_gxKZfQd_T-IjiYNwicvw7wE_ozVc9PS-bPOZhDCI6-WoW8lfvLGQPFBZBFF5PI_YYeRr7bXTFa0PaIIA48WWCdWbCeVq6BscBLioKgqjXD9PXRBKODTBUybwlZ2KKNChLjoGqRdYMrrwKXiLkaq-KtI5gyjRhyFxTRgO5Sp_6rNeJNxE22PSaqiYkLZrulWGTMOv_Mc9opvzP3OJPma-mRJHPqfCc6zZz2INHI9hrjiu9x57Gs438T01COkBZqHBTgKeN9Iz_fQrKvjPbOItvDeEfw1wVP8HAP4FG_kwxJ9wmX8ylqBa8hP_LmFwYJI0cmRGBbVWt17wUesWzYHkeUBaDmZt20TjYe4V2MF4rhGDRmxrB3styGrIHgb9-w3CtrcmgqtE3zCVxexV-lbZdr_XxtFKv7ONKiVT28tNFNcl4fr0HPr5I7Rz34Wb1K4hN8iUHoc8ZxCjjL8QBcktF-5i9xJ4KNzkDZixLwLT6gZDMxfPK0fOSnZGhD1ddgDF6QbSPRJUg-CxCNpc0fCJiirbhuLFXZ5_CwrX2SyDndJHFYyyNdf7p99pvYBjoz0pr0Hbal5o6TrE_qLvzKr8-ev3rB7henZ3d5ctlrPVasTXGV9lKzZywklcP5ErI62lFZ4M3uRv0TIK9np7SY-f93121Bq5flWWcHVbTEpNr90nv6Tdz3hv9HeaRn8Fsc_r5ilf5lk-qteMz1M-z_kd_ZRlUfFltpjhcjpPi3kxZ9lIsgKlXXvppWlgC-Xjgm2Vph2050oa3lFpWvnuxn13_n7-OBLrdJqms2k6my3nq3w1mWbLCtMCi0XK-CpPk_kUG4J_4ODIrEPRRbu1NChpo37e5Y9IPmKrENfRC0asdbU2a0MMMVjWbhQ6XIf2_gYF6eyh">