boostorg / boostorg/lockfree

[ Thread Safety ] boost::lockfree::queue<T> data race when T is a pointer type

Open
#120 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
160
Forks
99
PR merge metrics
No merged PRs in 30d

Description

**Issue Summary**

When using `boost::lockfree::queue` with `T` as a pointer type (e.g., `PGconn*`), concurrent `pop()` operations may return the same front node to multiple threads, even if the return value is checked. This violates the queue's thread-safety guarantee.

**Reproduction Steps**
1. Define a queue with pointer type (e.g., `PGconn*` pointers): `boost::lockfree::queue unsafe_queue(1024);`
2. Concurrently call `push()` and `pop()` from multiple threads and track the number of times each `PGconn*` is popped and pushed.

**Expected Behavior**

Each enqueued `PGconn*` should be pushed and popped equal times.

**Actual Behavior**

For `boost::lockfree::queue`, some `PGconn*` pointers are popped much more times than they are pushed.
For `boost::lockfree::queue` (where `Conn` wraps `PGconn*`), the behavior is correct (`pop count == push count`).

**Example Code**
```cpp
// Thread-unsafe case
boost::lockfree::queue unsafe_queue(1024);
// Concurrent pushes and pops will yield duplicate PGconn* pointers.

// Thread-safe case
struct Conn { PGconn* pgconn; };
boost::lockfree::queue safe_queue(1024);
// Concurrent pushes and pops behave correctly.
```
**Root Cause Analysis**

The issue likely stems from how pointer types are handled internally in `boost::lockfree::queue`. The queue may fail to atomically update the head node when `T` is a pointer, leading to race conditions. This does not occur when `T` is a user-defined type (e.g., `Conn`), possibly due to stricter memory ordering or type-specific handling.

Every time an element is dequeued, its number of entries and exits is counted once. The number of pops is **always greater than or equal to** pushes. There has **never** been a situation where the number of pops is less than pushes. **Therefore, the problem is likely to lie in the** `pop()`.

**Environment**

`Boost version: 1.83.0`
`Compiler: gcc/g++ 13.3`
`OS: Linux x86_64`

**Additional Notes**

The bug may also affect other pointer types (`int*`, custom class pointers, etc.), but only `PGconn*` is explicitly tested.
The lock-free context used for `push()` and `pop()` operations is confirmed to be correct (no external races).

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.