BlockInCriticalSection does not honour non-blocking streams created by eventfd
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
False positive on `unix.BlockInCriticalSection`. It doesn't seem to track it through templates.
Version:
```
$HOME/opt/Qt/Tools/QtCreator/libexec/qtcreator/clang/bin/clang-tidy --version
LLVM (http://llvm.org/):
LLVM version 20.1.3
Optimized build.
```
Repro:
```cpp
#include
#include
#include
#include
#include
#include
template
class MutexLocked
{
std::unique_lock l;
T *d = nullptr;
public:
MutexLocked() = default;
MutexLocked(T &other, std::mutex &m) :
l(m),
d(&other)
{
}
MutexLocked(const MutexLocked &other) = delete;
MutexLocked &operator=(const MutexLocked &other) = delete;
MutexLocked(MutexLocked &&other) noexcept :
l(std::move(other.l)),
d(other.d)
{
other.d = nullptr;
}
~MutexLocked()
{
std::cout << "Destroying MutexLocked, which destroys the unique_lock" << std::endl;
d = nullptr;
}
};
template
class MutexOwned
{
std::mutex m;
T d;
public:
template
MutexOwned(Args... args) :
d(args...)
{
}
MutexLocked lock()
{
MutexLocked r(d, m);
return r;
}
};
int main()
{
int fd = eventfd(0, EFD_NONBLOCK);
MutexOwned> strings;
while (true)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
uint64_t eventfd_value = 0;
if (read(fd, &eventfd_value, sizeof(uint64_t)) < 0)
std::cout << "No event written to eventfd, but that's OK" << std::endl;
{
auto locked = strings.lock();
continue;
}
if (read(fd, &eventfd_value, sizeof(uint64_t)) < 0)
std::cout << "No event written to eventfd, but that's OK" << std::endl;
}
return 0;
}
```
Result:
```
$ /home/halfgaar/opt/Qt/Tools/QtCreator/libexec/qtcreator/clang/bin/clang-tidy -p /tmp/QtCreator-UcKgAx/Clang-TidylIJEDJ/compile_commands.json main.cpp
1 warning generated.
/home/halfgaar/tmp/clang_false_postive/main.cpp:75:13: warning: Call to blocking function 'read' inside of critical section [clang-analyzer-unix.BlockInCriticalSection]
75 | if (read(fd, &eventfd_value, sizeof(uint64_t)) < 0)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/halfgaar/tmp/clang_false_postive/main.cpp:70:5: note: Loop condition is true. Entering loop body
70 | while (true)
| ^
/home/halfgaar/tmp/clang_false_postive/main.cpp:75:13: note: Assuming the condition is false
75 | if (read(fd, &eventfd_value, sizeof(uint64_t)) < 0)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/halfgaar/tmp/clang_false_postive/main.cpp:75:9: note: Taking false branch
75 | if (read(fd, &eventfd_value, sizeof(uint64_t)) < 0)
| ^
/home/halfgaar/tmp/clang_false_postive/main.cpp:79:27: note: Calling 'MutexOwned::lock'
79 | auto locked = strings.lock();
| ^~~~~~~~~~~~~~
/home/halfgaar/tmp/clang_false_postive/main.cpp:59:24: note: Calling constructor for 'MutexLocked>>'
59 | MutexLocked r(d, m);
| ^~~~~~~
/home/halfgaar/tmp/clang_false_postive/main.cpp:19:9: note: Calling constructor for 'unique_lock'
19 | l(m),
| ^~~~
/usr/include/c++/11/bits/unique_lock.h:69:2: note: Entering critical section here
69 | lock();
| ^~~~~~
/home/halfgaar/tmp/clang_false_postive/main.cpp:19:9: note: Returning from constructor for 'unique_lock'
19 | l(m),
| ^~~~
/home/halfgaar/tmp/clang_false_postive/main.cpp:59:24: note: Returning from constructor for 'MutexLocked>>'
59 | MutexLocked r(d, m);
| ^~~~~~~
/home/halfgaar/tmp/clang_false_postive/main.cpp:79:27: note: Returning from 'MutexOwned::lock'
79 | auto locked = strings.lock();
| ^~~~~~~~~~~~~~
/home/halfgaar/tmp/clang_false_postive/main.cpp:80:13: note: Execution continues on line 70
80 | continue;
| ^
/home/halfgaar/tmp/clang_false_postive/main.cpp:70:5: note: Loop condition is true. Entering loop body
70 | while (true)
| ^
/home/halfgaar/tmp/clang_false_postive/main.cpp:75:13: note: Call to blocking function 'read' inside of critical section
75 | if (read(fd, &eventfd_value, sizeof(uint64_t)) < 0)
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
Contributor guide
Assessment
This issue has not been assessed yet.