llvm / llvm/llvm-project

BlockInCriticalSection does not honour non-blocking streams created by eventfd

Open
#175,309 6 comments 0 reactions 0 assignees View on GitHub
clang:static analyzer false-positive
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.